From 21c84bcd96a2e457b446e53d3287878e32fc77e0 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 13 Nov 2015 20:11:12 -0400 Subject: Replace deprecated Carbon API calls with modern AudioComponent APIs in the CoreAudio backend. This prevents a deprecation notice from being output to stdout when alcOpenDevice is called in Mac OS X 10.11. The new API calls require Mac OS X 10.6 or newer. --- Alc/backends/coreaudio.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 43e881da..d9264217 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -137,8 +137,8 @@ static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags * static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) { - ComponentDescription desc; - Component comp; + AudioComponentDescription desc; + AudioComponent comp; ca_data *data; OSStatus err; @@ -154,19 +154,19 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) desc.componentFlags = 0; desc.componentFlagsMask = 0; - comp = FindNextComponent(NULL, &desc); + comp = AudioComponentFindNext(NULL, &desc); if(comp == NULL) { - ERR("FindNextComponent failed\n"); + ERR("AudioComponentFindNext failed\n"); return ALC_INVALID_VALUE; } data = calloc(1, sizeof(*data)); - err = OpenAComponent(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &data->audioUnit); if(err != noErr) { - ERR("OpenAComponent failed\n"); + ERR("AudioComponentInstanceNew failed\n"); free(data); return ALC_INVALID_VALUE; } @@ -176,7 +176,7 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - CloseComponent(data->audioUnit); + AudioComponentInstanceDispose(data->audioUnit); free(data); return ALC_INVALID_VALUE; } @@ -191,7 +191,7 @@ static void ca_close_playback(ALCdevice *device) ca_data *data = (ca_data*)device->ExtraData; AudioUnitUninitialize(data->audioUnit); - CloseComponent(data->audioUnit); + AudioComponentInstanceDispose(data->audioUnit); free(data); device->ExtraData = NULL; @@ -374,12 +374,13 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format AURenderCallbackStruct input; - ComponentDescription desc; + AudioComponentDescription desc; AudioDeviceID inputDevice; UInt32 outputFrameCount; UInt32 propertySize; + AudioObjectPropertyAddress propertyAddress; UInt32 enableIO; - Component comp; + AudioComponent comp; ca_data *data; OSStatus err; @@ -395,10 +396,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) desc.componentFlagsMask = 0; // Search for component with given description - comp = FindNextComponent(NULL, &desc); + comp = AudioComponentFindNext(NULL, &desc); if(comp == NULL) { - ERR("FindNextComponent failed\n"); + ERR("AudioComponentFindNext failed\n"); return ALC_INVALID_VALUE; } @@ -406,10 +407,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) device->ExtraData = data; // Open the component - err = OpenAComponent(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &data->audioUnit); if(err != noErr) { - ERR("OpenAComponent failed\n"); + ERR("AudioComponentInstanceNew failed\n"); goto error; } @@ -432,11 +433,16 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Get the default input device + propertySize = sizeof(AudioDeviceID); - err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice); + propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; + propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; + propertyAddress.mElement = kAudioObjectPropertyElementMaster; + + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &inputDevice); if(err != noErr) { - ERR("AudioHardwareGetProperty failed\n"); + ERR("AudioObjectGetPropertyData failed\n"); goto error; } @@ -596,7 +602,7 @@ error: if(data->audioConverter) AudioConverterDispose(data->audioConverter); if(data->audioUnit) - CloseComponent(data->audioUnit); + AudioComponentInstanceDispose(data->audioUnit); free(data); device->ExtraData = NULL; @@ -613,7 +619,7 @@ static void ca_close_capture(ALCdevice *device) destroy_buffer_list(data->bufferList); AudioConverterDispose(data->audioConverter); - CloseComponent(data->audioUnit); + AudioComponentInstanceDispose(data->audioUnit); free(data); device->ExtraData = NULL; -- cgit v1.2.3 From 8ac88304788026370d42449d9cbbd4bb396c01f6 Mon Sep 17 00:00:00 2001 From: v4hn Date: Fri, 20 Nov 2015 14:33:44 +0100 Subject: include correct libraries in case jack support is requested and found It just doesn't make sense to add pulseaudio libraries here... Also it breaks in case jack is requested, but pulseaudio is disabled :) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fe3e98c..c6442e67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -924,7 +924,7 @@ IF(JACK_FOUND) SET(HAVE_JACK 1) SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c) - ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) + ADD_BACKEND_LIBS(${JACK_LIBRARIES}) IF(CMAKE_VERSION VERSION_LESS "2.8.8") INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS}) ENDIF() -- cgit v1.2.3 From c8a3e51296d367990b9603a8e53f24dd1068b23d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 16:29:32 -0800 Subject: Fix the allow-resampler check for ALSA --- Alc/backends/alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 9a443c09..955fd8c0 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -770,7 +770,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ - if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0)) + if(!GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0)) { if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); -- cgit v1.2.3 From 63567526b0a17449baf57053d11688aa277a7e40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 Nov 2015 16:50:31 -0800 Subject: Better handle inexact ALSA period counts --- Alc/backends/alsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 955fd8c0..43c46484 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -677,6 +677,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) unsigned int rate; const char *funcerr; int allowmmap; + int dir; int err; switch(device->FmtType) @@ -787,7 +788,9 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); - CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL)); + CHECK(snd_pcm_hw_params_get_periods(hp, &periods, &dir)); + if(dir != 0) + WARN("Inexact period count: %u (%d)\n", periods, dir); snd_pcm_hw_params_free(hp); hp = NULL; -- cgit v1.2.3 From e45ff473618f3400def59fc3a06cec9fdc62452b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 15:52:43 -0800 Subject: Reformat Windows device name dressing --- Alc/backends/dsound.c | 11 +++++------ Alc/backends/mmdevapi.c | 25 +++++++++++++------------ Alc/backends/winmm.c | 20 +++++++++----------- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 4db4b557..f27ab37b 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -60,7 +60,7 @@ 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); -#define DEVNAME_TAIL " on OpenAL Soft" +#define DEVNAME_HEAD "OpenAL Soft on " #ifdef HAVE_DYNLOAD @@ -145,13 +145,12 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA { const DevMap *iter; - al_string_copy_wcstr(&entry.name, desc); - if(count == 0) - al_string_append_cstr(&entry.name, DEVNAME_TAIL); - else + al_string_copy_cstr(&entry.name, DEVNAME_HEAD); + al_string_append_wcstr(&entry.name, desc); + if(count != 0) { char str[64]; - snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); + snprintf(str, sizeof(str), " #%d", count+1); al_string_append_cstr(&entry.name, str); } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index e8563d33..0134a46c 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -62,7 +62,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) #define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) -#define DEVNAME_TAIL " on OpenAL Soft" +#define DEVNAME_HEAD "OpenAL Soft on " typedef struct { @@ -125,10 +125,13 @@ static void get_device_name(IMMDevice *device, al_string *name) PROPVARIANT pvname; HRESULT hr; + al_string_copy_cstr(name, DEVNAME_HEAD); + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + al_string_append_cstr(name, "Unknown Device Name"); return; } @@ -136,11 +139,17 @@ static void get_device_name(IMMDevice *device, al_string *name) hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); if(FAILED(hr)) + { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + al_string_append_cstr(name, "Unknown Device Name"); + } else if(pvname.vt == VT_LPWSTR) - al_string_copy_wcstr(name, pvname.pwszVal); + al_string_append_wcstr(name, pvname.pwszVal); else + { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); + al_string_append_cstr(name, "Unknown Device Name"); + } PropVariantClear(&pvname); IPropertyStore_Release(ps); @@ -193,12 +202,10 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) const DevMap *iter; al_string_copy(&entry.name, tmpname); - if(count == 0) - al_string_append_cstr(&entry.name, DEVNAME_TAIL); - else + if(count != 0) { char str[64]; - snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); + snprintf(str, sizeof(str), " #%d", count+1); al_string_append_cstr(&entry.name, str); } @@ -755,10 +762,7 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) { self->client = ptr; if(al_string_empty(device->DeviceName)) - { get_device_name(self->mmdev, &device->DeviceName); - al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL); - } } if(FAILED(hr)) @@ -1412,10 +1416,7 @@ static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) { self->client = ptr; if(al_string_empty(device->DeviceName)) - { get_device_name(self->mmdev, &device->DeviceName); - al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL); - } } if(FAILED(hr)) diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index bf97ef2e..3508ec49 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -37,7 +37,7 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -#define DEVNAME_TAIL " on OpenAL Soft" +#define DEVNAME_HEAD "OpenAL Soft on " static vector_al_string PlaybackDevices; @@ -71,13 +71,12 @@ static void ProbePlaybackDevices(void) ALuint count = 0; while(1) { - al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count == 0) - al_string_append_cstr(&dname, DEVNAME_TAIL); - else + al_string_copy_cstr(&dname, DEVNAME_HEAD); + al_string_append_wcstr(&dname, WaveCaps.szPname); + if(count != 0) { char str[64]; - snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); + snprintf(str, sizeof(str), " #%d", count+1); al_string_append_cstr(&dname, str); } count++; @@ -115,13 +114,12 @@ static void ProbeCaptureDevices(void) ALuint count = 0; while(1) { - al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count == 0) - al_string_append_cstr(&dname, DEVNAME_TAIL); - else + al_string_copy_cstr(&dname, DEVNAME_HEAD); + al_string_append_wcstr(&dname, WaveCaps.szPname); + if(count != 0) { char str[64]; - snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); + snprintf(str, sizeof(str), " #%d", count+1); al_string_append_cstr(&dname, str); } count++; -- cgit v1.2.3 From 675ec99d339bbc0a3bc91d3fa132ed28a2ed626e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 16:00:53 -0800 Subject: Update changelog --- ChangeLog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2f037254..e9fb4500 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +openal-soft-1.17.1: + + Fixed building with JACK and without PulseAudio. + + Fixed the ALSA backend's allow-resampler option. + + Improved handling of inexact ALSA period counts. + + Altered device naming scheme on Windows backends to better match other + drivers. + + Updated the CoreAudio backend to use the AudioComponent API. This fixes + deprecation warnings for OSX 10.11, although requires OSX 10.6 or newer. + openal-soft-1.17.0: Implemented a JACK playback backend. -- cgit v1.2.3 From 4e6acfa0d549281efcbe8293d95b76a37deb370d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 18:52:46 -0800 Subject: Only set _POSIX_C_SOURCE if needed --- CMakeLists.txt | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6442e67..f3651dcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,9 @@ OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON) OPTION(ALSOFT_INSTALL "Install headers and libraries" ON) -IF(WIN32) +IF(NOT WIN32) + SET(LIBNAME openal) +ELSE() SET(LIBNAME OpenAL32) ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0502") @@ -60,22 +62,7 @@ IF(WIN32) ENDIF() ENDIF() ENDIF() -ELSE() - SET(LIBNAME openal) - - # These are needed on non-Windows 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") -ENDIF() - -# Set defines for large file support -CHECK_FILE_OFFSET_BITS() -IF(_FILE_OFFSET_BITS) - ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") ENDIF() -ADD_DEFINITIONS(-D_LARGEFILE_SOURCE -D_LARGE_FILES) -SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") # QNX's gcc do not uses /usr/include and /usr/lib pathes by default @@ -111,6 +98,29 @@ ELSE() ENDIF() ENDIF() +# Check if _POSIX_C_SOURCE needs to be set for POSIX functions +CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) +IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) + SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L") + CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) + IF(NOT HAVE_POSIX_MEMALIGN_POSIX) + SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) + ELSE() + ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L) + ENDIF() + UNSET(OLD_REQUIRED_FLAGS) +ENDIF() + +# Set defines for large file support +CHECK_FILE_OFFSET_BITS() +IF(_FILE_OFFSET_BITS) + ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}) + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}") +ENDIF() +ADD_DEFINITIONS(-D_LARGEFILE_SOURCE -D_LARGE_FILES) +SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") + # MSVC may need workarounds for C99 restrict and inline IF(MSVC) # TODO: Once we truly require C99, these restrict and inline checks should go @@ -476,12 +486,12 @@ ENDIF() # Check if we have Windows headers CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0502) IF(NOT HAVE_WINDOWS_H) - CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY) + CHECK_SYMBOL_EXISTS(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) IF(NOT HAVE_GETTIMEOFDAY) MESSAGE(FATAL_ERROR "No timing function found!") ENDIF() - CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP) + CHECK_SYMBOL_EXISTS(nanosleep time.h HAVE_NANOSLEEP) IF(NOT HAVE_NANOSLEEP) MESSAGE(FATAL_ERROR "No sleep function found!") ENDIF() -- cgit v1.2.3 From 482372577e6eaa9f4b857dc3a335e67efd1ee367 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 19:09:48 -0800 Subject: Avoid using usleep in the examples We already have an al_nssleep wrapper in the common lib we can use. --- CMakeLists.txt | 15 ++++++++++----- examples/alhrtf.c | 2 +- examples/allatency.c | 2 +- examples/alloopback.c | 2 +- examples/alreverb.c | 2 +- examples/alstream.c | 2 +- examples/altonegen.c | 2 +- examples/common/alhelpers.h | 10 ++-------- 8 files changed, 18 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3651dcc..126364d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1230,27 +1230,32 @@ IF(ALSOFT_EXAMPLES) ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alstream examples/alstream.c) - TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alreverb examples/alreverb.c) - TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(allatency examples/allatency.c) - TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alloopback examples/alloopback.c) - TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alhrtf examples/alhrtf.c) - TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 6dac5308..b18a5115 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -227,7 +227,7 @@ int main(int argc, char **argv) angle = 0.0; alSourcePlay(source); do { - Sleep(10); + al_nssleep(10000000); /* Rotate the source around the listener by about 1/4 cycle per second. * Only affects mono sounds. diff --git a/examples/allatency.c b/examples/allatency.c index deb13d3b..afef43ca 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -182,7 +182,7 @@ int main(int argc, char **argv) /* Play the sound until it finishes. */ alSourcePlay(source); do { - Sleep(10); + al_nssleep(10000000); alGetSourcei(source, AL_SOURCE_STATE, &state); /* Get the source offset and latency. AL_SEC_OFFSET_LATENCY_SOFT will diff --git a/examples/alloopback.c b/examples/alloopback.c index 04c92818..c5dee36d 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -216,7 +216,7 @@ int main(int argc, char *argv[]) /* Play the sound until it finishes. */ alSourcePlay(source); do { - Sleep(10); + al_nssleep(10000000); alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); diff --git a/examples/alreverb.c b/examples/alreverb.c index 420b1c55..7d2bb343 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -311,7 +311,7 @@ int main(int argc, char **argv) /* Play the sound until it finishes. */ alSourcePlay(source); do { - Sleep(10); + al_nssleep(10000000); alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); diff --git a/examples/alstream.c b/examples/alstream.c index 2972d375..63478d6a 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -318,7 +318,7 @@ int main(int argc, char **argv) } while(UpdatePlayer(player)) - Sleep(10); + al_nssleep(10000000); /* All done with this file. Close it and go to the next */ ClosePlayerFile(player); diff --git a/examples/altonegen.c b/examples/altonegen.c index 65980529..74a04ee2 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -246,7 +246,7 @@ int main(int argc, char *argv[]) alSourcePlay(source); do { ALint pos; - Sleep(10); + al_nssleep(10000000); alGetSourcei(source, AL_SAMPLE_OFFSET, &pos); alGetSourcei(source, AL_SOURCE_STATE, &state); if(pos < last_pos && state == AL_PLAYING) diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 62ed5be2..1b4d2fbf 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -1,18 +1,12 @@ #ifndef ALHELPERS_H #define ALHELPERS_H -#ifndef _WIN32 -#include -#define Sleep(x) usleep((x)*1000) -#else -#define WIN32_LEAN_AND_MEAN -#include -#endif - #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" +#include "threads.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -- cgit v1.2.3 From 48447e2864a5811635be6cd42f56bd8992e477d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Dec 2015 19:51:48 -0800 Subject: Also install the HRTF example --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 126364d4..0d1273d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1260,7 +1260,7 @@ IF(ALSOFT_EXAMPLES) ${SDL_SOUND_INCLUDE_DIR}) IF(ALSOFT_INSTALL) - INSTALL(TARGETS alstream alreverb allatency alloopback + INSTALL(TARGETS alstream alreverb allatency alloopback alhrtf RUNTIME DESTINATION bin LIBRARY DESTINATION "lib${LIB_SUFFIX}" ARCHIVE DESTINATION "lib${LIB_SUFFIX}" -- cgit v1.2.3 From 21998924d81e382bfb4d63b036ac21eae8dcc04f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Dec 2015 17:45:56 -0800 Subject: Support %s as a string matching marker --- Alc/helpers.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- alsoftrc.sample | 1 + 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 7b9e58e0..25a47d88 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -549,6 +549,13 @@ FILE *OpenDataFile(const char *fname, const char *subdir) } +static size_t strlenW(const WCHAR *str) +{ + const WCHAR *end = str; + while(*end) ++end; + return end-str; +} + static const WCHAR *strchrW(const WCHAR *str, WCHAR ch) { for(;*str != 0;++str) @@ -570,9 +577,27 @@ static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch) return ret; } +static const WCHAR *strstrW(const WCHAR *haystack, const WCHAR *needle) +{ + size_t len = strlenW(needle); + while(*haystack != 0) + { + if(CompareStringW(GetThreadLocale(), NORM_IGNORECASE, + haystack, len, needle, len) == CSTR_EQUAL) + return haystack; + + do { + ++haystack; + } while(((*haystack)&0xC000) == 0x8000); + } + return NULL; +} + + /* Compares the filename in the find data with the match string. The match * string may contain the "%r" marker to signifiy a sample rate (really any - * positive integer), or "%%" to signify a single '%'. + * positive integer), "%%" to signify a single '%', or "%s" for a (non-greedy) + * string. */ static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) { @@ -608,6 +633,40 @@ static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) ret = l > 0; ++p; } + else if(*p == 's') + { + const WCHAR *next = p+1; + if(*next != '\0' && *next != '%') + { + const WCHAR *next_p = strchrW(next, '%'); + const WCHAR *m; + + if(!next_p) + m = strstrW(name, next); + else + { + WCHAR *tmp = malloc((next_p - next + 1) * 2); + memcpy(tmp, next, (next_p - next) * 2); + tmp[next_p - next] = 0; + + m = strstrW(name, tmp); + + free(tmp); + } + + ret = !!m; + if(ret) + { + size_t l; + if(next_p) l = next_p - next; + else l = strlenW(next); + + name = m + l; + next += l; + } + } + p = next; + } } } @@ -973,6 +1032,40 @@ static int MatchFilter(const struct dirent *dir) if(ret) name = end; ++p; } + else if(*p == 's') + { + const char *next = p+1; + if(*next != '\0' && *next != '%') + { + const char *next_p = strchr(next, '%'); + const char *m; + + if(!next_p) + m = strstr(name, next); + else + { + char *tmp = malloc(next_p - next + 1); + memcpy(tmp, next, next_p - next); + tmp[next_p - next] = 0; + + m = strstr(name, tmp); + + free(tmp); + } + + ret = !!m; + if(ret) + { + size_t l; + if(next_p) l = next_p - next; + else l = strlen(next); + + name = m + l; + next += l; + } + } + p = next; + } } } diff --git a/alsoftrc.sample b/alsoftrc.sample index eccc88b5..20c6c0ff 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -101,6 +101,7 @@ # format of the files are described in hrtf.txt. The filenames may contain # these markers, which will be replaced as needed: # %r - Device sampling rate +# %s - Non-greedy string (up to the following matching characters) # %% - Percent sign (%) # The listed files are relative to system-dependant data directories. On # Windows this is: -- cgit v1.2.3 From 455d5f48c0e99f6e3d7c237ee5f1570c37ec49be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Dec 2015 17:49:05 -0800 Subject: Use %s.mhr for the default hrtf table list --- Alc/hrtf.c | 2 +- alsoftrc.sample | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 71dd9d79..467232d7 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -820,7 +820,7 @@ error: vector_HrtfEntry EnumerateHrtf(const_al_string devname) { vector_HrtfEntry list = VECTOR_INIT_STATIC(); - const char *fnamelist = "default-%r.mhr"; + const char *fnamelist = "%s.mhr"; ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist); while(fnamelist && *fnamelist) diff --git a/alsoftrc.sample b/alsoftrc.sample index 20c6c0ff..039dba6a 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -111,7 +111,7 @@ # $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and # /usr/share/openal/hrtf) # An absolute path may also be specified, if the given file is elsewhere. -#hrtf_tables = default-%r.mhr +#hrtf_tables = %s.mhr ## cf_level: # Sets the crossfeed level for stereo output. Valid values are: -- cgit v1.2.3 From c08e975aa5760ce8b44c11a8a17d9e8214524570 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Dec 2015 06:36:00 -0800 Subject: Update changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index e9fb4500..de99cc98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ openal-soft-1.17.1: Fixed building with JACK and without PulseAudio. + Fixed building on FreeBSD. + Fixed the ALSA backend's allow-resampler option. Improved handling of inexact ALSA period counts. -- cgit v1.2.3 From f8a4ef6f514ad0accfc4fb7a05506f1879798b81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Dec 2015 19:17:59 -0800 Subject: Use the ALSOFT_LOCAL_PATH env var instead of the CWD --- Alc/helpers.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 25a47d88..3e8d9972 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -844,8 +844,17 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) al_string path = AL_STRING_INIT_STATIC(); WCHAR *cwdbuf; - /* Search the CWD. */ - if(!(cwdbuf=_wgetcwd(NULL, 0))) + /* Search the app-local directory. */ + if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') + { + al_string_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) + { + VECTOR_POP_BACK(path); + *VECTOR_ITER_END(path) = 0; + } + } + else if(!(cwdbuf=_wgetcwd(NULL, 0))) al_string_copy_cstr(&path, "."); else { @@ -1192,8 +1201,13 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) const char *str, *next; char cwdbuf[PATH_MAX]; - // Search CWD - if(!getcwd(cwdbuf, sizeof(cwdbuf))) + /* Search the app-local directory. */ + if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') + { + strncpy(cwdbuf, str, sizeof(cwdbuf)-1); + cwdbuf[sizeof(cwdbuf)-1] = '\0'; + } + else if(!getcwd(cwdbuf, sizeof(cwdbuf))) strcpy(cwdbuf, "."); RecurseDirectorySearch(cwdbuf, match, &results); -- cgit v1.2.3 From 26f8676b9b420390f4cd2cb9121dffbaeeabb918 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Dec 2015 19:39:50 -0800 Subject: Fix slashes on the local path on Windows --- Alc/helpers.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Alc/helpers.c b/Alc/helpers.c index 3e8d9972..e9efddf3 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -866,6 +866,9 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) } free(cwdbuf); } +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); /* Search the local and global data dirs. */ -- cgit v1.2.3 From 4612378593534922688fdad57c08fa4bb69f10f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 01:58:08 -0800 Subject: Update alsoft-config tooltip for HRTF tables --- utils/alsoft-config/mainwindow.ui | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 78564ada..ab575fee 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -224,6 +224,7 @@ to stereo output. are used in place of the default sets. The filenames may contain these markers, which will be replaced as needed: %r - Device sampling rate +%s - Non-greedy string (up to the following matching characters) %% - Percent sign (%) -- cgit v1.2.3 From e3d2df58b3cd8da8d326921b697ce7c40be4a058 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 04:01:15 -0800 Subject: Update changelog --- ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index de99cc98..a2661644 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,12 +6,12 @@ openal-soft-1.17.1: Fixed the ALSA backend's allow-resampler option. - Improved handling of inexact ALSA period counts. + Fixed handling of inexact ALSA period counts. Altered device naming scheme on Windows backends to better match other drivers. - Updated the CoreAudio backend to use the AudioComponent API. This fixes + Updated the CoreAudio backend to use the AudioComponent API. This clears up deprecation warnings for OSX 10.11, although requires OSX 10.6 or newer. openal-soft-1.17.0: -- cgit v1.2.3 From 14df326876d92f63c9c007da3c0434fba47c30b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Dec 2015 04:45:30 -0800 Subject: Release 1.17.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d1273d5..78059dba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ ENDIF() SET(LIB_MAJOR_VERSION "1") SET(LIB_MINOR_VERSION "17") -SET(LIB_REVISION "0") +SET(LIB_REVISION "1") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") -- cgit v1.2.3 From 13bf636a345b6caf65444c684b4a4c3b52fc263b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 07:26:27 -0800 Subject: Use Apple's pthread_setname_np before GNU's --- common/threads.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/threads.c b/common/threads.c index 71fa6ab9..8a1ad6ea 100644 --- a/common/threads.c +++ b/common/threads.c @@ -497,11 +497,11 @@ extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) -#if defined(__GNUC__) - pthread_setname_np(thr, name); -#elif defined(__APPLE__) +#if defined(__APPLE__) if(althrd_equal(thr, althrd_current()) pthread_setname_np(name); +#elif defined(__GNUC__) + pthread_setname_np(thr, name); #endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) pthread_set_name_np(thr, name); -- cgit v1.2.3 From d7b2bba2e694dd9a8ac9aa5f23837122a2f34523 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 07:35:39 -0800 Subject: Add missing closing parenthesis --- common/threads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/threads.c b/common/threads.c index 8a1ad6ea..1f6f2223 100644 --- a/common/threads.c +++ b/common/threads.c @@ -498,7 +498,7 @@ void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) #if defined(__APPLE__) - if(althrd_equal(thr, althrd_current()) + if(althrd_equal(thr, althrd_current())) pthread_setname_np(name); #elif defined(__GNUC__) pthread_setname_np(thr, name); -- cgit v1.2.3 From 01e43e5d4da47423a0457276febb01fb5efa84e4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 09:24:40 -0800 Subject: Add includes to work around broken GNU headers and POSIX-2001 --- Alc/backends/oss.c | 1 + Alc/backends/solaris.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index dce42e21..1c3763c6 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 52ca9090..6eaf1ee5 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From e034afe107dde75e34599a549a75f479bc692908 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 09:41:46 -0800 Subject: Check if _XOPEN_SOURCE needs to be set --- CMakeLists.txt | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78059dba..2fb0632b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,16 +98,31 @@ ELSE() ENDIF() ENDIF() -# Check if _POSIX_C_SOURCE needs to be set for POSIX functions -CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) -IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) - SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L") - CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) - IF(NOT HAVE_POSIX_MEMALIGN_POSIX) - SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) - ELSE() - ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L) +if(NOT WIN32) + # Check if _POSIX_C_SOURCE needs to be set for POSIX functions + CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) + IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) + SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L") + CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) + IF(NOT HAVE_POSIX_MEMALIGN_POSIX) + SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) + ELSE() + ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L) + ENDIF() + ENDIF() + + # Check if _XOPEN_SOURCE needs to be set (if POSIX < 2008) + CHECK_SYMBOL_EXISTS(scandir dirent.h HAVE_SCANDIR_DEFAULT) + IF(NOT HAVE_SCANDIR_DEFAULT) + SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_XOPEN_SOURCE=700") + CHECK_SYMBOL_EXISTS(scandir dirent.h HAVE_SCANDIR_XOPEN) + IF(NOT HAVE_SCANDIR_XOPEN) + SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) + ELSE() + ADD_DEFINITIONS(-D_XOPEN_SOURCE=700) + ENDIF() ENDIF() UNSET(OLD_REQUIRED_FLAGS) ENDIF() -- cgit v1.2.3 From 2850719ea213547e4dc5073da6e6ecfbad056b6a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 10:13:02 -0800 Subject: Add a .travis.yml for travis-ci --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..a4660249 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +language: c +script: cmake . && make -j2 -- cgit v1.2.3 From abd568f9d8bc7200da6b3f7cb1ab0d2d2fbc660b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Dec 2015 10:34:38 -0800 Subject: Build on Linux and OSX with Travis --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index a4660249..dfae8e7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,5 @@ +os: + - linux + - osx language: c script: cmake . && make -j2 -- cgit v1.2.3 From bce20d1f6be43dcf3a5be0ec97b35cbe335844e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Dec 2015 12:56:59 -0800 Subject: Don't overwrite the output with the dedicated effect --- Alc/effects/dedicated.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index e09cc682..dc581ace 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -86,7 +86,7 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesTo continue; for(i = 0;i < SamplesToDo;i++) - SamplesOut[c][i] = SamplesIn[i] * gains[c]; + SamplesOut[c][i] += SamplesIn[i] * gains[c]; } } -- cgit v1.2.3 From df2ee7ba873153a7bfe53665fd273eef22d12c68 Mon Sep 17 00:00:00 2001 From: "Keegan Drake H.P" Date: Thu, 17 Dec 2015 19:20:08 -0600 Subject: Add device enumeration support for OSSv4 --- Alc/backends/oss.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 206 insertions(+), 27 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 1c3763c6..c7fc404c 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -52,11 +52,158 @@ #define SOUND_MIXER_WRITE MIXER_WRITE #endif +#if defined(SOUND_VERSION) && (SOUND_VERSION) < 0x040000 +#define ALC_OSS_COMPAT +#endif +#ifndef SNDCTL_AUDIOINFO +#define ALC_OSS_COMPAT +#endif + +/* + * FreeBSD strongly discourages the use of specific devices, + * such as those returned in oss_audioinfo.devnode + */ +#ifdef __FreeBSD__ +#define ALC_OSS_DEVNODE_TRUC +#endif + +struct oss_device { + const ALCchar *handle; + const char *path; + struct oss_device *next; +}; + +static struct oss_device oss_playback = { + "OSS Default", + "/dev/dsp", + NULL +}; -static const ALCchar oss_device[] = "OSS Default"; +static struct oss_device oss_capture = { + "OSS Default", + "/dev/dsp", + NULL +}; -static const char *oss_driver = "/dev/dsp"; -static const char *oss_capture = "/dev/dsp"; +#ifdef ALC_OSS_COMPAT + +static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture) +{ + ; /* Stub */ +} + +static void ALCossListFree(struct oss_device *list) +{ + ; /* Stub */ +} + +#else + +static void ALCossListAppend(struct oss_device *list, char *handle, size_t hlen, char *path, size_t plen) { + struct oss_device *t; + struct oss_device *p; + void *m; + size_t i; + if (list == NULL || handle == NULL || path == NULL) + return; + /* skip the first item "OSS Default" */ + p = list; + t = list->next; +#ifdef ALC_OSS_DEVNODE_TRUC + for (i = 0; i < plen; i++) + if (path[i] == '.') + { + if (strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) + hlen = hlen + i - plen; + plen = i; + } +#endif + if (handle == NULL || hlen == 0 || *handle == '\0') { + handle = path; + hlen = plen; + } + while (t != NULL && strncmp(t->path, path, plen) != 0) { + p = t; + t = t->next; + } + if (t != NULL) + return; + m = malloc(sizeof(struct oss_device) + hlen + plen + 2); + t = (struct oss_device *)m; + t->handle = (char *)((uintptr_t)m + sizeof(struct oss_device)); + t->path = stpncpy((char *)t->handle, handle, hlen) + 1; + ((char *)t->handle)[hlen] = '\0'; + strncpy((char *)t->path, path, plen); + ((char *)t->path)[plen] = '\0'; + t->next = NULL; + p->next = t; +} + +static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture) +{ + struct oss_sysinfo si; + struct oss_audioinfo ai; + int fd; + int i; + if ((fd = open("/dev/mixer", O_RDONLY)) < 0) + { + ERR("Could not open /dev/mixer\n"); + return; + } + if (ioctl(fd, SNDCTL_SYSINFO, &si) == -1) + { + ERR("SNDCTL_SYSINFO\n"); + goto err; + } + for (i = 0; i < si.numaudios; i++) + { + char *handle; + size_t len; + ai.dev = i; + if (ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) + { + ERR("SNDCTL_SYSINFO\n"); + continue; + } + if (ai.handle[0] == '\0') + { + len = strnlen(ai.name, sizeof(ai.name)); + handle = ai.name; + } + else + { + len = strnlen(ai.handle, sizeof(ai.handle)); + handle = ai.handle; + } + if ((ai.caps & DSP_CAP_INPUT) && capture != NULL) + ALCossListAppend(capture, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); + if ((ai.caps & DSP_CAP_OUTPUT) && playback != NULL) + ALCossListAppend(playback, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); + } + close(fd); + return; +err: + if (fd >= 0) + close(fd); + return; +} + +static void ALCossListFree(struct oss_device *list) +{ + struct oss_device *cur, *t; + if (list == NULL) + return; + cur = list->next; + list->next = NULL; + while (cur != NULL) + { + t = cur->next; + free(cur); + cur = t; + } +} + +#endif static int log2i(ALCuint x) { @@ -69,7 +216,6 @@ static int log2i(ALCuint x) return y; } - typedef struct ALCplaybackOSS { DERIVE_FROM_TYPE(ALCbackend); @@ -153,19 +299,29 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { + struct oss_device *dev = &oss_playback; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; if(!name) - name = oss_device; - else if(strcmp(name, oss_device) != 0) - return ALC_INVALID_VALUE; + name = dev->handle; + else + { + while (dev != NULL) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if (dev == NULL) + return ALC_INVALID_VALUE; + } self->killNow = 0; - self->fd = open(oss_driver, O_WRONLY); + self->fd = open(dev->path, O_WRONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", oss_driver, strerror(errno)); + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); return ALC_INVALID_VALUE; } @@ -383,6 +539,7 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct oss_device *dev = &oss_capture; int numFragmentsLogSize; int log2FragmentSize; unsigned int periods; @@ -394,14 +551,23 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) char *err; if(!name) - name = oss_device; - else if(strcmp(name, oss_device) != 0) - return ALC_INVALID_VALUE; + name = dev->handle; + else + { + while (dev != NULL) + { + if (strcmp(dev->handle, name) == 0) + break; + dev = dev->next; + } + if (dev == NULL) + return ALC_INVALID_VALUE; + } - self->fd = open(oss_capture, O_RDONLY); + self->fd = open(dev->path, O_RDONLY); if(self->fd == -1) { - ERR("Could not open %s: %s\n", oss_capture, strerror(errno)); + ERR("Could not open %s: %s\n", dev->path, strerror(errno)); return ALC_INVALID_VALUE; } @@ -547,7 +713,7 @@ typedef struct ALCossBackendFactory { ALCbackendFactory *ALCossBackendFactory_getFactory(void); static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); -static DECLARE_FORWARD(ALCossBackendFactory, ALCbackendFactory, void, deinit) +static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); 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); @@ -563,12 +729,19 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void) ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) { - ConfigValueStr(NULL, "oss", "device", &oss_driver); - ConfigValueStr(NULL, "oss", "capture", &oss_capture); + ConfigValueStr(NULL, "oss", "device", &oss_playback.path); + ConfigValueStr(NULL, "oss", "capture", &oss_capture.path); return ALC_TRUE; } +void ALCossBackendFactory_deinit(ALCossBackendFactory* UNUSED(self)) +{ + ALCossListFree(&oss_playback); + ALCossListFree(&oss_capture); +} + + ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), ALCbackend_Type type) { if(type == ALCbackend_Playback || type == ALCbackend_Capture) @@ -582,21 +755,27 @@ void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProb { case ALL_DEVICE_PROBE: { -#ifdef HAVE_STAT - struct stat buf; - if(stat(oss_driver, &buf) == 0) -#endif - AppendAllDevicesList(oss_device); + struct oss_device *cur = &oss_playback; + ALCossListFree(cur); + ALCossListPopulate(cur, NULL); + while (cur != NULL) + { + AppendAllDevicesList(cur->handle); + cur = cur->next; + } } break; case CAPTURE_DEVICE_PROBE: { -#ifdef HAVE_STAT - struct stat buf; - if(stat(oss_capture, &buf) == 0) -#endif - AppendCaptureDeviceList(oss_device); + struct oss_device *cur = &oss_capture; + ALCossListFree(cur); + ALCossListPopulate(NULL, cur); + while (cur != NULL) + { + AppendCaptureDeviceList(cur->handle); + cur = cur->next; + } } break; } -- cgit v1.2.3 From 5a73aa2502a36af15a2d19be4474093c232e04b2 Mon Sep 17 00:00:00 2001 From: "Keegan Drake H.P" Date: Thu, 17 Dec 2015 20:05:21 -0600 Subject: Added a check for an empty path --- Alc/backends/oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index c7fc404c..9ca92410 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -104,7 +104,7 @@ static void ALCossListAppend(struct oss_device *list, char *handle, size_t hlen, struct oss_device *p; void *m; size_t i; - if (list == NULL || handle == NULL || path == NULL) + if (list == NULL || handle == NULL || path == NULL || plen == 0 || path[0] == '\0') return; /* skip the first item "OSS Default" */ p = list; @@ -118,7 +118,7 @@ static void ALCossListAppend(struct oss_device *list, char *handle, size_t hlen, plen = i; } #endif - if (handle == NULL || hlen == 0 || *handle == '\0') { + if (handle == NULL || hlen == 0 || handle[0] == '\0') { handle = path; hlen = plen; } -- cgit v1.2.3 From d93398a361da94cbb4f0ab07046fbab7c5e94e5d Mon Sep 17 00:00:00 2001 From: Niels Ole Salscheider Date: Sat, 19 Dec 2015 17:47:07 +0100 Subject: Allow to override the share install dir This is needed for multiarch layouts where the prefix is /usr/${host} but where arch-independet files are installed to /usr/share. --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb0632b..d6ffe9a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,9 @@ OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON) OPTION(ALSOFT_INSTALL "Install headers and libraries" ON) +set(SHARE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share" CACHE STRING "The share install dir") + + IF(NOT WIN32) SET(LIBNAME openal) ELSE() @@ -1174,7 +1177,7 @@ ENDIF() # Install alsoft.conf configuration file IF(ALSOFT_CONFIG) INSTALL(FILES alsoftrc.sample - DESTINATION share/openal + DESTINATION ${SHARE_INSTALL_DIR}/openal ) MESSAGE(STATUS "Installing sample configuration") MESSAGE(STATUS "") @@ -1184,7 +1187,7 @@ ENDIF() IF(ALSOFT_HRTF_DEFS) INSTALL(FILES hrtf/default-44100.mhr hrtf/default-48000.mhr - DESTINATION share/openal/hrtf + DESTINATION ${SHARE_INSTALL_DIR}/openal/hrtf ) MESSAGE(STATUS "Installing HRTF definitions") MESSAGE(STATUS "") -- cgit v1.2.3 From 0bb838bbaf8aae967588431adfbd4e5b8bee2317 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Jan 2016 15:45:42 -0800 Subject: Add an option to static-link libgcc Mainly just for MinGW to make OpenAL32.dll not rely on libgcc_s_sjlj-1.dll. --- CMakeLists.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6ffe9a2..f4740600 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,25 @@ ELSE() CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor)); int main() {return 0;}" HAVE_GCC_DESTRUCTOR) + + option(ALSOFT_STATIC_LIBGCC "Force -static-libgcc for static GCC runtimes" OFF) + if(ALSOFT_STATIC_LIBGCC) + set(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} -static-libgcc) + check_c_source_compiles( +"#include +int main() +{ + return 0; +}" + HAVE_STATIC_LIBGCC_SWITCH + ) + if(HAVE_STATIC_LIBGCC_SWITCH) + set(EXTRA_LIBS ${EXTRA_LIBS} -static-libgcc) + endif() + set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) + unset(OLD_REQUIRED_LIBRARIES) + endif() ENDIF() # Set visibility/export options if available -- cgit v1.2.3 From 0eb18e97112c2d7b35fe11339175161740c8fae1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Jan 2016 22:38:27 -0800 Subject: Update ChangeLog --- ChangeLog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ChangeLog b/ChangeLog index a2661644..189872cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +openal-soft-1.17.2: + + Implemented device enumeration for OSSv4. + + Fixed building on OSX. + + Fixed building on non-Windows systems without POSIX-2008. + + Fixed Dedicated Dialog and Dedicated LFE effect output. + + Added a build option to override the share install dir. + + Added a build option to static-link libgcc for MinGW. + openal-soft-1.17.1: Fixed building with JACK and without PulseAudio. -- cgit v1.2.3 From 3395b361fa59374c1c022ce1cc8c203f5d70f356 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Jan 2016 18:42:23 -0800 Subject: Silence a CMake warning on OSX about MACOSX_RPATH --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4740600..513bd037 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ PROJECT(OpenAL) IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0003 NEW) CMAKE_POLICY(SET CMP0005 NEW) + CMAKE_POLICY(SET CMP0042 NEW) ENDIF(COMMAND CMAKE_POLICY) SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") -- cgit v1.2.3 From bbd2876afb5265517d25e78d7dcaf7ccb494af0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 01:05:29 -0800 Subject: Improve the OSS enumeration code --- Alc/backends/oss.c | 134 ++++++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 63 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 9ca92410..1e286791 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -52,7 +52,7 @@ #define SOUND_MIXER_WRITE MIXER_WRITE #endif -#if defined(SOUND_VERSION) && (SOUND_VERSION) < 0x040000 +#if defined(SOUND_VERSION) && (SOUND_VERSION < 0x040000) #define ALC_OSS_COMPAT #endif #ifndef SNDCTL_AUDIOINFO @@ -85,126 +85,134 @@ static struct oss_device oss_capture = { NULL }; -#ifdef ALC_OSS_COMPAT +#ifdef ALC_OSS_COMPAT -static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture) -{ - ; /* Stub */ -} - -static void ALCossListFree(struct oss_device *list) +static void ALCossListPopulate(struct oss_device *UNUSED(playback), struct oss_device *UNUSED(capture)) { - ; /* Stub */ } #else -static void ALCossListAppend(struct oss_device *list, char *handle, size_t hlen, char *path, size_t plen) { - struct oss_device *t; - struct oss_device *p; - void *m; +static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) +{ + struct oss_device *next; + struct oss_device *last; size_t i; - if (list == NULL || handle == NULL || path == NULL || plen == 0 || path[0] == '\0') + + if(plen == 0 || path[0] == '\0') return; + /* skip the first item "OSS Default" */ - p = list; - t = list->next; + last = list; + next = list->next; #ifdef ALC_OSS_DEVNODE_TRUC - for (i = 0; i < plen; i++) - if (path[i] == '.') + for(i = 0;i < plen;i++) + { + if(path[i] == '.') { - if (strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) + if(strncmp(path + i, handle + hlen + i - plen, plen - i) == 0) hlen = hlen + i - plen; plen = i; } + } +#else + (void)i; #endif - if (handle == NULL || hlen == 0 || handle[0] == '\0') { + if(handle[0] == '\0') + { handle = path; hlen = plen; } - while (t != NULL && strncmp(t->path, path, plen) != 0) { - p = t; - t = t->next; + + while(next != NULL) + { + if(strncmp(next->path, path, plen) == 0) + return; + last = next; + next = next->next; } - if (t != NULL) - return; - m = malloc(sizeof(struct oss_device) + hlen + plen + 2); - t = (struct oss_device *)m; - t->handle = (char *)((uintptr_t)m + sizeof(struct oss_device)); - t->path = stpncpy((char *)t->handle, handle, hlen) + 1; - ((char *)t->handle)[hlen] = '\0'; - strncpy((char *)t->path, path, plen); - ((char *)t->path)[plen] = '\0'; - t->next = NULL; - p->next = t; + + next = (struct oss_device*)malloc(sizeof(struct oss_device) + hlen + plen + 2); + next->handle = (char*)(next + 1); + next->path = next->handle + hlen + 1; + next->next = NULL; + last->next = next; + + strncpy((char*)next->handle, handle, hlen); + ((char*)next->handle)[hlen] = '\0'; + strncpy((char*)next->path, path, plen); + ((char*)next->path)[plen] = '\0'; + + TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); } static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture) { struct oss_sysinfo si; struct oss_audioinfo ai; - int fd; - int i; - if ((fd = open("/dev/mixer", O_RDONLY)) < 0) + int fd, i; + + if((fd=open("/dev/mixer", O_RDONLY)) < 0) { ERR("Could not open /dev/mixer\n"); return; } - if (ioctl(fd, SNDCTL_SYSINFO, &si) == -1) + if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1) { - ERR("SNDCTL_SYSINFO\n"); - goto err; + ERR("SNDCTL_SYSINFO failed: %s\n", strerror(errno)); + goto done; } - for (i = 0; i < si.numaudios; i++) + for(i = 0;i < si.numaudios;i++) { - char *handle; + const char *handle; size_t len; + ai.dev = i; - if (ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) + if(ioctl(fd, SNDCTL_AUDIOINFO, &ai) == -1) { - ERR("SNDCTL_SYSINFO\n"); + ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); continue; } - if (ai.handle[0] == '\0') + if(ai.handle[0]) { - len = strnlen(ai.name, sizeof(ai.name)); - handle = ai.name; + len = strnlen(ai.handle, sizeof(ai.handle)); + handle = ai.handle; } else { - len = strnlen(ai.handle, sizeof(ai.handle)); - handle = ai.handle; + len = strnlen(ai.name, sizeof(ai.name)); + handle = ai.name; } - if ((ai.caps & DSP_CAP_INPUT) && capture != NULL) + if((ai.caps&DSP_CAP_INPUT) && capture != NULL) ALCossListAppend(capture, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); - if ((ai.caps & DSP_CAP_OUTPUT) && playback != NULL) + if((ai.caps&DSP_CAP_OUTPUT) && playback != NULL) ALCossListAppend(playback, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); } + +done: close(fd); - return; -err: - if (fd >= 0) - close(fd); - return; } +#endif + static void ALCossListFree(struct oss_device *list) { - struct oss_device *cur, *t; - if (list == NULL) + struct oss_device *cur; + if(list == NULL) return; + + /* skip the first item "OSS Default" */ cur = list->next; list->next = NULL; - while (cur != NULL) + + while(cur != NULL) { - t = cur->next; + struct oss_device *next = cur->next; free(cur); - cur = t; + cur = next; } } -#endif - static int log2i(ALCuint x) { int y = 0; -- cgit v1.2.3 From 9c05a16c9a394dea90fcefc29eb2ef2be06dc4b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 02:08:45 -0800 Subject: Fix for systems that don't have strnlen --- Alc/backends/oss.c | 18 ++++++++++++++---- CMakeLists.txt | 3 ++- config.h.in | 3 +++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 1e286791..33d7750a 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -93,15 +94,21 @@ static void ALCossListPopulate(struct oss_device *UNUSED(playback), struct oss_d #else +#ifndef HAVE_STRNLEN +static size_t strnlen(const char *str, size_t maxlen) +{ + const char *end = memchr(str, 0, maxlen); + if(!end) return maxlen; + return end - str; +} +#endif + static void ALCossListAppend(struct oss_device *list, const char *handle, size_t hlen, const char *path, size_t plen) { struct oss_device *next; struct oss_device *last; size_t i; - if(plen == 0 || path[0] == '\0') - return; - /* skip the first item "OSS Default" */ last = list; next = list->next; @@ -173,7 +180,10 @@ static void ALCossListPopulate(struct oss_device *playback, struct oss_device *c ERR("SNDCTL_AUDIOINFO (%d) failed: %s\n", i, strerror(errno)); continue; } - if(ai.handle[0]) + if(ai.devnode[0] == '\0') + continue; + + if(ai.handle[0] != '\0') { len = strnlen(ai.handle, sizeof(ai.handle)); handle = ai.handle; diff --git a/CMakeLists.txt b/CMakeLists.txt index 513bd037..e503df92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,8 +453,8 @@ IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2) ENDIF() -CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF) CHECK_FUNCTION_EXISTS(stat HAVE_STAT) +CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF) CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP) IF(NOT HAVE_STRCASECMP) CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP) @@ -475,6 +475,7 @@ IF(NOT HAVE_STRNCASECMP) ADD_DEFINITIONS(-Dstrncasecmp=_strnicmp) ENDIF() +CHECK_SYMBOL_EXISTS(strnlen string.h HAVE_STRNLEN) CHECK_SYMBOL_EXISTS(snprintf stdio.h HAVE_SNPRINTF) IF(NOT HAVE_SNPRINTF) CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF) diff --git a/config.h.in b/config.h.in index e66b1fe8..3bc3eb48 100644 --- a/config.h.in +++ b/config.h.in @@ -86,6 +86,9 @@ /* Define if we have the strtof function */ #cmakedefine HAVE_STRTOF +/* Define if we have the strnlen function */ +#cmakedefine HAVE_STRNLEN + /* Define if we have the __int64 type */ #cmakedefine HAVE___INT64 -- cgit v1.2.3 From bb0ac26ce1bc8966d87e5db2d9a9675bd939b6af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 02:33:45 -0800 Subject: Explicit check if pthread_setname_np accepts only one parameter --- CMakeLists.txt | 21 +++++++++++++++++++++ common/threads.c | 4 ++-- config.h.in | 3 +++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e503df92..9326f270 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -561,12 +561,33 @@ IF(NOT HAVE_WINDOWS_H) CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP) IF(NOT HAVE_PTHREAD_SETNAME_NP) CHECK_SYMBOL_EXISTS(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP) + ELSE() + CHECK_C_SOURCE_COMPILES(" +#include +#include +int main() +{ + pthread_setname_np(\"testname\"); + return 0; +}" + PTHREAD_SETNAME_NP_ONE_PARAM + ) ENDIF() CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) ELSE() 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) + ELSE() + CHECK_C_SOURCE_COMPILES(" +#include +int main() +{ + pthread_setname_np(\"testname\"); + return 0; +}" + PTHREAD_SETNAME_NP_ONE_PARAM + ) ENDIF() CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) ENDIF() diff --git a/common/threads.c b/common/threads.c index 1f6f2223..127b9083 100644 --- a/common/threads.c +++ b/common/threads.c @@ -497,10 +497,10 @@ extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); void althrd_setname(althrd_t thr, const char *name) { #if defined(HAVE_PTHREAD_SETNAME_NP) -#if defined(__APPLE__) +#if defined(PTHREAD_SETNAME_NP_ONE_PARAM) if(althrd_equal(thr, althrd_current())) pthread_setname_np(name); -#elif defined(__GNUC__) +#else pthread_setname_np(thr, name); #endif #elif defined(HAVE_PTHREAD_SET_NAME_NP) diff --git a/config.h.in b/config.h.in index 3bc3eb48..dd020027 100644 --- a/config.h.in +++ b/config.h.in @@ -194,6 +194,9 @@ /* Define if we have pthread_setname_np() */ #cmakedefine HAVE_PTHREAD_SETNAME_NP +/* Define if pthread_setname_np() only accepts one parameter */ +#cmakedefine PTHREAD_SETNAME_NP_ONE_PARAM + /* Define if we have pthread_set_name_np() */ #cmakedefine HAVE_PTHREAD_SET_NAME_NP -- cgit v1.2.3 From 8f26ad4ba237b3ad42fd1e28a7d800e4dc9e7fe4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 04:42:22 -0800 Subject: Avoid using scandir/alphasort They require POSIX 2008, which is a bit too "new" for my current liking. We can do well enough with opendir/readdir/closedir and qsort. --- Alc/helpers.c | 69 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index e9efddf3..9a9273c4 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -364,6 +364,11 @@ void RestoreFPUMode(const FPUCtl *ctl) } +static int StringSortCompare(const void *str1, const void *str2) +{ + return al_string_cmp(*(const_al_string*)str1, *(const_al_string*)str2); +} + #ifdef _WIN32 static WCHAR *FromUTF8(const char *str) @@ -706,6 +711,7 @@ static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_ hdl = FindFirstFileW(wpath, &fdata); if(hdl != INVALID_HANDLE_VALUE) { + size_t base = VECTOR_SIZE(*results); do { if(MatchFilter(match, &fdata)) { @@ -718,6 +724,10 @@ static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_ } } while(FindNextFileW(hdl, &fdata)); FindClose(hdl); + + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } free(wpath); @@ -1016,11 +1026,8 @@ FILE *OpenDataFile(const char *fname, const char *subdir) } -static const char *MatchString; -static int MatchFilter(const struct dirent *dir) +static int MatchFilter(const char *name, const char *match) { - const char *match = MatchString; - const char *name = dir->d_name; int ret = 1; do { @@ -1089,9 +1096,7 @@ static int MatchFilter(const struct dirent *dir) static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results) { - struct dirent **namelist; char *sep, *p; - int n, i; if(!match[0]) return; @@ -1101,22 +1106,33 @@ static void RecurseDirectorySearch(const char *path, const char *match, vector_a if(!sep) { - MatchString = match; + DIR *dir; + TRACE("Searching %s for %s\n", path?path:"/", match); - n = scandir(path?path:"/", &namelist, MatchFilter, alphasort); - if(n >= 0) + dir = opendir(path?path:"/"); + if(dir != NULL) { - for(i = 0;i < n;++i) + size_t base = VECTOR_SIZE(*results); + struct dirent *dirent; + while((dirent=readdir(dir)) != NULL) { - al_string str = AL_STRING_INIT_STATIC(); + al_string str; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || + !MatchFilter(dirent->d_name, match)) + continue; + + AL_STRING_INIT(str); if(path) al_string_copy_cstr(&str, path); al_string_append_char(&str, '/'); - al_string_append_cstr(&str, namelist[i]->d_name); + al_string_append_cstr(&str, dirent->d_name); TRACE("Got result %s\n", al_string_get_cstr(str)); VECTOR_PUSH_BACK(*results, str); - free(namelist[i]); } - free(namelist); + closedir(dir); + + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } return; @@ -1145,11 +1161,13 @@ static void RecurseDirectorySearch(const char *path, const char *match, vector_a { al_string npath = AL_STRING_INIT_STATIC(); al_string nmatch = AL_STRING_INIT_STATIC(); + const char *tomatch; + DIR *dir; if(!sep) { al_string_append_cstr(&npath, path?path:"/."); - MatchString = match; + tomatch = match; } else { @@ -1158,25 +1176,30 @@ static void RecurseDirectorySearch(const char *path, const char *match, vector_a al_string_append_range(&npath, match, sep); al_string_append_range(&nmatch, sep+1, next); - MatchString = al_string_get_cstr(nmatch); + tomatch = al_string_get_cstr(nmatch); } - TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString); - n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort); - if(n >= 0) + TRACE("Searching %s for %s\n", al_string_get_cstr(npath), tomatch); + dir = opendir(path?path:"/"); + if(dir != NULL) { al_string ndir = AL_STRING_INIT_STATIC(); - for(i = 0;i < n;++i) + struct dirent *dirent; + + while((dirent=readdir(dir)) != NULL) { + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || + !MatchFilter(dirent->d_name, tomatch)) + continue; al_string_copy(&ndir, npath); al_string_append_char(&ndir, '/'); - al_string_append_cstr(&ndir, namelist[i]->d_name); - free(namelist[i]); + al_string_append_cstr(&ndir, dirent->d_name); TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1); RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); } + closedir(dir); + al_string_deinit(&ndir); - free(namelist); } al_string_deinit(&nmatch); -- cgit v1.2.3 From 0a9e9858f983b7b4c6b92c3d9ecf69a9d3ecb3f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 06:08:18 -0800 Subject: Always define _XOPEN_SOURCE if _POSIX_C_SOURCE is too --- CMakeLists.txt | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9326f270..dac8d998 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,29 +103,16 @@ ELSE() ENDIF() if(NOT WIN32) - # Check if _POSIX_C_SOURCE needs to be set for POSIX functions + # Check if _POSIX_C_SOURCE and _XOPEN_SOURCE needs to be set for POSIX functions CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L") + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700") CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) IF(NOT HAVE_POSIX_MEMALIGN_POSIX) SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) ELSE() - ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L) - ENDIF() - ENDIF() - - # Check if _XOPEN_SOURCE needs to be set (if POSIX < 2008) - CHECK_SYMBOL_EXISTS(scandir dirent.h HAVE_SCANDIR_DEFAULT) - IF(NOT HAVE_SCANDIR_DEFAULT) - SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_XOPEN_SOURCE=700") - CHECK_SYMBOL_EXISTS(scandir dirent.h HAVE_SCANDIR_XOPEN) - IF(NOT HAVE_SCANDIR_XOPEN) - SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) - ELSE() - ADD_DEFINITIONS(-D_XOPEN_SOURCE=700) + ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700) ENDIF() ENDIF() UNSET(OLD_REQUIRED_FLAGS) -- cgit v1.2.3 From 26f5d385d557e677ef3c0600343a9997d3bebe3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 06:18:54 -0800 Subject: Only set cmake policy CMP0042 if it's valid --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dac8d998..847adc7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,11 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(OpenAL) IF(COMMAND CMAKE_POLICY) - CMAKE_POLICY(SET CMP0003 NEW) - CMAKE_POLICY(SET CMP0005 NEW) - CMAKE_POLICY(SET CMP0042 NEW) + CMAKE_POLICY(SET CMP0003 NEW) + CMAKE_POLICY(SET CMP0005 NEW) + IF(POLICY CMP0042) + CMAKE_POLICY(SET CMP0042 NEW) + ENDIF(POLICY CMP0042) ENDIF(COMMAND CMAKE_POLICY) SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") -- cgit v1.2.3 From fb599b5b83f8c6926d2c30a18fa093d14ea087a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 17:18:08 -0800 Subject: Lower the _POSIX_C_SOURCE and _XOPEN_SOURCE version requirements --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 847adc7c..d3b35c2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,12 +109,12 @@ if(NOT WIN32) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700") + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500") CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) IF(NOT HAVE_POSIX_MEMALIGN_POSIX) SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) ELSE() - ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700) + ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500) ENDIF() ENDIF() UNSET(OLD_REQUIRED_FLAGS) -- cgit v1.2.3 From 87b6c30932d66228af4774d6e65bdea3d9895514 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 21 Jan 2016 21:51:20 -0800 Subject: Reorder some cmake checks --- CMakeLists.txt | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3b35c2f..1ce10be7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -398,6 +398,25 @@ IF(NOT HAVE_GUIDDEF_H) CHECK_INCLUDE_FILE(initguid.h HAVE_INITGUID_H) ENDIF() +# Some systems need libm for some of the following math functions to work +CHECK_LIBRARY_EXISTS(m pow "" HAVE_LIBM) +IF(HAVE_LIBM) + SET(EXTRA_LIBS m ${EXTRA_LIBS}) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m) +ENDIF() + +# Check for the dlopen API (for dynamicly loading backend libs) +IF(ALSOFT_DLOPEN) + CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL) + IF(HAVE_LIBDL) + SET(EXTRA_LIBS dl ${EXTRA_LIBS}) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dl) + ENDIF() + + CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) +ENDIF() + +# Check for a cpuid intrinsic IF(HAVE_CPUID_H) CHECK_C_SOURCE_COMPILES("#include int main() @@ -406,7 +425,6 @@ IF(HAVE_CPUID_H) return __get_cpuid(0, &eax, &ebx, &ecx, &edx); }" HAVE_GCC_GET_CPUID) ENDIF() - IF(HAVE_INTRIN_H) CHECK_C_SOURCE_COMPILES("#include int main() @@ -417,14 +435,6 @@ IF(HAVE_INTRIN_H) }" HAVE_CPUID_INTRINSIC) ENDIF() -# Some systems need libm for some of the following math functions to work -CHECK_LIBRARY_EXISTS(m pow "" HAVE_LIBM) -IF(HAVE_LIBM) - SET(EXTRA_LIBS m ${EXTRA_LIBS}) - SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m) -ENDIF() - - CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) @@ -500,17 +510,6 @@ IF(NOT HAVE_ISNAN) ENDIF() -# Check for the dlopen API (for dynamicly loading backend libs) -IF(ALSOFT_DLOPEN) - CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) - IF(HAVE_DLFCN_H) - CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL) - IF(HAVE_LIBDL) - SET(EXTRA_LIBS dl ${EXTRA_LIBS}) - ENDIF() - ENDIF() -ENDIF() - # Check if we have Windows headers CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0502) IF(NOT HAVE_WINDOWS_H) -- cgit v1.2.3 From 352d9afd642e94651e69dbb28ade50eea88eae0d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Jan 2016 01:22:08 -0800 Subject: Inline a couple filterstate methods --- OpenAL32/Include/alFilter.h | 27 +++++++++++++++++++++++++-- OpenAL32/alFilter.c | 27 ++------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 3c65fd9f..fa86af27 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -68,7 +68,14 @@ inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth) return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); } -void ALfilterState_clear(ALfilterState *filter); +inline void ALfilterState_clear(ALfilterState *filter) +{ + filter->x[0] = 0.0f; + filter->x[1] = 0.0f; + filter->y[0] = 0.0f; + filter->y[1] = 0.0f; +} + void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample) @@ -90,7 +97,23 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); -void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); +inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) +{ + if(numsamples >= 2) + { + filter->x[1] = src[numsamples-2]; + filter->x[0] = src[numsamples-1]; + filter->y[1] = src[numsamples-2]; + filter->y[0] = src[numsamples-1]; + } + else if(numsamples == 1) + { + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = src[0]; + } +} typedef struct ALfilter { diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 3cf82c32..6d088a45 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -330,13 +330,8 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va } -void ALfilterState_clear(ALfilterState *filter) -{ - filter->x[0] = 0.0f; - filter->x[1] = 0.0f; - filter->y[0] = 0.0f; - filter->y[1] = 0.0f; -} +extern inline void ALfilterState_clear(ALfilterState *filter); +extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ) { @@ -418,24 +413,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->process = ALfilterState_processC; } -void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) -{ - if(numsamples >= 2) - { - filter->x[1] = src[numsamples-2]; - filter->x[0] = src[numsamples-1]; - filter->y[1] = src[numsamples-2]; - filter->y[0] = src[numsamples-1]; - } - else if(numsamples == 1) - { - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = src[0]; - } -} - static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -- cgit v1.2.3 From 94816d007375295a8d767b06a483a060be292692 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Jan 2016 03:38:15 -0800 Subject: Reorder filterstate properties --- Alc/effects/autowah.c | 26 +++++++------- Alc/effects/modulator.c | 11 +++--- OpenAL32/Include/alFilter.h | 15 ++++---- OpenAL32/alFilter.c | 85 +++++++++++++++++++++++---------------------- 4 files changed, 69 insertions(+), 68 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 6770f719..e97083e0 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -92,6 +92,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, for(it = 0;it < td;it++) { ALfloat smp = SamplesIn[it+base]; + ALfloat a[3], b[3]; ALfloat alpha, w0; ALfloat amplitude; ALfloat cutoff; @@ -117,19 +118,18 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, /* 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]; + b[0] = (1.0f - cosf(w0)) / 2.0f; + b[1] = 1.0f - cosf(w0); + b[2] = (1.0f - cosf(w0)) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cosf(w0); + a[2] = 1.0f - alpha; + + state->LowPass.a1 = a[1] / a[0]; + state->LowPass.a2 = a[2] / a[0]; + state->LowPass.b1 = b[1] / a[0]; + state->LowPass.b2 = b[2] / a[0]; + state->LowPass.input_gain = b[0] / a[0]; temps[it] = ALfilterState_processSingle(&state->LowPass, smp); } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index dceb408e..32d25c76 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -142,12 +142,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device cw = cosf(F_TAU * 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; + state->Filter.a1 = -a; + state->Filter.a2 = 0.0f; + state->Filter.b1 = -a; + state->Filter.b2 = 0.0f; + state->Filter.input_gain = a; ComputeAmbientGains(Device, Slot->Gain, state->Gain); } diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index fa86af27..6f44e3b7 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -42,8 +42,9 @@ typedef enum ALfilterType { 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" */ + ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ + ALfloat b1, b2; /* Transfer function coefficients "b" (b0 is input_gain) */ + ALfloat input_gain; void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); } ALfilterState; @@ -82,11 +83,11 @@ 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]; + outsmp = filter->input_gain * sample + + filter->b1 * filter->x[0] + + filter->b2 * filter->x[1] - + filter->a1 * filter->y[0] - + filter->a2 * filter->y[1]; filter->x[1] = filter->x[0]; filter->x[0] = sample; filter->y[1] = filter->y[0]; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 6d088a45..4280f41e 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -337,6 +337,8 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g { ALfloat alpha, sqrtgain_alpha_2; ALfloat w0, sin_w0, cos_w0; + ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; + ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; // Limit gain to -100dB gain = maxf(gain, 0.00001f); @@ -351,64 +353,63 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g { case ALfilterType_HighShelf: sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); - filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - filter->a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); - filter->a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_LowShelf: sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); - filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - filter->a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); - filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_Peaking: gain = sqrtf(gain); - filter->b[0] = 1.0f + alpha * gain; - filter->b[1] = -2.0f * cos_w0; - filter->b[2] = 1.0f - alpha * gain; - filter->a[0] = 1.0f + alpha / gain; - filter->a[1] = -2.0f * cos_w0; - filter->a[2] = 1.0f - alpha / gain; + b[0] = 1.0f + alpha * gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha * gain; + a[0] = 1.0f + alpha / gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha / gain; break; case ALfilterType_LowPass: - filter->b[0] = (1.0f - cos_w0) / 2.0f; - filter->b[1] = 1.0f - cos_w0; - filter->b[2] = (1.0f - cos_w0) / 2.0f; - filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cos_w0; - filter->a[2] = 1.0f - alpha; + b[0] = (1.0f - cos_w0) / 2.0f; + b[1] = 1.0f - cos_w0; + b[2] = (1.0f - cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; break; case ALfilterType_HighPass: - filter->b[0] = (1.0f + cos_w0) / 2.0f; - filter->b[1] = -(1.0f + cos_w0); - filter->b[2] = (1.0f + cos_w0) / 2.0f; - filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cos_w0; - filter->a[2] = 1.0f - alpha; + b[0] = (1.0f + cos_w0) / 2.0f; + b[1] = -(1.0f + cos_w0); + b[2] = (1.0f + cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; break; case ALfilterType_BandPass: - filter->b[0] = alpha; - filter->b[1] = 0; - filter->b[2] = -alpha; - filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cos_w0; - filter->a[2] = 1.0f - alpha; + b[0] = alpha; + b[1] = 0; + b[2] = -alpha; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; break; } - 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]; + filter->a1 = a[1] / a[0]; + filter->a2 = a[2] / a[0]; + filter->b1 = b[1] / a[0]; + filter->b2 = b[2] / a[0]; + filter->input_gain = b[0] / a[0]; filter->process = ALfilterState_processC; } -- cgit v1.2.3 From 5d552980a4e16a8266a59a2ebb35a1ce2a09de4e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Jan 2016 18:19:19 -0800 Subject: Move a couple extern inline declarations to the others --- OpenAL32/alFilter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 4280f41e..8e04ec2a 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -31,6 +31,8 @@ extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); +extern inline void ALfilterState_clear(ALfilterState *filter); +extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); @@ -330,9 +332,6 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va } -extern inline void ALfilterState_clear(ALfilterState *filter); -extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); - void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ) { ALfloat alpha, sqrtgain_alpha_2; -- cgit v1.2.3 From 7de8db2960e374e34bd48cd26d22315e63d17ebb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Jan 2016 21:47:43 -0800 Subject: Replace multiple fputc calls with one fwrite --- Alc/backends/wave.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 6b47c611..d54e21eb 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -56,16 +56,14 @@ static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = { static void fwrite16le(ALushort val, FILE *f) { - fputc(val&0xff, f); - fputc((val>>8)&0xff, f); + ALubyte data[2] = { val&0xff, (val>>8)&0xff }; + fwrite(data, 1, 2, f); } static void fwrite32le(ALuint val, FILE *f) { - fputc(val&0xff, f); - fputc((val>>8)&0xff, f); - fputc((val>>16)&0xff, f); - fputc((val>>24)&0xff, f); + ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff }; + fwrite(data, 1, 4, f); } -- cgit v1.2.3 From ddc885604df0521fb6f8f6862ce0d4c749b55fc8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Jan 2016 01:35:09 -0800 Subject: Clear SSE3 switch before testing if one's recognized --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ce10be7..bf97f4a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -358,6 +358,7 @@ ENDIF() SET(SSE_SWITCH "") SET(SSE2_SWITCH "") +SET(SSE3_SWITCH "") SET(SSE4_1_SWITCH "") IF(NOT MSVC) CHECK_C_COMPILER_FLAG(-msse HAVE_MSSE_SWITCH) -- cgit v1.2.3 From 5761aa9400ae6a4604ac1a81e582a4cd992933fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Jan 2016 01:51:43 -0800 Subject: Remove unneeded check for io.h --- CMakeLists.txt | 1 - config.h.in | 3 --- 2 files changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf97f4a0..c6262952 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,7 +386,6 @@ CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H) CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H) CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H) -CHECK_INCLUDE_FILE(io.h HAVE_IO_H) CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) CHECK_INCLUDE_FILE(intrin.h HAVE_INTRIN_H) diff --git a/config.h.in b/config.h.in index dd020027..b59226ee 100644 --- a/config.h.in +++ b/config.h.in @@ -146,9 +146,6 @@ /* Define if we have dirent.h */ #cmakedefine HAVE_DIRENT_H -/* Define if we have io.h */ -#cmakedefine HAVE_IO_H - /* Define if we have strings.h */ #cmakedefine HAVE_STRINGS_H -- cgit v1.2.3 From 4fb252677958b1eb11327f5617f090afbdfb5a71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Jan 2016 02:29:26 -0800 Subject: Fix "signed and unsigned type in conditional expression" warning --- examples/alffplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index 17f6d3bc..ab67d216 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -686,7 +686,7 @@ static int audio_thread(void *userdata) movState->audio.st->codec->sample_rate, movState->audio.st->codec->channel_layout ? movState->audio.st->codec->channel_layout : - av_get_default_channel_layout(movState->audio.st->codec->channels), + (uint64_t)av_get_default_channel_layout(movState->audio.st->codec->channels), movState->audio.st->codec->sample_fmt, movState->audio.st->codec->sample_rate, 0, NULL -- cgit v1.2.3 From 0189b923a233e269b4c8f9d17f6475ace5e2e4de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Jan 2016 19:12:39 -0800 Subject: Release 1.17.2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6262952..5784d351 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,7 @@ ENDIF() SET(LIB_MAJOR_VERSION "1") SET(LIB_MINOR_VERSION "17") -SET(LIB_REVISION "1") +SET(LIB_REVISION "2") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") -- cgit v1.2.3 From 79e0f3e747880a3e7d8342a8602b796b84c0f322 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jan 2016 01:49:28 -0800 Subject: Don't write one byte at a time for the wave writer on big endian --- Alc/backends/wave.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index d54e21eb..3b87d645 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -163,31 +163,33 @@ static int ALCwaveBackend_mixerProc(void *ptr) if(!IS_LITTLE_ENDIAN) { ALuint bytesize = BytesFromDevFmt(device->FmtType); - ALubyte *bytes = self->mBuffer; ALuint i; - if(bytesize == 1) + if(bytesize == 2) { - for(i = 0;i < self->mSize;i++) - fputc(bytes[i], self->mFile); - } - else if(bytesize == 2) - { - for(i = 0;i < self->mSize;i++) - fputc(bytes[i^1], self->mFile); + ALushort *samples = self->mBuffer; + ALuint len = self->mSize / 2; + for(i = 0;i < len;i++) + { + ALushort samp = samples[i]; + samples[i] = (samp>>8) | (samp<<8); + } } else if(bytesize == 4) { - for(i = 0;i < self->mSize;i++) - fputc(bytes[i^3], self->mFile); + ALuint *samples = self->mBuffer; + ALuint len = self->mSize / 4; + for(i = 0;i < len;i++) + { + ALuint samp = samples[i]; + samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) | + ((samp<<8)&0x00ff0000) | (samp<<24); + } } } - else - { - fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, - self->mFile); - (void)fs; - } + + fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, self->mFile); + (void)fs; if(ferror(self->mFile)) { ERR("Error writing to file\n"); -- cgit v1.2.3 From f547ef6d391be5e0cd3e0477c3f8de859a47df69 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jan 2016 06:11:51 -0800 Subject: Separate calculating ambisonic coefficients from the panning gains --- Alc/ALu.c | 16 ++++++--- Alc/effects/autowah.c | 4 +-- Alc/effects/chorus.c | 11 +++--- Alc/effects/compressor.c | 4 +-- Alc/effects/dedicated.c | 7 ++-- Alc/effects/distortion.c | 4 +-- Alc/effects/echo.c | 12 +++---- Alc/effects/equalizer.c | 4 +-- Alc/effects/flanger.c | 11 +++--- Alc/effects/modulator.c | 4 +-- Alc/effects/null.c | 2 +- Alc/effects/reverb.c | 19 +++++++--- Alc/panning.c | 73 +++++++++++++++++++++----------------- OpenAL32/Include/alAuxEffectSlot.h | 4 +-- OpenAL32/Include/alu.h | 48 +++++++++++++++++-------- 15 files changed, 134 insertions(+), 89 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 91c2aa7f..6a500833 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -471,7 +471,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; - ALCdevice *Device = ALContext->Device; + const ALCdevice *Device = ALContext->Device; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum FmtChannels Channels; @@ -646,7 +646,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A MixGains *gains = voice->Direct.Gains[c]; ALfloat Target[MAX_OUTPUT_CHANNELS]; - ComputeBFormatGains(Device, matrix.m[c], DryGain, Target); + ComputeBFormatGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; } @@ -751,6 +751,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { MixGains *gains = voice->Direct.Gains[c]; ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; /* Special-case LFE */ if(chans[c].channel == LFE) @@ -763,7 +764,9 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A continue; } - ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; } @@ -826,7 +829,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { - ALCdevice *Device = ALContext->Device; + const ALCdevice *Device = ALContext->Device; aluVector Position, Velocity, Direction, SourceToListener; ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; @@ -1223,6 +1226,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; /* Get the localized direction, and compute panned gains. */ if(Distance > FLT_EPSILON) @@ -1242,10 +1246,12 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte dir[1] *= dirfact; dir[2] *= dirfact; } - ComputeDirectionalGains(Device, dir, DryGain, Target); + CalcDirectionCoeffs(dir, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, Target); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) gains[j].Target = Target[j]; + UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index e97083e0..2da75c56 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -63,7 +63,7 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d return AL_TRUE; } -static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *device, const ALeffectslot *slot) { ALfloat attackTime, releaseTime; @@ -75,7 +75,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co state->PeakGain = slot->EffectProps.Autowah.PeakGain; state->Resonance = slot->EffectProps.Autowah.Resonance; - ComputeAmbientGains(device, slot->Gain, state->Gain); + ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); } static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 7aa5898b..1477d58b 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -91,11 +91,10 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev return AL_TRUE; } -static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot) { - static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f }; - static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f }; ALfloat frequency = (ALfloat)Device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat rate; ALint phase; @@ -113,8 +112,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ - ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]); - ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]); + CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[0]); + CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 9859a085..52a6324d 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -55,11 +55,11 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev return AL_TRUE; } -static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot) { state->Enabled = slot->EffectProps.Compressor.OnOff; - ComputeAmbientGains(device, slot->Gain, state->Gain); + ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index dc581ace..fdc20601 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -45,7 +45,7 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), return AL_TRUE; } -static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot) +static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot) { ALfloat Gain; ALuint i; @@ -69,8 +69,9 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device state->gains[idx] = Gain; else { - static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f }; - ComputeDirectionalGains(device, front_dir, Gain, state->gains); + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); + ComputePanningGains(device->AmbiCoeffs, device->NumChannels, coeffs, Gain, state->gains); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 221cec39..dc2e280a 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -52,7 +52,7 @@ static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state) return AL_TRUE; } -static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat bandwidth; @@ -83,7 +83,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(Device, Slot->Gain, state->Gain); + ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index f5a53c36..e2bb6407 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -81,10 +81,10 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) return AL_TRUE; } -static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot) { - ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f }; ALuint frequency = Device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gain, lrpan; state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1; @@ -103,12 +103,12 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL gain = Slot->Gain; /* First tap panning */ - pandir[0] = -lrpan; - ComputeDirectionalGains(Device, pandir, gain, state->Gain[0]); + CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, gain, state->Gain[0]); /* Second tap panning */ - pandir[0] = +lrpan; - ComputeDirectionalGains(Device, pandir, gain, state->Gain[1]); + CalcXYZCoeffs( lrpan, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, gain, state->Gain[1]); } static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 244667ab..4f7846fd 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -90,12 +90,12 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), return AL_TRUE; } -static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot) { ALfloat frequency = (ALfloat)device->Frequency; ALfloat gain, freq_mult; - ComputeAmbientGains(device, slot->Gain, state->Gain); + ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index f6191abd..5fcc8be8 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -91,11 +91,10 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D return AL_TRUE; } -static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot) { - static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f }; - static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f }; ALfloat frequency = (ALfloat)Device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat rate; ALint phase; @@ -113,8 +112,10 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency); /* Gains for left and right sides */ - ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]); - ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]); + CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[0]); + CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Flanger.Phase; rate = Slot->EffectProps.Flanger.Rate; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 32d25c76..9ef5d0dc 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -123,7 +123,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), return AL_TRUE; } -static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot) { ALfloat cw, a; @@ -148,7 +148,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device state->Filter.b2 = 0.0f; state->Filter.input_gain = a; - ComputeAmbientGains(Device, Slot->Gain, state->Gain); + ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/null.c b/Alc/effects/null.c index adc4ca81..d5f5bf11 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -33,7 +33,7 @@ static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* /* 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)) +static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot)) { } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index e1013309..f3de2116 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1065,6 +1065,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection }, LatePanAngles[4] = { DEG2RAD(45.0f), DEG2RAD(-45.0f), DEG2RAD(135.0f), DEG2RAD(-135.0f) }; + ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat length, ev, az; ALuint i; @@ -1072,7 +1073,10 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection if(!(length > FLT_EPSILON)) { for(i = 0;i < 4;i++) - ComputeAngleGains(Device, EarlyPanAngles[i], 0.0f, Gain, State->Early.PanGain[i]); + { + CalcAngleCoeffs(EarlyPanAngles[i], 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Early.PanGain[i]); + } } else { @@ -1090,7 +1094,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection float offset, naz, nev; naz = EarlyPanAngles[i] + (modff((az-EarlyPanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - ComputeAngleGains(Device, naz, nev, Gain, State->Early.PanGain[i]); + CalcAngleCoeffs(naz, nev, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Early.PanGain[i]); } } @@ -1098,7 +1103,10 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection if(!(length > FLT_EPSILON)) { for(i = 0;i < 4;i++) - ComputeAngleGains(Device, LatePanAngles[i], 0.0f, Gain, State->Late.PanGain[i]); + { + CalcAngleCoeffs(LatePanAngles[i], 0.0f, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Late.PanGain[i]); + } } else { @@ -1111,12 +1119,13 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection float offset, naz, nev; naz = LatePanAngles[i] + (modff((az-LatePanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - ComputeAngleGains(Device, naz, nev, Gain, State->Late.PanGain[i]); + CalcAngleCoeffs(naz, nev, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Late.PanGain[i]); } } } -static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) { const ALeffectProps *props = &Slot->EffectProps; ALuint frequency = Device->Frequency; diff --git a/Alc/panning.c b/Alc/panning.c index 6305bff7..e71a49f6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -33,6 +33,9 @@ #include "bool.h" +extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]); + + #define ZERO_ORDER_SCALE 0.0f #define FIRST_ORDER_SCALE 1.0f #define SECOND_ORDER_SCALE (1.0f / 1.22474f) @@ -82,35 +85,8 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; -void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALuint i; - - for(i = 0;i < device->NumChannels;i++) - { - // The W coefficients are based on a mathematical average of the - // output. The square root of the base average provides for a more - // perceptual average volume, better suited to non-directional gains. - gains[i] = sqrtf(device->AmbiCoeffs[i][0]) * ingain; - } - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALfloat dir[3] = { - sinf(angle) * cosf(elevation), - sinf(elevation), - -cosf(angle) * cosf(elevation) - }; - ComputeDirectionalGains(device, dir, ingain, gains); -} - -void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALuint i, j; /* Convert from OpenAL coords to Ambisonics. */ ALfloat x = -dir[2]; ALfloat y = -dir[0]; @@ -136,27 +112,58 @@ void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfl coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ +} + +void CalcAngleCoeffs(ALfloat angle, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + ALfloat dir[3] = { + sinf(angle) * cosf(elevation), + sinf(elevation), + -cosf(angle) * cosf(elevation) + }; + CalcDirectionCoeffs(dir, coeffs); +} + + +void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALuint i; + + for(i = 0;i < numchans;i++) + { + // The W coefficients are based on a mathematical average of the + // output. The square root of the base average provides for a more + // perceptual average volume, better suited to non-directional gains. + gains[i] = sqrtf(chancoeffs[i][0]) * ingain; + } + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + +void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALuint i, j; - for(i = 0;i < device->NumChannels;i++) + for(i = 0;i < numchans;i++) { float gain = 0.0f; for(j = 0;j < MAX_AMBI_COEFFS;j++) - gain += device->AmbiCoeffs[i][j]*coeffs[j]; + gain += chancoeffs[i][j]*coeffs[j]; gains[i] = gain * ingain; } for(;i < MAX_OUTPUT_CHANNELS;i++) gains[i] = 0.0f; } -void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeBFormatGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; - for(i = 0;i < device->NumChannels;i++) + for(i = 0;i < numchans;i++) { float gain = 0.0f; for(j = 0;j < 4;j++) - gain += device->AmbiCoeffs[i][j] * mtx[j]; + gain += chancoeffs[i][j] * mtx[j]; gains[i] = gain * ingain; } for(;i < MAX_OUTPUT_CHANNELS;i++) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 0f0d3ef8..bc768406 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -21,7 +21,7 @@ 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 update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot); void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); void (*const Delete)(void *ptr); @@ -30,7 +30,7 @@ struct ALeffectStateVtable { #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_THUNK2(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*) \ DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a309c4ab..5f5493c5 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -277,36 +277,56 @@ void aluInitMixer(void); ALvoid aluInitPanning(ALCdevice *Device); /** - * ComputeDirectionalGains + * CalcDirectionCoeffs * - * Sets channel gains based on a direction. The direction must be a 3-component - * vector no longer than 1 unit. + * Calculates ambisonic coefficients based on a direction vector. The vector + * must not be longer than 1 unit. */ -void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]); /** - * ComputeAngleGains + * CalcXYZCoeffs * - * Sets channel gains based on angle and elevation. The angle and elevation - * parameters are in radians, going right and up respectively. + * Same as CalcDirectionCoeffs except the direction is specified as separate x, + * y, and z parameters instead of an array. */ -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + ALfloat dir[3] = { x, y, z }; + CalcDirectionCoeffs(dir, coeffs); +} + +/** + * CalcAngleCoeffs + * + * Calculates ambisonic coefficients based on angle and elevation. The angle + * and elevation parameters are in radians, going right and up respectively. + */ +void CalcAngleCoeffs(ALfloat angle, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]); /** * ComputeAmbientGains * - * Sets channel gains for ambient, omni-directional sounds. + * Computes channel gains for ambient, omni-directional sounds. + */ +void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); + +/** + * ComputePanningGains + * + * Computes panning gains using the given channel decoder coefficients and the + * pre-calculated direction or angle coefficients. */ -void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeBFormatGains * - * Sets channel gains for a given (first-order) B-Format channel. The matrix is - * a 1x4 'slice' of the rotation matrix for a given channel used to orient the - * coefficients. + * Sets channel gains for a given (first-order) B-Format input channel. The + * matrix is a 1x4 'slice' of the rotation matrix for the given channel used to + * orient the soundfield. */ -void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeBFormatGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); ALvoid UpdateContextSources(ALCcontext *context); -- cgit v1.2.3 From fd387beda183c2c443ec45f7193f81cf82ede164 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Jan 2016 04:44:21 -0800 Subject: Avoid passing the device to SetChannelMap --- Alc/panning.c | 55 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index e71a49f6..dccb495e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -201,46 +201,47 @@ typedef struct ChannelMap { ChannelConfig Config; } ChannelMap; -static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count, ALfloat ambiscale, ALboolean isfuma) +static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs, + const ChannelMap *chanmap, size_t count, ALuint *outcount, + ALboolean isfuma) { size_t j, k; ALuint i; - device->AmbiScale = ambiscale; - for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++) + for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++) { - if(device->ChannelName[i] == LFE) + if(devchans[i] == LFE) { for(j = 0;j < MAX_AMBI_COEFFS;j++) - device->AmbiCoeffs[i][j] = 0.0f; + ambicoeffs[i][j] = 0.0f; continue; } for(j = 0;j < count;j++) { - if(device->ChannelName[i] == chanmap[j].ChanName) + if(devchans[i] != chanmap[j].ChanName) + continue; + + if(isfuma) { - if(isfuma) + /* Reformat FuMa -> ACN/N3D */ + for(k = 0;k < MAX_AMBI_COEFFS;++k) { - /* Reformat FuMa -> ACN/N3D */ - for(k = 0;k < MAX_AMBI_COEFFS;++k) - { - ALuint acn = FuMa2ACN[k]; - device->AmbiCoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn]; - } + ALuint acn = FuMa2ACN[k]; + ambicoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn]; } - else - { - for(k = 0;k < MAX_AMBI_COEFFS;++k) - device->AmbiCoeffs[i][k] = chanmap[j].Config[k]; - } - break; } + else + { + for(k = 0;k < MAX_AMBI_COEFFS;++k) + ambicoeffs[i][k] = chanmap[j].Config[k]; + } + break; } if(j == count) - ERR("Failed to match %s channel (%u) in config\n", GetLabelFromChannel(device->ChannelName[i]), i); + ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans[i]), i); } - device->NumChannels = i; + *outcount = i; } static bool LoadChannelSetup(ALCdevice *device) @@ -417,7 +418,9 @@ static bool LoadChannelSetup(ALCdevice *device) for(j = 0;j < MAX_AMBI_COEFFS;++j) chanmap[i].Config[j] = coeffs[j]; } - SetChannelMap(device, chanmap, count, ambiscale, isfuma); + SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, + &device->NumChannels, isfuma); + device->AmbiScale = ambiscale; return true; } @@ -492,7 +495,9 @@ ALvoid aluInitPanning(ALCdevice *device) device->ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) device->ChannelName[i] = InvalidChannel; - SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE); + SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, + &device->NumChannels, AL_TRUE); + device->AmbiScale = ambiscale; for(i = 0;i < 4;++i) { @@ -560,5 +565,7 @@ ALvoid aluInitPanning(ALCdevice *device) break; } - SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE); + SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, + &device->NumChannels, AL_TRUE); + device->AmbiScale = ambiscale; } -- cgit v1.2.3 From 2fa3ae85c9a4050eab3a4f140fb6accd0a02ce85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Jan 2016 08:16:47 -0800 Subject: Pass a pointer to the input samples array for effect processing --- Alc/ALu.c | 24 +++++++++++++++--------- Alc/effects/autowah.c | 4 ++-- Alc/effects/chorus.c | 6 +++--- Alc/effects/compressor.c | 6 +++--- Alc/effects/dedicated.c | 4 ++-- Alc/effects/distortion.c | 4 ++-- Alc/effects/echo.c | 4 ++-- Alc/effects/equalizer.c | 4 ++-- Alc/effects/flanger.c | 6 +++--- Alc/effects/modulator.c | 8 ++++---- Alc/effects/null.c | 2 +- Alc/effects/reverb.c | 6 +++--- OpenAL32/Include/alAuxEffectSlot.h | 4 ++-- 13 files changed, 44 insertions(+), 38 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 6a500833..2f1cdd85 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1473,19 +1473,25 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } /* effect slot processing */ -#define PROCESS_SLOT(iter) V((*iter)->EffectState,process)( \ - SamplesToDo, (*iter)->WetBuffer[0], device->DryBuffer, device->NumChannels \ -); - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, PROCESS_SLOT); -#undef PROCESS_SLOT + c = VECTOR_SIZE(ctx->ActiveAuxSlots); + for(i = 0;i < c;i++) + { + const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i); + ALeffectState *state = slot->EffectState; + V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer, + device->NumChannels); + } ctx = ctx->next; } - if((slot=device->DefaultSlot) != NULL) - V(slot->EffectState,process)( - SamplesToDo, slot->WetBuffer[0], device->DryBuffer, device->NumChannels - ); + if(device->DefaultSlot != NULL) + { + const ALeffectslot *slot = device->DefaultSlot; + ALeffectState *state = slot->EffectState; + V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer, + device->NumChannels); + } /* Increment the clock time. Every second's worth of samples is * converted and added to clock base so that large sample counts don't diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 2da75c56..09aecf15 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -78,7 +78,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *devi ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); } -static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; @@ -91,7 +91,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, for(it = 0;it < td;it++) { - ALfloat smp = SamplesIn[it+base]; + ALfloat smp = SamplesIn[0][it+base]; ALfloat a[3], b[3]; ALfloat alpha, w0; ALfloat amplitude; diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 1477d58b..1c9efd47 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -204,7 +204,7 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; @@ -217,10 +217,10 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co switch(state->waveform) { case CWF_Triangle: - ProcessTriangle(state, td, SamplesIn+base, temps); + ProcessTriangle(state, td, SamplesIn[0]+base, temps); break; case CWF_Sinusoid: - ProcessSinusoid(state, td, SamplesIn+base, temps); + ProcessSinusoid(state, td, SamplesIn[0]+base, temps); break; } diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 52a6324d..6c3b8375 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -62,7 +62,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); } -static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; @@ -79,7 +79,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples for(it = 0;it < td;it++) { - smp = SamplesIn[it+base]; + smp = SamplesIn[0][it+base]; amplitude = fabsf(smp); if(amplitude > gain) @@ -100,7 +100,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples for(it = 0;it < td;it++) { - smp = SamplesIn[it+base]; + smp = SamplesIn[0][it+base]; amplitude = 1.0f; if(amplitude > gain) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index fdc20601..06aad17c 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -76,7 +76,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * } } -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALfloat *gains = state->gains; ALuint i, c; @@ -87,7 +87,7 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesTo continue; for(i = 0;i < SamplesToDo;i++) - SamplesOut[c][i] += SamplesIn[i] * gains[c]; + SamplesOut[c][i] += SamplesIn[0][i] * gains[c]; } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index dc2e280a..697758f0 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -86,7 +86,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); } -static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALfloat fc = state->edge_coeff; ALuint base; @@ -108,7 +108,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples /* Fill oversample buffer using zero stuffing */ for(it = 0;it < td;it++) { - oversample_buffer[it][0] = SamplesIn[it+base]; + oversample_buffer[it][0] = SamplesIn[0][it+base]; oversample_buffer[it][1] = 0.0f; oversample_buffer[it][2] = 0.0f; oversample_buffer[it][3] = 0.0f; diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index e2bb6407..ebb6cf12 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -111,7 +111,7 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, gain, state->Gain[1]); } -static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALuint mask = state->BufferLength-1; const ALuint tap1 = state->Tap[0].delay; @@ -135,7 +135,7 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const // 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]); + smp = ALfilterState_processSingle(&state->Filter, temps[i][1]+SamplesIn[0][i+base]); state->SampleBuffer[offset&mask] = smp * state->FeedGain; offset++; } diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 4f7846fd..8ef52986 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -126,7 +126,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ); } -static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint base; ALuint it; @@ -140,7 +140,7 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo for(it = 0;it < td;it++) { - ALfloat smp = SamplesIn[base+it]; + ALfloat smp = SamplesIn[0][base+it]; for(ft = 0;ft < 4;ft++) smp = ALfilterState_processSingle(&state->filter[ft], smp); diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 5fcc8be8..21536f04 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -204,7 +204,7 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; @@ -217,10 +217,10 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, switch(state->waveform) { case FWF_Triangle: - ProcessTriangle(state, td, SamplesIn+base, temps); + ProcessTriangle(state, td, SamplesIn[0]+base, temps); break; case FWF_Sinusoid: - ProcessSinusoid(state, td, SamplesIn+base, temps); + ProcessSinusoid(state, td, SamplesIn[0]+base, temps); break; } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 9ef5d0dc..1719efeb 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -151,20 +151,20 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); } -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { switch(state->Waveform) { case SINUSOID: - ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + ProcessSin(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); break; case SAWTOOTH: - ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + ProcessSaw(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); break; case SQUARE: - ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + ProcessSquare(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); break; } } diff --git a/Alc/effects/null.c b/Alc/effects/null.c index d5f5bf11..0600703d 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -41,7 +41,7 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UN * 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), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels)) +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels)) { } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f3de2116..b822ec19 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -627,12 +627,12 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, } } -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + ALreverbState_processStandard(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); } // Given the allocated sample buffer, this function updates each delay line diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index bc768406..bbb112be 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -22,7 +22,7 @@ struct ALeffectStateVtable { ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot); - void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); + void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); void (*const Delete)(void *ptr); }; @@ -31,7 +31,7 @@ struct ALeffectStateVtable { DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ DECLARE_THUNK2(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*) \ -DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ +DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ \ -- cgit v1.2.3 From c1f87414c5452f595f78b7a52a7063a023ce2982 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Jan 2016 00:02:46 -0800 Subject: Mix to multichannel for effects This mixes to a 4-channel first-order ambisonics buffer. With ACN ordering and N3D scaling, this makes it easy to remain compatible with effects that only care about mono input since channel 0 is an unattenuated mono signal. --- Alc/ALc.c | 2 + Alc/ALu.c | 290 ++++++++++++++++++++++++++++++------- Alc/mixer.c | 2 +- Alc/panning.c | 22 ++- OpenAL32/Include/alAuxEffectSlot.h | 19 ++- OpenAL32/Include/alu.h | 10 +- OpenAL32/alAuxEffectSlot.c | 2 + 7 files changed, 283 insertions(+), 64 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d6d23eba..f69f6ecc 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3496,6 +3496,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) DELETE_OBJ(state); ERR("Failed to initialize the default effect\n"); } + else + aluInitEffectPanning(device->DefaultSlot); } { diff --git a/Alc/ALu.c b/Alc/ALu.c index 2f1cdd85..70f686f3 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -365,14 +365,18 @@ static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint ste static void UpdateWetStepping(SendParams *params, ALuint num_chans, ALuint steps) { ALfloat delta; - ALuint i; + ALuint i, j; if(steps < 2) { for(i = 0;i < num_chans;i++) { - params->Gains[i].Current = params->Gains[i].Target; - params->Gains[i].Step = 0.0f; + MixGains *gains = params->Gains[i]; + for(j = 0;j < params->OutChannels;j++) + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } } params->Counter = 0; return; @@ -381,13 +385,17 @@ static void UpdateWetStepping(SendParams *params, ALuint num_chans, ALuint steps delta = 1.0f / (ALfloat)steps; for(i = 0;i < num_chans;i++) { - ALfloat diff = params->Gains[i].Target - params->Gains[i].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - params->Gains[i].Step = diff * delta; - else + MixGains *gains = params->Gains[i]; + for(j = 0;j < params->OutChannels;j++) { - params->Gains[i].Current = params->Gains[i].Target; - params->Gains[i].Step = 0.0f; + ALfloat diff = gains[j].Target - gains[j].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + gains[j].Step = diff * delta; + else + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } } } params->Counter = steps; @@ -479,6 +487,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; + ALeffectslot *SendSlots[MAX_SENDS]; ALuint NumSends, Frequency; ALboolean Relative; const struct ChanMap *chans = NULL; @@ -507,13 +516,20 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { - ALeffectslot *Slot = ALSource->Send[i].Slot; - if(!Slot && i == 0) - Slot = Device->DefaultSlot; - if(!Slot || Slot->EffectType == AL_EFFECT_NULL) + SendSlots[i] = ALSource->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = Device->DefaultSlot; + if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = NULL; voice->Send[i].OutBuffer = NULL; + voice->Send[i].OutChannels = 0; + } else - voice->Send[i].OutBuffer = Slot->WetBuffer; + { + voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer; + voice->Send[i].OutChannels = SendSlots[i]->NumChannels; + } } /* Calculate the stepping value */ @@ -653,20 +669,37 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; - voice->IsHrtf = AL_FALSE; - for(i = 0;i < NumSends;i++) { - /* Only the first channel of B-Format buffers (W) goes to auxiliary - * sends. It also needs to be scaled by sqrt(2) to account for the - * signal being scaled by sqrt(1/2). - */ - voice->Send[i].Gains[0].Target = WetGain[i] * 1.414213562f; - for(c = 1;c < num_channels;c++) - voice->Send[i].Gains[c].Target = 0.0f; + if(!SendSlots[i]) + { + for(c = 0;c < num_channels;c++) + { + MixGains *gains = voice->Send[i].Gains[c]; + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + } + else + { + for(c = 0;c < num_channels;c++) + { + const ALeffectslot *Slot = SendSlots[i]; + MixGains *gains = voice->Send[i].Gains[c]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALuint j; + + ComputeBFormatGains(Slot->AmbiCoeffs, Slot->NumChannels, + matrix.m[c], WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + } UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); voice->Send[i].Moving = AL_TRUE; } + + voice->IsHrtf = AL_FALSE; } else { @@ -683,7 +716,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A for(c = 0;c < num_channels;c++) { MixGains *gains = voice->Direct.Gains[c]; - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) gains[j].Target = 0.0f; @@ -703,8 +735,44 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) gains[idx].Target = DryGain; } + + /* Auxiliary sends still use normal panning since they mix to B-Format, which can't + * channel-match. */ + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[c]; + if(!SendSlots[i]) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + else + { + const ALeffectslot *Slot = SendSlots[i]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALuint j; + + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, + coeffs, WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + } + } + UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; + for(i = 0;i < NumSends;i++) + { + UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } voice->IsHrtf = AL_FALSE; } @@ -742,6 +810,40 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.Counter = 0; voice->Direct.Moving = AL_TRUE; + /* Normal panning for auxiliary sends. */ + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[c]; + if(!SendSlots[i]) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + else + { + const ALeffectslot *Slot = SendSlots[i]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALuint j; + + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, + coeffs, WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + } + } + for(i = 0;i < NumSends;i++) + { + UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } + voice->IsHrtf = AL_TRUE; } else @@ -769,19 +871,38 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; + + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[c]; + ALuint j; + + if(!SendSlots[i]) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + else + { + const ALeffectslot *Slot = SendSlots[i]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, + coeffs, WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + } } + UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; + for(i = 0;i < NumSends;i++) + { + UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } voice->IsHrtf = AL_FALSE; } - for(i = 0;i < NumSends;i++) - { - for(c = 0;c < num_channels;c++) - voice->Send[i].Gains[c].Target = WetGain[i]; - UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; - } } { @@ -838,6 +959,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat AirAbsorptionFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; ALbufferlistitem *BufferListItem; + ALeffectslot *SendSlots[MAX_SENDS]; ALfloat Attenuation; ALfloat RoomAttenuation[MAX_SENDS]; ALfloat MetersPerUnit; @@ -899,26 +1021,26 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { - ALeffectslot *Slot = ALSource->Send[i].Slot; + SendSlots[i] = ALSource->Send[i].Slot; - if(!Slot && i == 0) - Slot = Device->DefaultSlot; - if(!Slot || Slot->EffectType == AL_EFFECT_NULL) + if(!SendSlots[i] && i == 0) + SendSlots[i] = Device->DefaultSlot; + if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL) { - Slot = NULL; + SendSlots[i] = NULL; RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = 1.0f; } - else if(Slot->AuxSendAuto) + else if(SendSlots[i]->AuxSendAuto) { RoomRolloff[i] = RoomRolloffBase; - if(IsReverbEffect(Slot->EffectType)) + if(IsReverbEffect(SendSlots[i]->EffectType)) { - RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor; - DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime * + RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor; + DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime * SPEEDOFSOUNDMETRESPERSEC; - RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF; + RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF; } else { @@ -935,10 +1057,16 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte RoomAirAbsorption[i] = AIRABSORBGAINHF; } - if(!Slot || Slot->EffectType == AL_EFFECT_NULL) + if(!SendSlots[i]) + { voice->Send[i].OutBuffer = NULL; + voice->Send[i].OutChannels = 0; + } else - voice->Send[i].OutBuffer = Slot->WetBuffer; + { + voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer; + voice->Send[i].OutChannels = SendSlots[i]->NumChannels; + } } /* Transform source to listener space (convert to head relative) */ @@ -1159,6 +1287,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; ALfloat dirfact = 1.0f; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; @@ -1217,6 +1347,34 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte voice->Direct.LastDir = dir; } + dir.v[0] *= dirfact; + dir.v[1] *= dirfact; + dir.v[2] *= dirfact; + CalcDirectionCoeffs(dir.v, coeffs); + + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[0]; + ALuint j; + + if(!SendSlots[i]) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + else + { + const ALeffectslot *Slot = SendSlots[i]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, + coeffs, WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + + UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } + voice->IsHrtf = AL_TRUE; } else @@ -1255,14 +1413,31 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[0]; + ALuint j; + + if(!SendSlots[i]) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } + else + { + const ALeffectslot *Slot = SendSlots[i]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, + coeffs, WetGain[i], Target); + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = Target[j]; + } + + UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } + voice->IsHrtf = AL_FALSE; } - for(i = 0;i < NumSends;i++) - { - voice->Send[i].Gains[0].Target = WetGain[i]; - UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; - } { ALfloat hfscale = ALSource->Direct.HFReference / Frequency; @@ -1438,7 +1613,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE)) V(slot->EffectState,update)(device, slot); - memset(slot->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)); + for(i = 0;i < slot->NumChannels;i++) + memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); } ctx = ATOMIC_LOAD(&device->ContextList); @@ -1447,17 +1623,21 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(!ctx->DeferUpdates) { UpdateContextSources(ctx); -#define UPDATE_SLOT(iter) do { \ - if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ - V((*iter)->EffectState,update)(device, *iter); \ - memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)); \ +#define UPDATE_SLOT(iter) do { \ + if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ + V((*iter)->EffectState,update)(device, *iter); \ + for(i = 0;i < (*iter)->NumChannels;i++) \ + memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ } while(0) VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); #undef UPDATE_SLOT } else { -#define CLEAR_WET_BUFFER(iter) memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)) +#define CLEAR_WET_BUFFER(iter) do { \ + for(i = 0;i < (*iter)->NumChannels;i++) \ + memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ +} while(0) VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER); #undef CLEAR_WET_BUFFER } diff --git a/Alc/mixer.c b/Alc/mixer.c index 712075f1..ddcf6f6b 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -570,7 +570,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Device->FilteredData, ResampledData, DstBufferSize, parms->Filters[chan].ActiveType ); - MixSamples(samples, 1, parms->OutBuffer, &parms->Gains[chan], + MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan], parms->Counter, OutPos, DstBufferSize); } } diff --git a/Alc/panning.c b/Alc/panning.c index dccb495e..c4eb3f82 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -27,8 +27,7 @@ #include #include "alMain.h" -#include "AL/al.h" -#include "AL/alc.h" +#include "alAuxEffectSlot.h" #include "alu.h" #include "bool.h" @@ -569,3 +568,22 @@ ALvoid aluInitPanning(ALCdevice *device) &device->NumChannels, AL_TRUE); device->AmbiScale = ambiscale; } + +void aluInitEffectPanning(ALeffectslot *slot) +{ + static const ChannelMap FirstOrderN3D[4] = { + { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } }, + }; + static const enum Channel AmbiChannels[MAX_OUTPUT_CHANNELS] = { + BFormatW, BFormatY, BFormatZ, BFormatX, InvalidChannel + }; + + memset(slot->AmbiCoeffs, 0, sizeof(slot->AmbiCoeffs)); + slot->NumChannels = 0; + + SetChannelMap(AmbiChannels, slot->AmbiCoeffs, FirstOrderN3D, COUNTOF(FirstOrderN3D), + &slot->NumChannels, AL_FALSE); +} diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index bbb112be..3f677fd1 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -64,6 +64,9 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = } +#define MAX_EFFECT_CHANNELS (4) + + typedef struct ALeffectslot { ALenum EffectType; ALeffectProps EffectProps; @@ -74,12 +77,24 @@ typedef struct ALeffectslot { ATOMIC(ALenum) NeedsUpdate; ALeffectState *EffectState; - alignas(16) ALfloat WetBuffer[1][BUFFERSIZE]; - RefCount ref; /* Self ID */ ALuint id; + + ALuint NumChannels; + ChannelConfig AmbiCoeffs[MAX_EFFECT_CHANNELS]; + /* Wet buffer configuration is ACN channel order with N3D scaling: + * * Channel 0 is the unattenuated mono signal. + * * Channel 1 is OpenAL -X + * * Channel 2 is OpenAL Y + * * Channel 3 is OpenAL -Z + * Consequently, effects that only want to work with mono input can use + * channel 0 by itself. Effects that want multichannel can process the + * ambisonics signal and create a B-Format pan (ComputeBFormatGains) for + * the device output. + */ + alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALeffectslot; inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 5f5493c5..63a03adc 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -13,6 +13,7 @@ #include "alMain.h" #include "alBuffer.h" #include "alFilter.h" +#include "alAuxEffectSlot.h" #include "hrtf.h" #include "align.h" @@ -34,6 +35,7 @@ extern "C" { struct ALsource; struct ALvoice; +struct ALeffectslot; /* The number of distinct scale and phase intervals within the filter table. */ @@ -164,6 +166,7 @@ typedef struct DirectParams { typedef struct SendParams { ALfloat (*OutBuffer)[BUFFERSIZE]; + ALuint OutChannels; ALboolean Moving; ALuint Counter; @@ -173,10 +176,7 @@ typedef struct SendParams { ALfilterState LowPass; ALfilterState HighPass; } Filters[MAX_INPUT_CHANNELS]; - - /* Gain control, which applies to each input channel to a single (mono) - * output buffer. */ - MixGains Gains[MAX_INPUT_CHANNELS]; + MixGains Gains[MAX_INPUT_CHANNELS][MAX_EFFECT_CHANNELS]; } SendParams; @@ -276,6 +276,8 @@ void aluInitMixer(void); ALvoid aluInitPanning(ALCdevice *Device); +void aluInitEffectPanning(struct ALeffectslot *slot); + /** * CalcDirectionCoeffs * diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index c1314301..b0dba25d 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -90,6 +90,8 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo SET_ERROR_AND_GOTO(context, err, done); } + aluInitEffectPanning(slot); + VECTOR_PUSH_BACK(slotvec, slot); effectslots[cur] = slot->id; -- cgit v1.2.3 From 210b4c1fcdfff2ada91456dcdb494331d58dd7cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Jan 2016 02:49:40 -0800 Subject: Make the compressor effect multichannel --- Alc/effects/compressor.c | 83 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 6c3b8375..e3c26bd9 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -31,7 +31,7 @@ typedef struct ALcompressorState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; + ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; /* Effect parameters */ ALboolean Enabled; @@ -57,73 +57,106 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot) { + aluMatrixf matrix; + ALfloat scale; + ALuint i; + state->Enabled = slot->EffectProps.Compressor.OnOff; - ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); + scale = device->AmbiScale; + aluMatrixfSet(&matrix, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, scale, 0.0f, 0.0f, + 0.0f, 0.0f, scale, 0.0f, + 0.0f, 0.0f, 0.0f, scale + ); + for(i = 0;i < 4;i++) + ComputeBFormatGains(device->AmbiCoeffs, device->NumChannels, + matrix.m[i], slot->Gain, state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - ALuint it, kt; + ALuint i, j, k; ALuint base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[256]; - ALuint td = minu(256, SamplesToDo-base); + ALfloat temps[64][4]; + ALuint td = minu(64, SamplesToDo-base); + + /* Load samples into the temp buffer first. */ + for(j = 0;j < 4;j++) + { + for(i = 0;i < td;i++) + temps[i][j] = SamplesIn[j][i+base]; + } if(state->Enabled) { - ALfloat output, smp, amplitude; ALfloat gain = state->GainCtrl; + ALfloat output, amplitude; - for(it = 0;it < td;it++) + for(i = 0;i < td;i++) { - smp = SamplesIn[0][it+base]; - - amplitude = fabsf(smp); + /* Roughly calculate the maximum amplitude from the 4-channel + * signal, and attack or release the gain control to reach it. + */ + amplitude = fabsf(temps[i][0]); + amplitude = maxf(amplitude + fabsf(temps[i][1]), + maxf(amplitude + fabsf(temps[i][2]), + amplitude + fabsf(temps[i][3]))); 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; + /* Apply the inverse of the gain control to normalize/compress + * the volume. */ + output = 1.0f / clampf(gain, 0.5f, 2.0f); + for(j = 0;j < 4;j++) + temps[i][j] *= output; } state->GainCtrl = gain; } else { - ALfloat output, smp, amplitude; ALfloat gain = state->GainCtrl; + ALfloat output, amplitude; - for(it = 0;it < td;it++) + for(i = 0;i < td;i++) { - smp = SamplesIn[0][it+base]; - + /* Same as above, except the amplitude is forced to 1. This + * helps ensure smooth gain changes when the compressor is + * turned on and off. + */ 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; + output = 1.0f / clampf(gain, 0.5f, 2.0f); + for(j = 0;j < 4;j++) + temps[i][j] *= output; } state->GainCtrl = gain; } - - for(kt = 0;kt < NumChannels;kt++) + /* Now mix to the output. */ + for(j = 0;j < 4;j++) { - ALfloat gain = state->Gain[kt]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; + for(k = 0;k < NumChannels;k++) + { + ALfloat gain = state->Gain[j][k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * temps[it]; + for(i = 0;i < td;i++) + SamplesOut[k][base+i] += gain * temps[i][j]; + } } base += td; -- cgit v1.2.3 From 3ac786c6af35952b056d5ca44afa6fb03acb1e7c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Jan 2016 07:26:19 -0800 Subject: Convert the equalizer effect to multichannel --- Alc/effects/equalizer.c | 123 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 33 deletions(-) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 8ef52986..0a1ff1db 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -71,14 +71,20 @@ * filter coefficients" by Robert Bristow-Johnson * * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ + +/* The maximum number of sample frames per update. */ +#define MAX_UPDATE_SAMPLES 256 + typedef struct ALequalizerState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; + ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; /* Effect parameters */ - ALfilterState filter[4]; + ALfilterState filter[4][MAX_EFFECT_CHANNELS]; + + ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES]; } ALequalizerState; static ALvoid ALequalizerState_Destruct(ALequalizerState *UNUSED(state)) @@ -94,8 +100,19 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { ALfloat frequency = (ALfloat)device->Frequency; ALfloat gain, freq_mult; - - ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); + aluMatrixf matrix; + ALuint i; + + gain = device->AmbiScale; + aluMatrixfSet(&matrix, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, gain, 0.0f, 0.0f, + 0.0f, 0.0f, gain, 0.0f, + 0.0f, 0.0f, 0.0f, gain + ); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputeBFormatGains(device->AmbiCoeffs, device->NumChannels, + matrix.m[i], slot->Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint @@ -103,59 +120,96 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * */ gain = sqrtf(slot->EffectProps.Equalizer.LowGain); freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency; - ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf, + ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); + /* Copy the filter coefficients for the other input channels. */ + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + { + state->filter[0][i].a1 = state->filter[0][0].a1; + state->filter[0][i].a2 = state->filter[0][0].a2; + state->filter[0][i].b1 = state->filter[0][0].b1; + state->filter[0][i].b2 = state->filter[0][0].b2; + state->filter[0][i].input_gain = state->filter[0][0].input_gain; + state->filter[0][i].process = state->filter[0][0].process; + } gain = slot->EffectProps.Equalizer.Mid1Gain; freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency; - ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking, + ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width) ); + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + { + state->filter[1][i].a1 = state->filter[1][0].a1; + state->filter[1][i].a2 = state->filter[1][0].a2; + state->filter[1][i].b1 = state->filter[1][0].b1; + state->filter[1][i].b2 = state->filter[1][0].b2; + state->filter[1][i].input_gain = state->filter[1][0].input_gain; + state->filter[1][i].process = state->filter[1][0].process; + } gain = slot->EffectProps.Equalizer.Mid2Gain; freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency; - ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking, + ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width) ); + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + { + state->filter[2][i].a1 = state->filter[2][0].a1; + state->filter[2][i].a2 = state->filter[2][0].a2; + state->filter[2][i].b1 = state->filter[2][0].b1; + state->filter[2][i].b2 = state->filter[2][0].b2; + state->filter[2][i].input_gain = state->filter[2][0].input_gain; + state->filter[2][i].process = state->filter[2][0].process; + } gain = sqrtf(slot->EffectProps.Equalizer.HighGain); freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency; - ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf, + ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + { + state->filter[3][i].a1 = state->filter[3][0].a1; + state->filter[3][i].a2 = state->filter[3][0].a2; + state->filter[3][i].b1 = state->filter[3][0].b1; + state->filter[3][i].b2 = state->filter[3][0].b2; + state->filter[3][i].input_gain = state->filter[3][0].input_gain; + state->filter[3][i].process = state->filter[3][0].process; + } } static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { + ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer; + ALuint it, kt, ft; ALuint base; - ALuint it; - ALuint kt; - ALuint ft; for(base = 0;base < SamplesToDo;) { - ALfloat temps[256]; - ALuint td = minu(256, SamplesToDo-base); - - for(it = 0;it < td;it++) + ALuint td = minu(MAX_UPDATE_SAMPLES, SamplesToDo-base); + + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td); + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_process(&state->filter[1][ft], Samples[1][ft], Samples[0][ft], td); + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_process(&state->filter[2][ft], Samples[2][ft], Samples[1][ft], td); + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_process(&state->filter[3][ft], Samples[3][ft], Samples[2][ft], td); + + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) { - ALfloat smp = SamplesIn[0][base+it]; - - for(ft = 0;ft < 4;ft++) - smp = ALfilterState_processSingle(&state->filter[ft], smp); - - temps[it] = smp; - } - - for(kt = 0;kt < NumChannels;kt++) - { - ALfloat gain = state->Gain[kt]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * temps[it]; + for(kt = 0;kt < NumChannels;kt++) + { + ALfloat gain = state->Gain[ft][kt]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(it = 0;it < td;it++) + SamplesOut[kt][base+it] += gain * Samples[3][ft][it]; + } } base += td; @@ -174,7 +228,7 @@ typedef struct ALequalizerStateFactory { ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory)) { ALequalizerState *state; - int it; + int it, ft; state = ALequalizerState_New(sizeof(*state)); if(!state) return NULL; @@ -183,7 +237,10 @@ ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(fa /* 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]); + { + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_clear(&state->filter[it][ft]); + } return STATIC_CAST(ALeffectState, state); } -- cgit v1.2.3 From a046a951e9d36813a833169e6ce43f0bdef9195a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Jan 2016 23:28:38 -0800 Subject: Use separate modulator functions only for the waveform --- Alc/effects/modulator.c | 98 +++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 1719efeb..213f60c3 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -33,11 +33,7 @@ typedef struct ALmodulatorState { DERIVE_FROM_TYPE(ALeffectState); - enum { - SINUSOID, - SAWTOOTH, - SQUARE - } Waveform; + void (*Process)(ALfloat*, const ALfloat*, ALuint, const ALuint, ALuint); ALuint index; ALuint step; @@ -67,44 +63,16 @@ static inline ALfloat Square(ALuint index) } #define DECL_TEMPLATE(func) \ -static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ - const ALfloat *restrict SamplesIn, \ - ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) \ +static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\ + ALuint index, const ALuint step, ALuint todo) \ { \ - const ALuint step = state->step; \ - ALuint index = state->index; \ - ALuint base; \ - \ - for(base = 0;base < SamplesToDo;) \ + ALuint i; \ + for(i = 0;i < todo;i++) \ { \ - ALfloat temps[256]; \ - ALuint td = minu(256, SamplesToDo-base); \ - 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 < NumChannels;k++) \ - { \ - ALfloat gain = state->Gain[k]; \ - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) \ - continue; \ - \ - for(i = 0;i < td;i++) \ - SamplesOut[k][base+i] += gain * temps[i]; \ - } \ - \ - base += td; \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + dst[i] = src[i] * func(index); \ } \ - state->index = index; \ } DECL_TEMPLATE(Sin) @@ -128,11 +96,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * ALfloat cw, a; if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->Waveform = SINUSOID; + state->Process = ModulateSin; 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->Process = ModulateSaw; + else /*if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ + state->Process = ModulateSquare; state->step = fastf2u(Slot->EffectProps.Modulator.Frequency*WAVEFORM_FRACONE / Device->Frequency); @@ -147,26 +115,44 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter.b1 = -a; state->Filter.b2 = 0.0f; state->Filter.input_gain = a; + state->Filter.process = ALfilterState_processC; ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - switch(state->Waveform) - { - case SINUSOID: - ProcessSin(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); - break; - - case SAWTOOTH: - ProcessSaw(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); - break; + const ALuint step = state->step; + ALuint index = state->index; + ALuint base; - case SQUARE: - ProcessSquare(state, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); - break; + for(base = 0;base < SamplesToDo;) + { + ALfloat temps[2][128]; + ALuint td = minu(128, SamplesToDo-base); + ALuint i, k; + + ALfilterState_process(&state->Filter, temps[0], &SamplesIn[0][base], td); + state->Process(temps[1], temps[0], index, step, td); + + for(k = 0;k < NumChannels;k++) + { + ALfloat gain = state->Gain[k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < td;i++) + SamplesOut[k][base+i] += gain * temps[1][i]; + } + + for(i = 0;i < td;i++) + { + index += step; + index &= WAVEFORM_FRACMASK; + } + base += td; } + state->index = index; } DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) -- cgit v1.2.3 From 7111322526f1dea7df987a843b8a42f4e746ccc4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Jan 2016 23:44:43 -0800 Subject: Make the modulator effect multichannel --- Alc/effects/modulator.c | 63 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 213f60c3..bb74d3ec 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -38,9 +38,9 @@ typedef struct ALmodulatorState { ALuint index; ALuint step; - ALfloat Gain[MAX_OUTPUT_CHANNELS]; + ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; - ALfilterState Filter; + ALfilterState Filter[MAX_EFFECT_CHANNELS]; } ALmodulatorState; #define WAVEFORM_FRACBITS 24 @@ -93,7 +93,9 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot) { - ALfloat cw, a; + ALfloat scale, cw, a; + aluMatrixf matrix; + ALuint i; if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Process = ModulateSin; @@ -110,14 +112,26 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); - state->Filter.a1 = -a; - state->Filter.a2 = 0.0f; - state->Filter.b1 = -a; - state->Filter.b2 = 0.0f; - state->Filter.input_gain = a; - state->Filter.process = ALfilterState_processC; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + state->Filter[i].a1 = -a; + state->Filter[i].a2 = 0.0f; + state->Filter[i].b1 = -a; + state->Filter[i].b2 = 0.0f; + state->Filter[i].input_gain = a; + state->Filter[i].process = ALfilterState_processC; + } - ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); + scale = Device->AmbiScale; + aluMatrixfSet(&matrix, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, scale, 0.0f, 0.0f, + 0.0f, 0.0f, scale, 0.0f, + 0.0f, 0.0f, 0.0f, scale + ); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputeBFormatGains(Device->AmbiCoeffs, Device->NumChannels, + matrix.m[i], Slot->Gain, state->Gain[i]); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) @@ -130,19 +144,22 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesTo { ALfloat temps[2][128]; ALuint td = minu(128, SamplesToDo-base); - ALuint i, k; + ALuint i, j, k; - ALfilterState_process(&state->Filter, temps[0], &SamplesIn[0][base], td); - state->Process(temps[1], temps[0], index, step, td); - - for(k = 0;k < NumChannels;k++) + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) { - ALfloat gain = state->Gain[k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < td;i++) - SamplesOut[k][base+i] += gain * temps[1][i]; + ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td); + state->Process(temps[1], temps[0], index, step, td); + + for(k = 0;k < NumChannels;k++) + { + ALfloat gain = state->Gain[j][k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < td;i++) + SamplesOut[k][base+i] += gain * temps[1][i]; + } } for(i = 0;i < td;i++) @@ -167,6 +184,7 @@ typedef struct ALmodulatorStateFactory { static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory)) { ALmodulatorState *state; + ALuint i; state = ALmodulatorState_New(sizeof(*state)); if(!state) return NULL; @@ -175,7 +193,8 @@ static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UN state->index = 0; state->step = 1; - ALfilterState_clear(&state->Filter); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ALfilterState_clear(&state->Filter[i]); return STATIC_CAST(ALeffectState, state); } -- cgit v1.2.3 From 729f213c09f7046554ba4aa05473c33edb3ee406 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jan 2016 03:33:02 -0800 Subject: Fix scaling for effect sends of B-Format sources --- Alc/ALu.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 70f686f3..d152b343 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -648,7 +648,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A aluNormalize(U); /* Build a rotate + conversion matrix (B-Format -> N3D), and include - * scaling for first-order content. */ + * scaling for first-order content on second- or third-order output. + */ scale = Device->AmbiScale * 1.732050808f; aluMatrixfSet(&matrix, 1.414213562f, 0.0f, 0.0f, 0.0f, @@ -669,6 +670,14 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); voice->Direct.Moving = AL_TRUE; + /* Rebuild the matrix, without the second- or third-order output + * scaling (effects take first-order content, and will do the scaling + * themselves when mixing to the output). + */ + scale = 1.732050808f; + aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale); + aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale); + aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale); for(i = 0;i < NumSends;i++) { if(!SendSlots[i]) -- cgit v1.2.3 From 063ef9c2fccdf8ce4b0148a1a06de4b9234d86b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jan 2016 07:13:07 -0800 Subject: Properly silence the LFE input channel gain on the source sends --- Alc/ALu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Alc/ALu.c b/Alc/ALu.c index d152b343..8108e7c2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -872,6 +872,14 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A gains[i].Target = 0.0f; if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) gains[idx].Target = DryGain; + + for(i = 0;i < NumSends;i++) + { + MixGains *gains = voice->Send[i].Gains[c]; + ALuint j; + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + gains[j].Target = 0.0f; + } continue; } -- cgit v1.2.3 From d69dd6dc7aa50fa3bd77338065b381b57be05acd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jan 2016 00:42:58 -0800 Subject: Make the source's buffer queue a singly-linked list --- OpenAL32/Include/alSource.h | 1 - OpenAL32/alSource.c | 57 +++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 13596161..253cd05f 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -18,7 +18,6 @@ struct ALsource; typedef struct ALbufferlistitem { struct ALbuffer *buffer; struct ALbufferlistitem *volatile next; - struct ALbufferlistitem *volatile prev; } ALbufferlistitem; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 0d454882..d31a0377 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -631,7 +631,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p newlist = malloc(sizeof(ALbufferlistitem)); newlist->buffer = buffer; newlist->next = NULL; - newlist->prev = NULL; IncrementRef(&buffer->ref); /* Source is now Static */ @@ -2334,19 +2333,15 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(!BufferListStart) { 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; } + BufferList->buffer = buffer; + BufferList->next = NULL; if(!buffer) continue; /* Hold a read lock on each buffer being queued while checking all @@ -2372,26 +2367,27 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu buffer_error: /* A buffer failed (invalid ID or format), so unlock and release * each buffer we had. */ - while(BufferList != NULL) + while(BufferListStart) { - ALbufferlistitem *prev = BufferList->prev; - if((buffer=BufferList->buffer) != NULL) + ALbufferlistitem *next = BufferListStart->next; + if((buffer=BufferListStart->buffer) != NULL) { DecrementRef(&buffer->ref); ReadUnlock(&buffer->lock); } - free(BufferList); - BufferList = prev; + free(BufferListStart); + BufferListStart = next; } goto done; } } /* All buffers good, unlock them now. */ + BufferList = BufferListStart; while(BufferList != NULL) { ALbuffer *buffer = BufferList->buffer; if(buffer) ReadUnlock(&buffer->lock); - BufferList = BufferList->prev; + BufferList = BufferList->next; } /* Source is now streaming */ @@ -2403,10 +2399,11 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu /* Queue head is not NULL, append to the end of the queue */ while(BufferList->next != NULL) BufferList = BufferList->next; - - BufferListStart->prev = BufferList; BufferList->next = BufferListStart; } + /* If the current buffer was at the end (NULL), put it at the start of the newly queued + * buffers. + */ BufferList = NULL; ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart); WriteUnlock(&source->queue_lock); @@ -2419,10 +2416,10 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint { ALCcontext *context; ALsource *source; - ALbufferlistitem *NewHead; ALbufferlistitem *OldHead; + ALbufferlistitem *OldTail; ALbufferlistitem *Current; - ALsizei i; + ALsizei i = 0; if(nb == 0) return; @@ -2438,13 +2435,16 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint WriteLock(&source->queue_lock); /* Find the new buffer queue head */ - NewHead = ATOMIC_LOAD(&source->queue); + OldTail = ATOMIC_LOAD(&source->queue); Current = ATOMIC_LOAD(&source->current_buffer); - for(i = 0;i < nb && NewHead;i++) + if(OldTail != Current) { - if(NewHead == Current) - break; - NewHead = NewHead->next; + for(i = 1;i < nb;i++) + { + ALbufferlistitem *next = OldTail->next; + if(!next || next == Current) break; + OldTail = next; + } } if(source->Looping || source->SourceType != AL_STREAMING || i != nb) { @@ -2454,18 +2454,15 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Swap it, and cut the new head from the old. */ - OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead); - if(NewHead) + OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next); + if(OldTail->next) { ALCdevice *device = context->Device; - ALbufferlistitem *OldTail = NewHead->prev; uint count; - /* Cut the new head's link back to the old body. The mixer is robust - * enough to handle the link back going away. Once the active mix (if - * any) is complete, it's safe to finish cutting the old tail from the - * new head. */ - NewHead->prev = NULL; + /* Once the active mix (if any) is done, it's safe to cut the old tail + * from the new head. + */ if(((count=ReadRef(&device->MixCount))&1) != 0) { while(count == ReadRef(&device->MixCount)) -- cgit v1.2.3 From 7f908d90af9ed4b2f7ff415c412a080b22cac125 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jan 2016 09:00:23 -0800 Subject: Rename ComputeBFormatGains to ComputeFirstOrderGains --- Alc/ALu.c | 6 +++--- Alc/effects/compressor.c | 4 ++-- Alc/effects/equalizer.c | 4 ++-- Alc/effects/modulator.c | 4 ++-- Alc/panning.c | 2 +- OpenAL32/Include/alu.h | 10 +++++----- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8108e7c2..e0c96175 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -663,7 +663,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A MixGains *gains = voice->Direct.Gains[c]; ALfloat Target[MAX_OUTPUT_CHANNELS]; - ComputeBFormatGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, Target); + ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, Target); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) gains[i].Target = Target[i]; } @@ -698,8 +698,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALfloat Target[MAX_OUTPUT_CHANNELS]; ALuint j; - ComputeBFormatGains(Slot->AmbiCoeffs, Slot->NumChannels, - matrix.m[c], WetGain[i], Target); + ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, + matrix.m[c], WetGain[i], Target); for(j = 0;j < MAX_EFFECT_CHANNELS;j++) gains[j].Target = Target[j]; } diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index e3c26bd9..e835a5aa 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -71,8 +71,8 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice 0.0f, 0.0f, 0.0f, scale ); for(i = 0;i < 4;i++) - ComputeBFormatGains(device->AmbiCoeffs, device->NumChannels, - matrix.m[i], slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(device->AmbiCoeffs, device->NumChannels, + matrix.m[i], slot->Gain, state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 0a1ff1db..051e8c7f 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -111,8 +111,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * 0.0f, 0.0f, 0.0f, gain ); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeBFormatGains(device->AmbiCoeffs, device->NumChannels, - matrix.m[i], slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(device->AmbiCoeffs, device->NumChannels, + matrix.m[i], slot->Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index bb74d3ec..cd6ccb22 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -130,8 +130,8 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * 0.0f, 0.0f, 0.0f, scale ); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeBFormatGains(Device->AmbiCoeffs, Device->NumChannels, - matrix.m[i], Slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, + matrix.m[i], Slot->Gain, state->Gain[i]); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/panning.c b/Alc/panning.c index c4eb3f82..8464efd6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -154,7 +154,7 @@ void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const gains[i] = 0.0f; } -void ComputeBFormatGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 63a03adc..eb2ea534 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -322,13 +322,13 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** - * ComputeBFormatGains + * ComputeFirstOrderGains * - * Sets channel gains for a given (first-order) B-Format input channel. The - * matrix is a 1x4 'slice' of the rotation matrix for the given channel used to - * orient the soundfield. + * Sets channel gains for a first-order ambisonics input channel. The matrix is + * a 1x4 'slice' of a transform matrix for the input channel, used to scale and + * orient the sound samples. */ -void ComputeBFormatGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); ALvoid UpdateContextSources(ALCcontext *context); -- cgit v1.2.3 From 46cae36ef9e22bb715d13c756a88f6ff62c487a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jan 2016 09:39:07 -0800 Subject: Fix an out of date comment --- Alc/effects/reverb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index b822ec19..2b4ac923 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1049,10 +1049,8 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, State->Echo.Coeff, cw); - /* Calculate the echo mixing coefficients. The first is applied to the - * echo itself. The second is used to attenuate the late reverb when - * echo depth is high and diffusion is low, so the echo is slightly - * stronger than the decorrelated echos in the reverb tail. + /* Calculate the echo mixing coefficient. This is applied to the output mix + * only, not the feedback. */ State->Echo.MixCoeff = reverbGain * lateGain * echoDepth; } -- cgit v1.2.3 From b4a9b40d68323a9c67cc4d182189b3be3e74117e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Feb 2016 01:45:16 -0800 Subject: Apply the main reverb gain with the panning --- Alc/effects/reverb.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 2b4ac923..fab049f6 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -925,13 +925,13 @@ 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, ALreverbState *State) +static ALvoid UpdateEarlyLines(ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State) { ALuint index; // Calculate the early reflections gain (from the master effect gain, and // reflections gain parameters) with a constant attenuation of 0.5. - State->Early.Gain = 0.5f * reverbGain * earlyGain; + State->Early.Gain = 0.5f * earlyGain; // Calculate the gain (coefficient) for each early delay line using the // late delay time. This expands the early reflections to the start of @@ -963,7 +963,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat } // 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 echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { ALfloat length; ALuint index; @@ -976,8 +976,7 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix * echo is slightly stronger than the decorrelated echos in the reverb * tail. */ - State->Late.Gain = reverbGain * lateGain * xMix * - (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); + State->Late.Gain = lateGain * xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -1027,7 +1026,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, ALreverbState *State) +static ALvoid UpdateEchoLine(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); @@ -1052,7 +1051,7 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT /* Calculate the echo mixing coefficient. This is applied to the output mix * only, not the feedback. */ - State->Echo.MixCoeff = reverbGain * lateGain * echoDepth; + State->Echo.MixCoeff = lateGain * echoDepth; } // Update the early and late 3D panning gains. @@ -1128,7 +1127,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device const ALeffectProps *props = &Slot->EffectProps; ALuint frequency = Device->Frequency; ALfloat lfscale, hfscale, hfRatio; - ALfloat gainlf, gainhf; + ALfloat gain, gainlf, gainhf; ALfloat cw, x, y; if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) @@ -1155,7 +1154,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device frequency, State); // Update the early lines. - UpdateEarlyLines(props->Reverb.Gain, props->Reverb.ReflectionsGain, + UpdateEarlyLines(props->Reverb.ReflectionsGain, props->Reverb.LateReverbDelay, State); // Update the decorrelator. @@ -1175,21 +1174,21 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device cw = cosf(F_TAU * hfscale); // Update the late lines. - UpdateLateLines(props->Reverb.Gain, props->Reverb.LateReverbGain, x, + UpdateLateLines(props->Reverb.LateReverbGain, x, props->Reverb.Density, props->Reverb.DecayTime, props->Reverb.Diffusion, props->Reverb.EchoDepth, hfRatio, cw, frequency, State); // Update the echo line. - UpdateEchoLine(props->Reverb.Gain, props->Reverb.LateReverbGain, + UpdateEchoLine(props->Reverb.LateReverbGain, props->Reverb.EchoTime, props->Reverb.DecayTime, props->Reverb.Diffusion, props->Reverb.EchoDepth, hfRatio, cw, frequency, State); + gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, - Slot->Gain * ReverbBoost, State); + props->Reverb.LateReverbPan, gain, State); } -- cgit v1.2.3 From d315ca4139c7bfc0ed9b0b89c59bdd3af3708da8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Feb 2016 22:24:40 -0800 Subject: Try to map reverb outputs directly to output channels HRTF and B-Format output still need to use virtual panning directions, but the reverb works better when it outputs directly to an output channel. Ambient and directional panning is used to properly mask and attenuate each output channel. Note that currently the "direct panning" output is quieter than it should be. Work is underway to attenuate the early reflections and late reverb better. --- Alc/effects/reverb.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index fab049f6..bc12bc3b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1055,6 +1055,77 @@ static ALvoid UpdateEchoLine(ALfloat lateGain, ALfloat echoTime, ALfloat decayTi } // Update the early and late 3D panning gains. +static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +{ + ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; + ALfloat DirGains[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat length; + ALuint i; + + ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain, AmbientGains); + + memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Early.PanGain[i&3][i] = AmbientGains[i]; + } + } + else + { + ALfloat pan[3] = { + ReflectionsPan[0] / length, + ReflectionsPan[1] / length, + -ReflectionsPan[2] / length, + }; + length = minf(length, 1.0f); + + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + } + } + + memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Late.PanGain[i&3][i] = AmbientGains[i]; + } + } + else + { + ALfloat pan[3] = { + LateReverbPan[0] / length, + LateReverbPan[1] / length, + -LateReverbPan[2] / length, + }; + length = minf(length, 1.0f); + + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + } + } +} + static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) { static const ALfloat EarlyPanAngles[4] = { @@ -1187,8 +1258,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. - Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, State); + if(Device->Hrtf || Device->FmtChans == DevFmtBFormat3D) + Update3DPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, State); + else + UpdateDirectPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, State); } -- cgit v1.2.3 From 305ef3215d1406707d92a7d3b7f9ae73b3dbde98 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 07:34:31 -0800 Subject: Modify how the four output reverb points are calculated For HRTF and B-Format output, the points no longer move but instead scale based on the desired panning direction. --- Alc/effects/reverb.c | 102 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index bc12bc3b..01f4caf3 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1069,7 +1069,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + for(i = 0;i < Device->NumChannels;i++) { if(Device->ChannelName[i] == LFE) continue; @@ -1078,6 +1078,10 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec } else { + /* Note that EAX Reverb's panning vectors are using right-handed + * coordinates, rather that the OpenAL's left-handed coordinates. + * Negate Z to fix this. + */ ALfloat pan[3] = { ReflectionsPan[0] / length, ReflectionsPan[1] / length, @@ -1087,7 +1091,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec CalcDirectionCoeffs(pan, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + for(i = 0;i < Device->NumChannels;i++) { if(Device->ChannelName[i] == LFE) continue; @@ -1099,7 +1103,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + for(i = 0;i < Device->NumChannels;i++) { if(Device->ChannelName[i] == LFE) continue; @@ -1117,7 +1121,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec CalcDirectionCoeffs(pan, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < MAX_OUTPUT_CHANNELS && Device->ChannelName[i] != InvalidChannel;i++) + for(i = 0;i < Device->NumChannels;i++) { if(Device->ChannelName[i] == LFE) continue; @@ -1128,69 +1132,87 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) { - static const ALfloat EarlyPanAngles[4] = { - DEG2RAD(0.0f), DEG2RAD(-90.0f), DEG2RAD(90.0f), DEG2RAD(180.0f) - }, LatePanAngles[4] = { - DEG2RAD(45.0f), DEG2RAD(-45.0f), DEG2RAD(135.0f), DEG2RAD(-135.0f) + static const ALfloat PanDirs[4][3] = { + { -0.707106781f, 0.0f, -0.707106781f }, /* Front left */ + { 0.707106781f, 0.0f, -0.707106781f }, /* Front right */ + { 0.707106781f, 0.0f, 0.707106781f }, /* Back right */ + { -0.707106781f, 0.0f, 0.707106781f } /* Back left */ }; ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat length, ev, az; + ALfloat gain[4]; + ALfloat length; ALuint i; + /* 0.5 would be the gain scaling when the panning vector is 0. This also + * equals sqrt(1/4), a nice gain scaling for the four virtual points + * producing an "ambient" response. + */ + gain[0] = 0.5f; + gain[1] = 0.5f; + gain[2] = 0.5f; + gain[3] = 0.5f; length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(!(length > FLT_EPSILON)) + if(length > 1.0f) { + ALfloat pan[3] = { + ReflectionsPan[0] / length, + ReflectionsPan[1] / length, + -ReflectionsPan[2] / length, + }; for(i = 0;i < 4;i++) { - CalcAngleCoeffs(EarlyPanAngles[i], 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Early.PanGain[i]); + ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; } } - else + else if(length > FLT_EPSILON) { - ev = asinf(clampf(ReflectionsPan[1]/length, -1.0f, 1.0f)); - az = atan2f(ReflectionsPan[0], ReflectionsPan[2]); - - length = minf(length, 1.0f); for(i = 0;i < 4;i++) { - /* This is essentially just a lerp, but takes the shortest path - * with respect to circular wrapping. e.g. - * -135 -> +/-180 -> +135 - * instead of - * -135 -> 0 -> +135 */ - float offset, naz, nev; - naz = EarlyPanAngles[i] + (modff((az-EarlyPanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - CalcAngleCoeffs(naz, nev, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Early.PanGain[i]); + ALfloat dotp = ReflectionsPan[0]*PanDirs[i][0] + ReflectionsPan[1]*PanDirs[i][1] + + -ReflectionsPan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; } } + for(i = 0;i < 4;i++) + { + CalcDirectionCoeffs(PanDirs[i], coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Early.PanGain[i]); + } + gain[0] = 0.5f; + gain[1] = 0.5f; + gain[2] = 0.5f; + gain[3] = 0.5f; length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(!(length > FLT_EPSILON)) + if(length > 1.0f) { + ALfloat pan[3] = { + LateReverbPan[0] / length, + LateReverbPan[1] / length, + -LateReverbPan[2] / length, + }; + length = 1.0f; for(i = 0;i < 4;i++) { - CalcAngleCoeffs(LatePanAngles[i], 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Late.PanGain[i]); + ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; } } - else + else if(length > FLT_EPSILON) { - ev = asinf(clampf(LateReverbPan[1]/length, -1.0f, 1.0f)); - az = atan2f(LateReverbPan[0], LateReverbPan[2]); - - length = minf(length, 1.0f); for(i = 0;i < 4;i++) { - float offset, naz, nev; - naz = LatePanAngles[i] + (modff((az-LatePanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; - CalcAngleCoeffs(naz, nev, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, State->Late.PanGain[i]); + ALfloat dotp = LateReverbPan[0]*PanDirs[i][0] + LateReverbPan[1]*PanDirs[i][1] + + -LateReverbPan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; } } + for(i = 0;i < 4;i++) + { + CalcDirectionCoeffs(PanDirs[i], coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Late.PanGain[i]); + } } static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) -- cgit v1.2.3 From b8e74c88cf5bc6389a0f9d2a130c39d7d45ae265 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 07:46:33 -0800 Subject: Separate early and late reverb output for standard reverb too --- Alc/effects/reverb.c | 60 +++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 01f4caf3..7f4139c6 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -88,8 +88,7 @@ typedef struct ALreverbState { DelayLine Delay[4]; ALuint Offset[4]; - // The gain for each output channel based on 3D panning (only for the - // EAX path). + // The gain for each output channel based on 3D panning. ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Early; @@ -127,8 +126,7 @@ typedef struct ALreverbState { ALfloat LpCoeff[4]; ALfloat LpSample[4]; - // The gain for each output channel based on 3D panning (only for the - // EAX path). + // The gain for each output channel based on 3D panning. ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Late; @@ -159,10 +157,6 @@ typedef struct ALreverbState { // The current read offset for all delay lines. ALuint Offset; - // The gain for each output channel (non-EAX path only; aliased from - // Late.PanGain) - ALfloat (*Gain)[MAX_OUTPUT_CHANNELS]; - /* Temporary storage used when processing. */ ALfloat ReverbSamples[MAX_UPDATE_SAMPLES][4]; ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4]; @@ -434,10 +428,10 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res // Output the results of the matrix for all four channels, attenuated by // the late reverb gain (which is attenuated by the 'x' mix coefficient). // Mix early reflections and late reverb. - out[i][0] += State->Late.Gain * f[0]; - out[i][1] += State->Late.Gain * f[1]; - out[i][2] += State->Late.Gain * f[2]; - out[i][3] += State->Late.Gain * f[3]; + out[i][0] = State->Late.Gain * f[0]; + out[i][1] = State->Late.Gain * f[1]; + out[i][2] = State->Late.Gain * f[2]; + out[i][3] = State->Late.Gain * f[3]; // Re-feed the cyclical delay lines. DelayLineIn(&State->Late.Delay[0], offset, f[0]); @@ -488,7 +482,7 @@ static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restri // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict out)[4]) +static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) { ALuint i; @@ -499,7 +493,7 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat * ); // Calculate the early reflection from the first delay tap. - EarlyReflection(State, todo, out); + EarlyReflection(State, todo, early); // Feed the decorrelator from the energy-attenuated output of the second // delay tap. @@ -512,7 +506,7 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat * } // Calculate the late reverb from the decorrelator taps. - LateReverb(State, todo, out); + LateReverb(State, todo, late); // Step all delays forward one sample. State->Offset += todo; @@ -552,7 +546,6 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa } // Calculate the late reverb from the decorrelator taps. - memset(late, 0, sizeof(*late)*todo); LateReverb(State, todo, late); // Calculate and mix in any echo. @@ -564,25 +557,34 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - ALfloat (*restrict out)[4] = State->ReverbSamples; + ALfloat (*restrict early)[4] = State->EarlySamples; + ALfloat (*restrict late)[4] = State->ReverbSamples; ALuint index, c, i, l; + ALfloat gain; /* Process reverb for these samples. */ for(index = 0;index < SamplesToDo;) { ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); - VerbPass(State, todo, &SamplesIn[index], out); + VerbPass(State, todo, &SamplesIn[index], early, late); for(l = 0;l < 4;l++) { for(c = 0;c < NumChannels;c++) { - ALfloat gain = State->Gain[l][c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*out[i][l]; + gain = State->Early.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*late[i][l]; + } } } @@ -1147,10 +1149,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection * equals sqrt(1/4), a nice gain scaling for the four virtual points * producing an "ambient" response. */ - gain[0] = 0.5f; - gain[1] = 0.5f; - gain[2] = 0.5f; - gain[3] = 0.5f; + gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); if(length > 1.0f) { @@ -1180,10 +1179,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Early.PanGain[i]); } - gain[0] = 0.5f; - gain[1] = 0.5f; - gain[2] = 0.5f; - gain[3] = 0.5f; + gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); if(length > 1.0f) { @@ -1392,8 +1388,6 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f state->Offset = 0; - state->Gain = state->Late.PanGain; - return STATIC_CAST(ALeffectState, state); } -- cgit v1.2.3 From 8627a92ea82ce53339ebc4fdb2e39ddcfa46d3cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 08:14:41 -0800 Subject: Better organize the reverb code into separate labeled sections --- Alc/effects/reverb.c | 1779 +++++++++++++++++++++++++------------------------- 1 file changed, 898 insertions(+), 881 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7f4139c6..7911e43b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -162,12 +162,29 @@ typedef struct ALreverbState { ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4]; } ALreverbState; +static ALvoid ALreverbState_Destruct(ALreverbState *State) +{ + free(State->SampleBuffer); + State->SampleBuffer = NULL; +} + +static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); +static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot); +static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALreverbState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); + /* This is a user config option for modifying the overall output of the reverb * effect. */ ALfloat ReverbBoost = 1.0f; -/* Specifies whether to use a standard reverb effect in place of EAX reverb */ +/* Specifies whether to use a standard reverb effect in place of EAX reverb (no + * high-pass, modulation, or echo). + */ ALboolean EmulateEAXReverb = AL_FALSE; /* This coefficient is used to define the maximum frequency range controlled @@ -221,1080 +238,1080 @@ static const ALfloat LATE_LINE_LENGTH[4] = static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; -// Basic delay line input/output routines. -static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) +/************************************** + * Device Update * + **************************************/ + +// Given the allocated sample buffer, this function updates each delay line +// offset. +static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) { - return Delay->Line[offset&Delay->Mask]; + Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line]; } -static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) +// Calculate the length of a delay line and store its mask and offset. +static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, ALuint extra, DelayLine *Delay) { - Delay->Line[offset&Delay->Mask] = in; + ALuint samples; + + // All line lengths are powers of 2, calculated from their lengths, with + // an additional sample in case of rounding errors. + samples = fastf2u(length*frequency) + extra; + samples = NextPowerOf2(samples + 1); + // All lines share a single sample buffer. + Delay->Mask = samples - 1; + Delay->Line = (ALfloat*)offset; + // Return the sample count for accumulation. + return samples; } -// Given an input sample, this function produces modulation for the late -// reverb. -static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat in) +/* Calculates the delay line metrics and allocates the shared sample buffer + * for all lines given the sample rate (frequency). If an allocation failure + * occurs, it returns AL_FALSE. + */ +static ALboolean AllocLines(ALuint frequency, ALreverbState *State) { - ALfloat sinus, frac, fdelay; - ALfloat out0, out1; - ALuint delay; - - // 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_TAU * State->Mod.Index / State->Mod.Range); + ALuint totalSamples, index; + ALfloat length; + ALfloat *newBuffer = NULL; - // Step the modulation index forward, keeping it bound to its range. - State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + // All delay line lengths are calculated to accomodate the full range of + // lengths given their respective paramters. + totalSamples = 0; - // 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 - // small parameter changes. - State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, - State->Mod.Coeff); + /* The modulator's line length is calculated from the maximum modulation + * time and depth coefficient, and halfed for the low-to-high frequency + * swing. An additional sample is added to keep it stable when there is no + * modulation. + */ + length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); + totalSamples += CalcLineLength(length, totalSamples, frequency, 1, + &State->Mod.Delay); - // Calculate the read offset and fraction between it and the next sample. - frac = modff(State->Mod.Filter*sinus + 1.0f, &fdelay); - delay = fastf2u(fdelay); + // The initial delay is the sum of the reflections and late reverb + // delays. This must include space for storing a loop update to feed the + // early reflections, decorrelator, and echo. + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; + totalSamples += CalcLineLength(length, totalSamples, frequency, + MAX_UPDATE_SAMPLES, &State->Delay); - // Get the two samples crossed by the offset, and feed the delay line - // with the next input sample. - out0 = DelayLineOut(&State->Mod.Delay, offset - delay); - out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); - DelayLineIn(&State->Mod.Delay, offset, in); + // The early reflection lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, + frequency, 0, &State->Early.Delay[index]); - // The output is obtained by linearly interpolating the two samples that - // were acquired above. - return lerp(out0, out1, frac); -} + // The decorrelator line is calculated from the lowest reverb density (a + // parameter value of 1). This must include space for storing a loop update + // to feed the late reverb. + length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * + LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, + &State->Decorrelator); -// Given some input sample, this function produces four-channel outputs for the -// early reflections. -static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) -{ - ALfloat d[4], v, f[4]; - ALuint i; + // The late all-pass lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, + frequency, 0, &State->Late.ApDelay[index]); - for(i = 0;i < todo;i++) + // The late delay lines are calculated from the lowest reverb density. + for(index = 0;index < 4;index++) { - ALuint offset = State->Offset+i; + length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Late.Delay[index]); + } - // Obtain the decayed results of each early delay line. - d[0] = DelayLineOut(&State->Early.Delay[0], offset-State->Early.Offset[0]) * State->Early.Coeff[0]; - d[1] = DelayLineOut(&State->Early.Delay[1], offset-State->Early.Offset[1]) * State->Early.Coeff[1]; - d[2] = DelayLineOut(&State->Early.Delay[2], offset-State->Early.Offset[2]) * State->Early.Coeff[2]; - d[3] = DelayLineOut(&State->Early.Delay[3], offset-State->Early.Offset[3]) * State->Early.Coeff[3]; + // The echo all-pass and delay lines. + totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, + frequency, 0, &State->Echo.ApDelay); + totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, + frequency, 0, &State->Echo.Delay); - /* The following uses a lossless scattering junction from waveguide - * theory. It actually amounts to a householder mixing matrix, which - * will produce a maximally diffuse response, and means this can - * probably be considered a simple feed-back delay network (FDN). - * N - * --- - * \ - * v = 2/N / d_i - * --- - * i=1 - */ - v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; - // The junction is loaded with the input here. - v += DelayLineOut(&State->Delay, offset-State->DelayTap[0]); + if(totalSamples != State->TotalSamples) + { + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); + newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); + if(newBuffer == NULL) + return AL_FALSE; + State->SampleBuffer = newBuffer; + State->TotalSamples = totalSamples; + } - // Calculate the feed values for the delay lines. - f[0] = v - d[0]; - f[1] = v - d[1]; - f[2] = v - d[2]; - f[3] = v - d[3]; + // Update all delays to reflect the new sample buffer. + RealizeLineOffset(State->SampleBuffer, &State->Delay); + RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); + for(index = 0;index < 4;index++) + { + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); + } + RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); - // Re-feed the delay lines. - DelayLineIn(&State->Early.Delay[0], offset, f[0]); - DelayLineIn(&State->Early.Delay[1], offset, f[1]); - DelayLineIn(&State->Early.Delay[2], offset, f[2]); - DelayLineIn(&State->Early.Delay[3], offset, f[3]); + // Clear the sample buffer. + for(index = 0;index < State->TotalSamples;index++) + State->SampleBuffer[index] = 0.0f; - // Output the results of the junction for all four channels. - out[i][0] = State->Early.Gain * f[0]; - out[i][1] = State->Early.Gain * f[1]; - out[i][2] = State->Early.Gain * f[2]; - out[i][3] = State->Early.Gain * f[3]; - } + return AL_TRUE; } -// Basic attenuated all-pass input/output routine. -static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff) +static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) { - ALfloat out, feed; + ALuint frequency = Device->Frequency, index; - out = DelayLineOut(Delay, outOffset); - feed = feedCoeff * in; - DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); + // Allocate the delay lines. + if(!AllocLines(frequency, State)) + return AL_FALSE; - // The time-based attenuation is only applied to the delay output to - // keep it from affecting the feed-back path (which is already controlled - // by the all-pass feed coefficient). - return (coeff * out) - feed; + // Calculate the modulation filter coefficient. Notice that the exponent + // is calculated given the current sample rate. This ensures that the + // resulting filter response over time is consistent across all sample + // rates. + State->Mod.Coeff = powf(MODULATION_FILTER_COEFF, + MODULATION_FILTER_CONST / frequency); + + // The early reflection and late all-pass filter line lengths are static, + // so their offsets only need to be calculated once. + for(index = 0;index < 4;index++) + { + State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * frequency); + State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * frequency); + } + + // The echo all-pass filter line length is static, so its offset only + // needs to be calculated once. + State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency); + + return AL_TRUE; } -// All-pass input/output routine for late reverb. -static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in) +/************************************** + * Effect Update * + **************************************/ + +// 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) { - return AllpassInOut(&State->Late.ApDelay[index], - offset - State->Late.ApOffset[index], - offset, in, State->Late.ApFeedCoeff, - State->Late.ApCoeff[index]); + return powf(0.001f/*-60 dB*/, length/decayTime); } -// Low-pass filter input/output routine for late reverb. -static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in) +// Calculate a decay length from a coefficient and the time until the decay +// reaches -60 dB. +static inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime) { - in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]); - State->Late.LpSample[index] = in; - return in; + return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; } -// Given four decorrelated input samples, this function produces four-channel -// output for the late reverb. -static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) +// 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) { - ALfloat d[4], f[4]; - ALuint i; - - for(i = 0;i < todo;i++) - { - ALuint offset = State->Offset+i; - - f[0] = DelayLineOut(&State->Decorrelator, offset); - f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); - f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); - f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); - - // Obtain the decayed results of the cyclical delay lines, and add the - // corresponding input channels. Then pass the results through the - // low-pass filters. - f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; - f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; - f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; - f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; + /* 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 + * amplitude for the sample n. + * + * Decaying feedback matches exponential decay of the form Sum(a^n), + * where a is the attenuation coefficient, and n is the sample. The area + * under this decay curve can be calculated as: 1 / (1 - a). + * + * Modifying the above equation to find the squared area under the curve + * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be + * calculated by inverting the square root of this approximation, + * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). + */ + return sqrtf(1.0f - (a * a)); +} - // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and - // back to 0. - d[0] = LateLowPassInOut(State, 2, f[2]); - d[1] = LateLowPassInOut(State, 0, f[0]); - d[2] = LateLowPassInOut(State, 3, f[3]); - d[3] = LateLowPassInOut(State, 1, f[1]); +// Calculate the mixing matrix coefficients given a diffusion factor. +static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) +{ + ALfloat n, t; - // To help increase diffusion, run each line through an all-pass filter. - // When there is no diffusion, the shortest all-pass filter will feed - // the shortest delay line. - d[0] = LateAllPassInOut(State, offset, 0, d[0]); - d[1] = LateAllPassInOut(State, offset, 1, d[1]); - d[2] = LateAllPassInOut(State, offset, 2, d[2]); - d[3] = LateAllPassInOut(State, offset, 3, d[3]); + // The matrix is of order 4, so n is sqrt (4 - 1). + n = sqrtf(3.0f); + t = diffusion * atanf(n); - /* Late reverb is done with a modified feed-back delay network (FDN) - * topology. Four input lines are each fed through their own all-pass - * filter and then into the mixing matrix. The four outputs of the - * mixing matrix are then cycled back to the inputs. Each output feeds - * a different input to form a circlular feed cycle. - * - * The mixing matrix used is a 4D skew-symmetric rotation matrix - * derived using a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y - * with differing signs, and d is the coefficient x. The matrix is - * thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * To reduce the number of multiplies, the x coefficient is applied - * with the cyclical delay line coefficients. Thus only the y - * coefficient is applied when mixing, and is modified to be: y / x. - */ - f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); - f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); - f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); - f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + // Calculate the first mixing matrix coefficient. + *x = cosf(t); + // Calculate the second mixing matrix coefficient. + *y = sinf(t) / n; +} - // Output the results of the matrix for all four channels, attenuated by - // the late reverb gain (which is attenuated by the 'x' mix coefficient). - // Mix early reflections and late reverb. - out[i][0] = State->Late.Gain * f[0]; - out[i][1] = State->Late.Gain * f[1]; - out[i][2] = State->Late.Gain * f[2]; - out[i][3] = State->Late.Gain * f[3]; +// Calculate the limited HF ratio for use with the late reverb low-pass +// filters. +static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) +{ + ALfloat limitRatio; - // Re-feed the cyclical delay lines. - DelayLineIn(&State->Late.Delay[0], offset, f[0]); - DelayLineIn(&State->Late.Delay[1], offset, f[1]); - DelayLineIn(&State->Late.Delay[2], offset, f[2]); - DelayLineIn(&State->Late.Delay[3], offset, f[3]); - } + /* Find the attenuation due to air absorption in dB (converting delay + * time to meters using the speed of sound). Then reversing the decay + * equation, solve for HF ratio. The delay length is cancelled out of + * the equation, so it can be calculated once for all lines. + */ + limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * + SPEEDOFSOUNDMETRESPERSEC); + /* Using the limit calculated above, apply the upper bound to the HF + * ratio. Also need to limit the result to a minimum of 0.1, just like the + * HF ratio parameter. */ + return clampf(limitRatio, 0.1f, hfRatio); } -// Given an input sample, this function mixes echo into the four-channel late -// reverb. -static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4]) +// 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) { - ALfloat out, feed; - ALuint i; + ALfloat coeff, g; - for(i = 0;i < todo;i++) + // Eventually this should boost the high frequencies when the ratio + // exceeds 1. + coeff = 0.0f; + if (hfRatio < 1.0f) { - ALuint offset = State->Offset+i; - - // Get the latest attenuated echo sample for output. - feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) * - State->Echo.Coeff; - - // Mix the output into the late reverb channels. - out = State->Echo.MixCoeff * feed; - late[i][0] += out; - late[i][1] += out; - late[i][2] += out; - late[i][3] += out; - - // Mix the energy-attenuated input with the output and pass it through - // the echo low-pass filter. - feed += DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * - State->Echo.DensityGain; - feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); - State->Echo.LpSample = feed; + // Calculate the low-pass coefficient by dividing the HF decay + // coefficient by the full decay coefficient. + g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; - // Then the echo all-pass filter. - feed = AllpassInOut(&State->Echo.ApDelay, offset-State->Echo.ApOffset, - offset, feed, State->Echo.ApFeedCoeff, - State->Echo.ApCoeff); + // Damping is done with a 1-pole filter, so g needs to be squared. + g *= g; + 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); + } - // Feed the delay with the mixed and filtered sample. - DelayLineIn(&State->Echo.Delay, offset, feed); + // Very low decay times will produce minimal output, so apply an + // upper bound to the coefficient. + coeff = minf(coeff, 0.98f); } + return coeff; } -// Perform the non-EAX reverb pass on a given input sample, resulting in -// four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) +// 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, ALreverbState *State) { - ALuint i; - - // Low-pass filter the incoming samples. - for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, - ALfilterState_processSingle(&State->LpFilter, in[i]) - ); - - // Calculate the early reflection from the first delay tap. - EarlyReflection(State, todo, early); + ALuint range; - // Feed the decorrelator from the energy-attenuated output of the second - // delay tap. - for(i = 0;i < todo;i++) - { - ALuint offset = State->Offset+i; - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); - } + /* Modulation is calculated in two parts. + * + * The modulation time effects the sinus applied to the change in + * frequency. An index out of the current time range (both in samples) + * is incremented each sample. The range is bound to a reasonable + * minimum (1 sample) and when the timing changes, the index is rescaled + * to the new range (to keep the sinus consistent). + */ + range = maxu(fastf2u(modTime*frequency), 1); + State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range / + State->Mod.Range); + State->Mod.Range = range; - // Calculate the late reverb from the decorrelator taps. - LateReverb(State, todo, late); + /* The modulation depth effects the amount of frequency change over the + * range of the sinus. It needs to be scaled by the modulation time so + * that a given depth produces a consistent change in frequency over all + * ranges of time. Since the depth is applied to a sinus value, it needs + * to be halfed once for the sinus range and again for the sinus swing + * in time (half of it is spent decreasing the frequency, half is spent + * increasing it). + */ + State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / + 2.0f * frequency; +} - // Step all delays forward one sample. - State->Offset += todo; +// Update the offsets for the initial effect delay line. +static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State) +{ + // Calculate the initial delay taps. + State->DelayTap[0] = fastf2u(earlyDelay * frequency); + State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); } -// Perform the EAX reverb pass on a given input sample, resulting in four- -// channel output. -static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) +// Update the early reflections gain and line coefficients. +static ALvoid UpdateEarlyLines(ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State) { - ALuint i; + ALuint index; - // Band-pass and modulate the incoming samples. - for(i = 0;i < todo;i++) - { - ALfloat sample = input[i]; - sample = ALfilterState_processSingle(&State->LpFilter, sample); - sample = ALfilterState_processSingle(&State->HpFilter, sample); + // Calculate the early reflections gain (from the master effect gain, and + // reflections gain parameters) with a constant attenuation of 0.5. + State->Early.Gain = 0.5f * earlyGain; - // Perform any modulation on the input. - sample = EAXModulation(State, State->Offset+i, sample); + // Calculate the gain (coefficient) for each early delay line using the + // late delay time. This expands the early reflections to the start of + // the late reverb. + for(index = 0;index < 4;index++) + State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], + lateDelay); +} - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset+i, sample); - } +// Update the offsets for the decorrelator line. +static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State) +{ + ALuint index; + ALfloat length; - // Calculate the early reflection from the first delay tap. - EarlyReflection(State, todo, early); - - // Feed the decorrelator from the energy-attenuated output of the second - // delay tap. - for(i = 0;i < todo;i++) + /* The late reverb inputs are decorrelated to smooth the reverb tail and + * reduce harsh echos. The first tap occurs immediately, while the + * remaining taps are delayed by multiples of a fraction of the smallest + * cyclical delay time. + * + * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay + */ + for(index = 0;index < 3;index++) { - ALuint offset = State->Offset+i; - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * + LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); + State->DecoTap[index] = fastf2u(length * frequency); } - - // Calculate the late reverb from the decorrelator taps. - LateReverb(State, todo, late); - - // Calculate and mix in any echo. - EAXEcho(State, todo, late); - - // Step all delays forward. - State->Offset += todo; } -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +// Update the late reverb gains, line lengths, and line coefficients. +static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { - ALfloat (*restrict early)[4] = State->EarlySamples; - ALfloat (*restrict late)[4] = State->ReverbSamples; - ALuint index, c, i, l; - ALfloat gain; + ALfloat length; + ALuint index; - /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;) - { - ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); + /* Calculate the late reverb gain (from the master effect gain, and late + * reverb gain parameters). Since the output is tapped prior to the + * application of the next delay line coefficients, this gain needs to be + * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate + * the late reverb when echo depth is high and diffusion is low, so the + * echo is slightly stronger than the decorrelated echos in the reverb + * tail. + */ + State->Late.Gain = lateGain * xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); - VerbPass(State, todo, &SamplesIn[index], early, late); + /* To compensate for changes in modal density and decay time of the late + * reverb signal, the input is attenuated based on the maximal energy of + * the outgoing signal. This approximation is used to keep the apparent + * energy of the signal equal for all ranges of density and decay time. + * + * The average length of the cyclcical delay lines is used to calculate + * the attenuation coefficient. + */ + length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; + length *= 1.0f + (density * LATE_LINE_MULTIPLIER); + State->Late.DensityGain = CalcDensityGain( + CalcDecayCoeff(length, decayTime) + ); - for(l = 0;l < 4;l++) - { - for(c = 0;c < NumChannels;c++) - { - gain = State->Early.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[i][l]; - } - gain = State->Late.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[i][l]; - } - } - } + // Calculate the all-pass feed-back and feed-forward coefficient. + State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); - index += todo; - } -} + for(index = 0;index < 4;index++) + { + // Calculate the gain (coefficient) for each all-pass line. + State->Late.ApCoeff[index] = CalcDecayCoeff( + ALLPASS_LINE_LENGTH[index], decayTime + ); -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) -{ - ALfloat (*restrict early)[4] = State->EarlySamples; - ALfloat (*restrict late)[4] = State->ReverbSamples; - ALuint index, c, i, l; - ALfloat gain; + // Calculate the length (in seconds) of each cyclical delay line. + length = LATE_LINE_LENGTH[index] * + (1.0f + (density * LATE_LINE_MULTIPLIER)); - /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;) - { - ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); + // Calculate the delay offset for each cyclical delay line. + State->Late.Offset[index] = fastf2u(length * frequency); - EAXVerbPass(State, todo, &SamplesIn[index], early, late); + // Calculate the gain (coefficient) for each cyclical line. + State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); - for(l = 0;l < 4;l++) - { - for(c = 0;c < NumChannels;c++) - { - gain = State->Early.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[i][l]; - } - gain = State->Late.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[i][l]; - } - } - } + // Calculate the damping coefficient for each low-pass filter. + State->Late.LpCoeff[index] = CalcDampingCoeff( + hfRatio, length, decayTime, State->Late.Coeff[index], cw + ); - index += todo; + // Attenuate the cyclical line coefficients by the mixing coefficient + // (x). + State->Late.Coeff[index] *= xMix; } } -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +// Update the echo gain, line offset, line coefficients, and mixing +// coefficients. +static ALvoid UpdateEchoLine(ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { - if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); - else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); -} + // Update the offset and coefficient for the echo delay line. + State->Echo.Offset = fastf2u(echoTime * frequency); -// Given the allocated sample buffer, this function updates each delay line -// offset. -static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) -{ - Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line]; -} + // Calculate the decay coefficient for the echo line. + State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); -// Calculate the length of a delay line and store its mask and offset. -static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, ALuint extra, DelayLine *Delay) -{ - ALuint samples; + // Calculate the energy-based attenuation coefficient for the echo delay + // line. + State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); - // All line lengths are powers of 2, calculated from their lengths, with - // an additional sample in case of rounding errors. - samples = fastf2u(length*frequency) + extra; - samples = NextPowerOf2(samples + 1); - // All lines share a single sample buffer. - Delay->Mask = samples - 1; - Delay->Line = (ALfloat*)offset; - // Return the sample count for accumulation. - return samples; -} + // Calculate the echo all-pass feed coefficient. + State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); -/* Calculates the delay line metrics and allocates the shared sample buffer - * for all lines given the sample rate (frequency). If an allocation failure - * occurs, it returns AL_FALSE. - */ -static ALboolean AllocLines(ALuint frequency, ALreverbState *State) -{ - ALuint totalSamples, index; - ALfloat length; - ALfloat *newBuffer = NULL; + // Calculate the echo all-pass attenuation coefficient. + State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); - // All delay line lengths are calculated to accomodate the full range of - // lengths given their respective paramters. - totalSamples = 0; + // Calculate the damping coefficient for each low-pass filter. + State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, + State->Echo.Coeff, cw); - /* The modulator's line length is calculated from the maximum modulation - * time and depth coefficient, and halfed for the low-to-high frequency - * swing. An additional sample is added to keep it stable when there is no - * modulation. + /* Calculate the echo mixing coefficient. This is applied to the output mix + * only, not the feedback. */ - length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); - totalSamples += CalcLineLength(length, totalSamples, frequency, 1, - &State->Mod.Delay); + State->Echo.MixCoeff = lateGain * echoDepth; +} - // The initial delay is the sum of the reflections and late reverb - // delays. This must include space for storing a loop update to feed the - // early reflections, decorrelator, and echo. - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY; - totalSamples += CalcLineLength(length, totalSamples, frequency, - MAX_UPDATE_SAMPLES, &State->Delay); +// Update the early and late 3D panning gains. +static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +{ + ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; + ALfloat DirGains[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat length; + ALuint i; - // The early reflection lines. - for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Early.Delay[index]); + ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain, AmbientGains); - // The decorrelator line is calculated from the lowest reverb density (a - // parameter value of 1). This must include space for storing a loop update - // to feed the late reverb. - length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * - LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, - &State->Decorrelator); + memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < Device->NumChannels;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Early.PanGain[i&3][i] = AmbientGains[i]; + } + } + else + { + /* Note that EAX Reverb's panning vectors are using right-handed + * coordinates, rather that the OpenAL's left-handed coordinates. + * Negate Z to fix this. + */ + ALfloat pan[3] = { + ReflectionsPan[0] / length, + ReflectionsPan[1] / length, + -ReflectionsPan[2] / length, + }; + length = minf(length, 1.0f); - // The late all-pass lines. - for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Late.ApDelay[index]); + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->NumChannels;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + } + } - // The late delay lines are calculated from the lowest reverb density. - for(index = 0;index < 4;index++) + memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); + if(!(length > FLT_EPSILON)) { - length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.Delay[index]); + for(i = 0;i < Device->NumChannels;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Late.PanGain[i&3][i] = AmbientGains[i]; + } } + else + { + ALfloat pan[3] = { + LateReverbPan[0] / length, + LateReverbPan[1] / length, + -LateReverbPan[2] / length, + }; + length = minf(length, 1.0f); - // The echo all-pass and delay lines. - totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, - frequency, 0, &State->Echo.ApDelay); - totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, - frequency, 0, &State->Echo.Delay); + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->NumChannels;i++) + { + if(Device->ChannelName[i] == LFE) + continue; + State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + } + } +} - if(totalSamples != State->TotalSamples) +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +{ + static const ALfloat PanDirs[4][3] = { + { -0.707106781f, 0.0f, -0.707106781f }, /* Front left */ + { 0.707106781f, 0.0f, -0.707106781f }, /* Front right */ + { 0.707106781f, 0.0f, 0.707106781f }, /* Back right */ + { -0.707106781f, 0.0f, 0.707106781f } /* Back left */ + }; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat gain[4]; + ALfloat length; + ALuint i; + + /* 0.5 would be the gain scaling when the panning vector is 0. This also + * equals sqrt(1/4), a nice gain scaling for the four virtual points + * producing an "ambient" response. + */ + gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; + length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); + if(length > 1.0f) { - TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); - newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); - if(newBuffer == NULL) - return AL_FALSE; - State->SampleBuffer = newBuffer; - State->TotalSamples = totalSamples; + ALfloat pan[3] = { + ReflectionsPan[0] / length, + ReflectionsPan[1] / length, + -ReflectionsPan[2] / length, + }; + for(i = 0;i < 4;i++) + { + ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; + } } - - // Update all delays to reflect the new sample buffer. - RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); - for(index = 0;index < 4;index++) + else if(length > FLT_EPSILON) { - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); - RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); + for(i = 0;i < 4;i++) + { + ALfloat dotp = ReflectionsPan[0]*PanDirs[i][0] + ReflectionsPan[1]*PanDirs[i][1] + + -ReflectionsPan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; + } + } + for(i = 0;i < 4;i++) + { + CalcDirectionCoeffs(PanDirs[i], coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Early.PanGain[i]); } - RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); - - // Clear the sample buffer. - for(index = 0;index < State->TotalSamples;index++) - State->SampleBuffer[index] = 0.0f; - return AL_TRUE; + gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; + length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); + if(length > 1.0f) + { + ALfloat pan[3] = { + LateReverbPan[0] / length, + LateReverbPan[1] / length, + -LateReverbPan[2] / length, + }; + length = 1.0f; + for(i = 0;i < 4;i++) + { + ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; + } + } + else if(length > FLT_EPSILON) + { + for(i = 0;i < 4;i++) + { + ALfloat dotp = LateReverbPan[0]*PanDirs[i][0] + LateReverbPan[1]*PanDirs[i][1] + + -LateReverbPan[2]*PanDirs[i][2]; + gain[i] = dotp*0.5f + 0.5f; + } + } + for(i = 0;i < 4;i++) + { + CalcDirectionCoeffs(PanDirs[i], coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Late.PanGain[i]); + } } -static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) +static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) { - ALuint frequency = Device->Frequency, index; + const ALeffectProps *props = &Slot->EffectProps; + ALuint frequency = Device->Frequency; + ALfloat lfscale, hfscale, hfRatio; + ALfloat gain, gainlf, gainhf; + ALfloat cw, x, y; - // Allocate the delay lines. - if(!AllocLines(frequency, State)) - return AL_FALSE; + if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) + State->IsEax = AL_TRUE; + else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) + State->IsEax = AL_FALSE; - // Calculate the modulation filter coefficient. Notice that the exponent - // is calculated given the current sample rate. This ensures that the - // resulting filter response over time is consistent across all sample - // rates. - State->Mod.Coeff = powf(MODULATION_FILTER_COEFF, - MODULATION_FILTER_CONST / frequency); + // Calculate the master filters + hfscale = props->Reverb.HFReference / frequency; + gainhf = maxf(props->Reverb.GainHF, 0.0001f); + ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, + gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); + lfscale = props->Reverb.LFReference / frequency; + gainlf = maxf(props->Reverb.GainLF, 0.0001f); + ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, + gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); - // The early reflection and late all-pass filter line lengths are static, - // so their offsets only need to be calculated once. - for(index = 0;index < 4;index++) - { - State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * - frequency); - State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * - frequency); - } + // Update the modulator line. + UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, + frequency, State); - // The echo all-pass filter line length is static, so its offset only - // needs to be calculated once. - State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency); + // Update the initial effect delay. + UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, + frequency, State); + + // Update the early lines. + UpdateEarlyLines(props->Reverb.ReflectionsGain, + props->Reverb.LateReverbDelay, State); + + // Update the decorrelator. + UpdateDecorrelator(props->Reverb.Density, frequency, State); + + // Get the mixing matrix coefficients (x and y). + CalcMatrixCoeffs(props->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 = props->Reverb.DecayHFRatio; + if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, + props->Reverb.DecayTime); + + cw = cosf(F_TAU * hfscale); + // Update the late lines. + UpdateLateLines(props->Reverb.LateReverbGain, x, + props->Reverb.Density, props->Reverb.DecayTime, + props->Reverb.Diffusion, props->Reverb.EchoDepth, + hfRatio, cw, frequency, State); + + // Update the echo line. + UpdateEchoLine(props->Reverb.LateReverbGain, + props->Reverb.EchoTime, props->Reverb.DecayTime, + props->Reverb.Diffusion, props->Reverb.EchoDepth, + hfRatio, cw, frequency, State); - return AL_TRUE; + gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; + // Update early and late 3D panning. + if(Device->Hrtf || Device->FmtChans == DevFmtBFormat3D) + Update3DPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, State); + else + UpdateDirectPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, State); } -// 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) -{ - 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) +/************************************** + * Effect Processing * + **************************************/ + +// Basic delay line input/output routines. +static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) { - return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; + return Delay->Line[offset&Delay->Mask]; } -// 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 ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) { - /* 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 - * amplitude for the sample n. - * - * Decaying feedback matches exponential decay of the form Sum(a^n), - * where a is the attenuation coefficient, and n is the sample. The area - * under this decay curve can be calculated as: 1 / (1 - a). - * - * Modifying the above equation to find the squared area under the curve - * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be - * calculated by inverting the square root of this approximation, - * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). - */ - return sqrtf(1.0f - (a * a)); + Delay->Line[offset&Delay->Mask] = in; } -// Calculate the mixing matrix coefficients given a diffusion factor. -static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) +// Given an input sample, this function produces modulation for the late +// reverb. +static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat in) { - ALfloat n, t; + ALfloat sinus, frac, fdelay; + ALfloat out0, out1; + ALuint delay; - // The matrix is of order 4, so n is sqrt (4 - 1). - n = sqrtf(3.0f); - t = diffusion * atanf(n); + // 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_TAU * State->Mod.Index / State->Mod.Range); - // Calculate the first mixing matrix coefficient. - *x = cosf(t); - // Calculate the second mixing matrix coefficient. - *y = sinf(t) / n; -} + // Step the modulation index forward, keeping it bound to its range. + State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; -// Calculate the limited HF ratio for use with the late reverb low-pass -// filters. -static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) -{ - ALfloat limitRatio; + // 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 + // small parameter changes. + State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, + State->Mod.Coeff); - /* Find the attenuation due to air absorption in dB (converting delay - * time to meters using the speed of sound). Then reversing the decay - * equation, solve for HF ratio. The delay length is cancelled out of - * the equation, so it can be calculated once for all lines. - */ - limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * - SPEEDOFSOUNDMETRESPERSEC); - /* Using the limit calculated above, apply the upper bound to the HF - * ratio. Also need to limit the result to a minimum of 0.1, just like the - * HF ratio parameter. */ - return clampf(limitRatio, 0.1f, hfRatio); + // Calculate the read offset and fraction between it and the next sample. + frac = modff(State->Mod.Filter*sinus + 1.0f, &fdelay); + delay = fastf2u(fdelay); + + // Get the two samples crossed by the offset, and feed the delay line + // with the next input sample. + out0 = DelayLineOut(&State->Mod.Delay, offset - delay); + out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); + DelayLineIn(&State->Mod.Delay, offset, in); + + // The output is obtained by linearly interpolating the two samples that + // were acquired above. + return lerp(out0, out1, frac); } -// 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) +// Given some input sample, this function produces four-channel outputs for the +// early reflections. +static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) { - ALfloat coeff, g; + ALfloat d[4], v, f[4]; + ALuint i; - // Eventually this should boost the high frequencies when the ratio - // exceeds 1. - coeff = 0.0f; - if (hfRatio < 1.0f) + for(i = 0;i < todo;i++) { - // Calculate the low-pass coefficient by dividing the HF decay - // coefficient by the full decay coefficient. - g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; - - // Damping is done with a 1-pole filter, so g needs to be squared. - g *= g; - 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); - } + ALuint offset = State->Offset+i; - // Very low decay times will produce minimal output, so apply an - // upper bound to the coefficient. - coeff = minf(coeff, 0.98f); - } - return coeff; -} + // Obtain the decayed results of each early delay line. + d[0] = DelayLineOut(&State->Early.Delay[0], offset-State->Early.Offset[0]) * State->Early.Coeff[0]; + d[1] = DelayLineOut(&State->Early.Delay[1], offset-State->Early.Offset[1]) * State->Early.Coeff[1]; + d[2] = DelayLineOut(&State->Early.Delay[2], offset-State->Early.Offset[2]) * State->Early.Coeff[2]; + d[3] = DelayLineOut(&State->Early.Delay[3], offset-State->Early.Offset[3]) * State->Early.Coeff[3]; -// 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, ALreverbState *State) -{ - ALuint range; + /* The following uses a lossless scattering junction from waveguide + * theory. It actually amounts to a householder mixing matrix, which + * will produce a maximally diffuse response, and means this can + * probably be considered a simple feed-back delay network (FDN). + * N + * --- + * \ + * v = 2/N / d_i + * --- + * i=1 + */ + v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; + // The junction is loaded with the input here. + v += DelayLineOut(&State->Delay, offset-State->DelayTap[0]); - /* Modulation is calculated in two parts. - * - * The modulation time effects the sinus applied to the change in - * frequency. An index out of the current time range (both in samples) - * is incremented each sample. The range is bound to a reasonable - * minimum (1 sample) and when the timing changes, the index is rescaled - * to the new range (to keep the sinus consistent). - */ - range = maxu(fastf2u(modTime*frequency), 1); - State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range / - State->Mod.Range); - State->Mod.Range = range; + // Calculate the feed values for the delay lines. + f[0] = v - d[0]; + f[1] = v - d[1]; + f[2] = v - d[2]; + f[3] = v - d[3]; - /* The modulation depth effects the amount of frequency change over the - * range of the sinus. It needs to be scaled by the modulation time so - * that a given depth produces a consistent change in frequency over all - * ranges of time. Since the depth is applied to a sinus value, it needs - * to be halfed once for the sinus range and again for the sinus swing - * in time (half of it is spent decreasing the frequency, half is spent - * increasing it). - */ - State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / - 2.0f * frequency; -} + // Re-feed the delay lines. + DelayLineIn(&State->Early.Delay[0], offset, f[0]); + DelayLineIn(&State->Early.Delay[1], offset, f[1]); + DelayLineIn(&State->Early.Delay[2], offset, f[2]); + DelayLineIn(&State->Early.Delay[3], offset, f[3]); -// Update the offsets for the initial effect delay line. -static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State) -{ - // Calculate the initial delay taps. - State->DelayTap[0] = fastf2u(earlyDelay * frequency); - State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); + // Output the results of the junction for all four channels. + out[i][0] = State->Early.Gain * f[0]; + out[i][1] = State->Early.Gain * f[1]; + out[i][2] = State->Early.Gain * f[2]; + out[i][3] = State->Early.Gain * f[3]; + } } -// Update the early reflections gain and line coefficients. -static ALvoid UpdateEarlyLines(ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State) +// Basic attenuated all-pass input/output routine. +static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff) { - ALuint index; + ALfloat out, feed; - // Calculate the early reflections gain (from the master effect gain, and - // reflections gain parameters) with a constant attenuation of 0.5. - State->Early.Gain = 0.5f * earlyGain; + out = DelayLineOut(Delay, outOffset); + feed = feedCoeff * in; + DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); - // Calculate the gain (coefficient) for each early delay line using the - // late delay time. This expands the early reflections to the start of - // the late reverb. - for(index = 0;index < 4;index++) - State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], - lateDelay); + // The time-based attenuation is only applied to the delay output to + // keep it from affecting the feed-back path (which is already controlled + // by the all-pass feed coefficient). + return (coeff * out) - feed; } -// Update the offsets for the decorrelator line. -static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State) +// All-pass input/output routine for late reverb. +static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in) { - ALuint index; - ALfloat length; + return AllpassInOut(&State->Late.ApDelay[index], + offset - State->Late.ApOffset[index], + offset, in, State->Late.ApFeedCoeff, + State->Late.ApCoeff[index]); +} - /* The late reverb inputs are decorrelated to smooth the reverb tail and - * reduce harsh echos. The first tap occurs immediately, while the - * remaining taps are delayed by multiples of a fraction of the smallest - * cyclical delay time. - * - * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay - */ - for(index = 0;index < 3;index++) - { - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * - LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->DecoTap[index] = fastf2u(length * frequency); - } +// Low-pass filter input/output routine for late reverb. +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; + return in; } -// Update the late reverb gains, line lengths, and line coefficients. -static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +// Given four decorrelated input samples, this function produces four-channel +// output for the late reverb. +static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) { - ALfloat length; - ALuint index; - - /* Calculate the late reverb gain (from the master effect gain, and late - * reverb gain parameters). Since the output is tapped prior to the - * application of the next delay line coefficients, this gain needs to be - * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate - * the late reverb when echo depth is high and diffusion is low, so the - * echo is slightly stronger than the decorrelated echos in the reverb - * tail. - */ - State->Late.Gain = lateGain * xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); + ALfloat d[4], f[4]; + ALuint i; - /* To compensate for changes in modal density and decay time of the late - * reverb signal, the input is attenuated based on the maximal energy of - * the outgoing signal. This approximation is used to keep the apparent - * energy of the signal equal for all ranges of density and decay time. - * - * The average length of the cyclcical delay lines is used to calculate - * the attenuation coefficient. - */ - length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + - LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; - length *= 1.0f + (density * LATE_LINE_MULTIPLIER); - State->Late.DensityGain = CalcDensityGain( - CalcDecayCoeff(length, decayTime) - ); + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; - // Calculate the all-pass feed-back and feed-forward coefficient. - State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); + f[0] = DelayLineOut(&State->Decorrelator, offset); + f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); + f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); + f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); - for(index = 0;index < 4;index++) - { - // Calculate the gain (coefficient) for each all-pass line. - State->Late.ApCoeff[index] = CalcDecayCoeff( - ALLPASS_LINE_LENGTH[index], decayTime - ); + // Obtain the decayed results of the cyclical delay lines, and add the + // corresponding input channels. Then pass the results through the + // low-pass filters. + f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; + f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; + f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; + f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; - // Calculate the length (in seconds) of each cyclical delay line. - length = LATE_LINE_LENGTH[index] * - (1.0f + (density * LATE_LINE_MULTIPLIER)); + // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and + // back to 0. + d[0] = LateLowPassInOut(State, 2, f[2]); + d[1] = LateLowPassInOut(State, 0, f[0]); + d[2] = LateLowPassInOut(State, 3, f[3]); + d[3] = LateLowPassInOut(State, 1, f[1]); - // Calculate the delay offset for each cyclical delay line. - State->Late.Offset[index] = fastf2u(length * frequency); + // To help increase diffusion, run each line through an all-pass filter. + // When there is no diffusion, the shortest all-pass filter will feed + // the shortest delay line. + d[0] = LateAllPassInOut(State, offset, 0, d[0]); + d[1] = LateAllPassInOut(State, offset, 1, d[1]); + d[2] = LateAllPassInOut(State, offset, 2, d[2]); + d[3] = LateAllPassInOut(State, offset, 3, d[3]); - // Calculate the gain (coefficient) for each cyclical line. - State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. Each output feeds + * a different input to form a circlular feed cycle. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix + * derived using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is + * thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied + * with the cyclical delay line coefficients. Thus only the y + * coefficient is applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); - // Calculate the damping coefficient for each low-pass filter. - State->Late.LpCoeff[index] = CalcDampingCoeff( - hfRatio, length, decayTime, State->Late.Coeff[index], cw - ); + // Output the results of the matrix for all four channels, attenuated by + // the late reverb gain (which is attenuated by the 'x' mix coefficient). + // Mix early reflections and late reverb. + out[i][0] = State->Late.Gain * f[0]; + out[i][1] = State->Late.Gain * f[1]; + out[i][2] = State->Late.Gain * f[2]; + out[i][3] = State->Late.Gain * f[3]; - // Attenuate the cyclical line coefficients by the mixing coefficient - // (x). - State->Late.Coeff[index] *= xMix; + // Re-feed the cyclical delay lines. + DelayLineIn(&State->Late.Delay[0], offset, f[0]); + DelayLineIn(&State->Late.Delay[1], offset, f[1]); + DelayLineIn(&State->Late.Delay[2], offset, f[2]); + DelayLineIn(&State->Late.Delay[3], offset, f[3]); } } -// Update the echo gain, line offset, line coefficients, and mixing -// coefficients. -static ALvoid UpdateEchoLine(ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +// Given an input sample, this function mixes echo into the four-channel late +// reverb. +static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4]) { - // Update the offset and coefficient for the echo delay line. - State->Echo.Offset = fastf2u(echoTime * frequency); + ALfloat out, feed; + ALuint i; - // Calculate the decay coefficient for the echo line. - State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; - // Calculate the energy-based attenuation coefficient for the echo delay - // line. - State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); + // Get the latest attenuated echo sample for output. + feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) * + State->Echo.Coeff; - // Calculate the echo all-pass feed coefficient. - State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); + // Mix the output into the late reverb channels. + out = State->Echo.MixCoeff * feed; + late[i][0] += out; + late[i][1] += out; + late[i][2] += out; + late[i][3] += out; - // Calculate the echo all-pass attenuation coefficient. - State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); + // Mix the energy-attenuated input with the output and pass it through + // the echo low-pass filter. + feed += DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * + State->Echo.DensityGain; + feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); + State->Echo.LpSample = feed; - // Calculate the damping coefficient for each low-pass filter. - State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, - State->Echo.Coeff, cw); + // Then the echo all-pass filter. + feed = AllpassInOut(&State->Echo.ApDelay, offset-State->Echo.ApOffset, + offset, feed, State->Echo.ApFeedCoeff, + State->Echo.ApCoeff); - /* Calculate the echo mixing coefficient. This is applied to the output mix - * only, not the feedback. - */ - State->Echo.MixCoeff = lateGain * echoDepth; + // Feed the delay with the mixed and filtered sample. + DelayLineIn(&State->Echo.Delay, offset, feed); + } } -// Update the early and late 3D panning gains. -static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +// Perform the non-EAX reverb pass on a given input sample, resulting in +// four-channel output. +static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) { - ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; - ALfloat DirGains[MAX_OUTPUT_CHANNELS]; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat length; ALuint i; - ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain, AmbientGains); - - memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); - length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; - State->Early.PanGain[i&3][i] = AmbientGains[i]; - } - } - else - { - /* Note that EAX Reverb's panning vectors are using right-handed - * coordinates, rather that the OpenAL's left-handed coordinates. - * Negate Z to fix this. - */ - ALfloat pan[3] = { - ReflectionsPan[0] / length, - ReflectionsPan[1] / length, - -ReflectionsPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; - State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); - } - } - - memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); - length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; - State->Late.PanGain[i&3][i] = AmbientGains[i]; - } - } - else - { - ALfloat pan[3] = { - LateReverbPan[0] / length, - LateReverbPan[1] / length, - -LateReverbPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; - State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); - } + // Low-pass filter the incoming samples. + for(i = 0;i < todo;i++) + DelayLineIn(&State->Delay, State->Offset+i, + ALfilterState_processSingle(&State->LpFilter, in[i]) + ); + + // Calculate the early reflection from the first delay tap. + EarlyReflection(State, todo, early); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; + ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * + State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, offset, sample); } + + // Calculate the late reverb from the decorrelator taps. + LateReverb(State, todo, late); + + // Step all delays forward one sample. + State->Offset += todo; } -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +// Perform the EAX reverb pass on a given input sample, resulting in four- +// channel output. +static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) { - static const ALfloat PanDirs[4][3] = { - { -0.707106781f, 0.0f, -0.707106781f }, /* Front left */ - { 0.707106781f, 0.0f, -0.707106781f }, /* Front right */ - { 0.707106781f, 0.0f, 0.707106781f }, /* Back right */ - { -0.707106781f, 0.0f, 0.707106781f } /* Back left */ - }; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat gain[4]; - ALfloat length; ALuint i; - /* 0.5 would be the gain scaling when the panning vector is 0. This also - * equals sqrt(1/4), a nice gain scaling for the four virtual points - * producing an "ambient" response. - */ - gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; - length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(length > 1.0f) - { - ALfloat pan[3] = { - ReflectionsPan[0] / length, - ReflectionsPan[1] / length, - -ReflectionsPan[2] / length, - }; - for(i = 0;i < 4;i++) - { - ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; - } - } - else if(length > FLT_EPSILON) - { - for(i = 0;i < 4;i++) - { - ALfloat dotp = ReflectionsPan[0]*PanDirs[i][0] + ReflectionsPan[1]*PanDirs[i][1] + - -ReflectionsPan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; - } - } - for(i = 0;i < 4;i++) + // Band-pass and modulate the incoming samples. + for(i = 0;i < todo;i++) { - CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Early.PanGain[i]); - } + ALfloat sample = input[i]; + sample = ALfilterState_processSingle(&State->LpFilter, sample); + sample = ALfilterState_processSingle(&State->HpFilter, sample); - gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; - length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(length > 1.0f) - { - ALfloat pan[3] = { - LateReverbPan[0] / length, - LateReverbPan[1] / length, - -LateReverbPan[2] / length, - }; - length = 1.0f; - for(i = 0;i < 4;i++) - { - ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; - } - } - else if(length > FLT_EPSILON) - { - for(i = 0;i < 4;i++) - { - ALfloat dotp = LateReverbPan[0]*PanDirs[i][0] + LateReverbPan[1]*PanDirs[i][1] + - -LateReverbPan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; - } + // Perform any modulation on the input. + sample = EAXModulation(State, State->Offset+i, sample); + + // Feed the initial delay line. + DelayLineIn(&State->Delay, State->Offset+i, sample); } - for(i = 0;i < 4;i++) + + // Calculate the early reflection from the first delay tap. + EarlyReflection(State, todo, early); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + for(i = 0;i < todo;i++) { - CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Late.PanGain[i]); + ALuint offset = State->Offset+i; + ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * + State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, offset, sample); } -} -static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) -{ - const ALeffectProps *props = &Slot->EffectProps; - ALuint frequency = Device->Frequency; - ALfloat lfscale, hfscale, hfRatio; - ALfloat gain, gainlf, gainhf; - ALfloat cw, x, y; + // Calculate the late reverb from the decorrelator taps. + LateReverb(State, todo, late); - if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) - State->IsEax = AL_TRUE; - else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) - State->IsEax = AL_FALSE; + // Calculate and mix in any echo. + EAXEcho(State, todo, late); - // Calculate the master filters - hfscale = props->Reverb.HFReference / frequency; - gainhf = maxf(props->Reverb.GainHF, 0.0001f); - ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, - gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); - lfscale = props->Reverb.LFReference / frequency; - gainlf = maxf(props->Reverb.GainLF, 0.0001f); - ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, - gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); + // Step all delays forward. + State->Offset += todo; +} - // Update the modulator line. - UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, - frequency, State); +static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +{ + ALfloat (*restrict early)[4] = State->EarlySamples; + ALfloat (*restrict late)[4] = State->ReverbSamples; + ALuint index, c, i, l; + ALfloat gain; - // Update the initial effect delay. - UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, - frequency, State); + /* Process reverb for these samples. */ + for(index = 0;index < SamplesToDo;) + { + ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); - // Update the early lines. - UpdateEarlyLines(props->Reverb.ReflectionsGain, - props->Reverb.LateReverbDelay, State); + VerbPass(State, todo, &SamplesIn[index], early, late); - // Update the decorrelator. - UpdateDecorrelator(props->Reverb.Density, frequency, State); + for(l = 0;l < 4;l++) + { + for(c = 0;c < NumChannels;c++) + { + gain = State->Early.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*late[i][l]; + } + } + } - // Get the mixing matrix coefficients (x and y). - CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); - // Then divide x into y to simplify the matrix calculation. - State->Late.MixCoeff = y / x; + index += todo; + } +} - // If the HF limit parameter is flagged, calculate an appropriate limit - // based on the air absorption parameter. - hfRatio = props->Reverb.DecayHFRatio; - if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) - hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, - props->Reverb.DecayTime); +static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +{ + ALfloat (*restrict early)[4] = State->EarlySamples; + ALfloat (*restrict late)[4] = State->ReverbSamples; + ALuint index, c, i, l; + ALfloat gain; - cw = cosf(F_TAU * hfscale); - // Update the late lines. - UpdateLateLines(props->Reverb.LateReverbGain, x, - props->Reverb.Density, props->Reverb.DecayTime, - props->Reverb.Diffusion, props->Reverb.EchoDepth, - hfRatio, cw, frequency, State); + /* Process reverb for these samples. */ + for(index = 0;index < SamplesToDo;) + { + ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); - // Update the echo line. - UpdateEchoLine(props->Reverb.LateReverbGain, - props->Reverb.EchoTime, props->Reverb.DecayTime, - props->Reverb.Diffusion, props->Reverb.EchoDepth, - hfRatio, cw, frequency, State); + EAXVerbPass(State, todo, &SamplesIn[index], early, late); - gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; - // Update early and late 3D panning. - if(Device->Hrtf || Device->FmtChans == DevFmtBFormat3D) - Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, State); - else - UpdateDirectPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, State); -} + for(l = 0;l < 4;l++) + { + for(c = 0;c < NumChannels;c++) + { + gain = State->Early.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*late[i][l]; + } + } + } + index += todo; + } +} -static ALvoid ALreverbState_Destruct(ALreverbState *State) +static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - free(State->SampleBuffer); - State->SampleBuffer = NULL; + if(State->IsEax) + ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); + else + ALreverbState_processStandard(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); } -DECLARE_DEFAULT_ALLOCATORS(ALreverbState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); - typedef struct ALreverbStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); -- cgit v1.2.3 From 538f2839d1d32e11b4dcf1636abb286b9a51b3e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 08:43:51 -0800 Subject: Apply the early and late reverb gains with the panning gains --- Alc/effects/reverb.c | 54 +++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7911e43b..8ae10a9a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -533,14 +533,13 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint freq State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); } -// Update the early reflections gain and line coefficients. -static ALvoid UpdateEarlyLines(ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State) +// Update the early reflections mix and line coefficients. +static ALvoid UpdateEarlyLines(ALfloat lateDelay, ALreverbState *State) { ALuint index; - // Calculate the early reflections gain (from the master effect gain, and - // reflections gain parameters) with a constant attenuation of 0.5. - State->Early.Gain = 0.5f * earlyGain; + // Calculate the early reflections with a constant attenuation of 0.5. + State->Early.Gain = 0.5f; // Calculate the gain (coefficient) for each early delay line using the // late delay time. This expands the early reflections to the start of @@ -571,8 +570,8 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat } } -// Update the late reverb gains, line lengths, and line coefficients. -static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +// Update the late reverb mix, line lengths, and line coefficients. +static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { ALfloat length; ALuint index; @@ -585,7 +584,7 @@ static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, A * echo is slightly stronger than the decorrelated echos in the reverb * tail. */ - State->Late.Gain = lateGain * xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); + State->Late.Gain = xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -635,7 +634,7 @@ static ALvoid UpdateLateLines(ALfloat lateGain, ALfloat xMix, ALfloat density, A // Update the echo gain, line offset, line coefficients, and mixing // coefficients. -static ALvoid UpdateEchoLine(ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +static ALvoid UpdateEchoLine(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); @@ -660,11 +659,11 @@ static ALvoid UpdateEchoLine(ALfloat lateGain, ALfloat echoTime, ALfloat decayTi /* Calculate the echo mixing coefficient. This is applied to the output mix * only, not the feedback. */ - State->Echo.MixCoeff = lateGain * echoDepth; + State->Echo.MixCoeff = echoDepth; } // Update the early and late 3D panning gains. -static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) { ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; ALfloat DirGains[MAX_OUTPUT_CHANNELS]; @@ -682,7 +681,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec { if(Device->ChannelName[i] == LFE) continue; - State->Early.PanGain[i&3][i] = AmbientGains[i]; + State->Early.PanGain[i&3][i] = AmbientGains[i] * EarlyGain; } } else @@ -704,7 +703,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec { if(Device->ChannelName[i] == LFE) continue; - State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; } } @@ -716,7 +715,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec { if(Device->ChannelName[i] == LFE) continue; - State->Late.PanGain[i&3][i] = AmbientGains[i]; + State->Late.PanGain[i&3][i] = AmbientGains[i] * LateGain; } } else @@ -734,12 +733,12 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec { if(Device->ChannelName[i] == LFE) continue; - State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length); + State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; } } } -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) { static const ALfloat PanDirs[4][3] = { { -0.707106781f, 0.0f, -0.707106781f }, /* Front left */ @@ -783,7 +782,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Early.PanGain[i]); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, + Gain*EarlyGain*gain[i], State->Early.PanGain[i]); } gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; @@ -814,7 +814,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain*gain[i], State->Late.PanGain[i]); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, + Gain*LateGain*gain[i], State->Late.PanGain[i]); } } @@ -850,8 +851,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device frequency, State); // Update the early lines. - UpdateEarlyLines(props->Reverb.ReflectionsGain, - props->Reverb.LateReverbDelay, State); + UpdateEarlyLines(props->Reverb.LateReverbDelay, State); // Update the decorrelator. UpdateDecorrelator(props->Reverb.Density, frequency, State); @@ -870,14 +870,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device cw = cosf(F_TAU * hfscale); // Update the late lines. - UpdateLateLines(props->Reverb.LateReverbGain, x, - props->Reverb.Density, props->Reverb.DecayTime, + UpdateLateLines(x, props->Reverb.Density, props->Reverb.DecayTime, props->Reverb.Diffusion, props->Reverb.EchoDepth, hfRatio, cw, frequency, State); // Update the echo line. - UpdateEchoLine(props->Reverb.LateReverbGain, - props->Reverb.EchoTime, props->Reverb.DecayTime, + UpdateEchoLine(props->Reverb.EchoTime, props->Reverb.DecayTime, props->Reverb.Diffusion, props->Reverb.EchoDepth, hfRatio, cw, frequency, State); @@ -885,10 +883,14 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device // Update early and late 3D panning. if(Device->Hrtf || Device->FmtChans == DevFmtBFormat3D) Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, State); + props->Reverb.LateReverbPan, gain, + props->Reverb.ReflectionsGain, + props->Reverb.LateReverbGain, State); else UpdateDirectPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, State); + props->Reverb.LateReverbPan, gain, + props->Reverb.ReflectionsGain, + props->Reverb.LateReverbGain, State); } -- cgit v1.2.3 From 301d4c158b1f4a61ebbbd3b24c3b6c43708ce03e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 09:42:43 -0800 Subject: Update a couple outdated comments --- Alc/effects/reverb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 8ae10a9a..4c91c53c 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -576,8 +576,7 @@ static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat length; ALuint index; - /* Calculate the late reverb gain (from the master effect gain, and late - * reverb gain parameters). Since the output is tapped prior to the + /* Calculate the late reverb gain. Since the output is tapped prior to the * application of the next delay line coefficients, this gain needs to be * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate * the late reverb when echo depth is high and diffusion is low, so the @@ -1104,7 +1103,6 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res // Output the results of the matrix for all four channels, attenuated by // the late reverb gain (which is attenuated by the 'x' mix coefficient). - // Mix early reflections and late reverb. out[i][0] = State->Late.Gain * f[0]; out[i][1] = State->Late.Gain * f[1]; out[i][2] = State->Late.Gain * f[2]; -- cgit v1.2.3 From 3cac4dff95b7bf5c95c0fa7b70dc3423d4694b24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 09:55:08 -0800 Subject: Boost the direct-pan reverb to better match the expected volume Hopefully. Would be nice to have a reference implementation for this style of reverb to compare with. --- Alc/effects/reverb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 4c91c53c..74388c13 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -670,6 +670,8 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec ALfloat length; ALuint i; + /* Apply a boost of about 3dB to better match the expected stereo output volume. */ + Gain *= 1.414213562f; ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain, AmbientGains); memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); -- cgit v1.2.3 From 127c7e3b8cb949dc405660e9429ff4e8b475bf60 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 11:06:10 -0800 Subject: Don't explicitly check for LFE It's going to be set to 0 gain anyway --- Alc/effects/reverb.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 74388c13..ddf4689b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -679,11 +679,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec if(!(length > FLT_EPSILON)) { for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; State->Early.PanGain[i&3][i] = AmbientGains[i] * EarlyGain; - } } else { @@ -701,11 +697,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec CalcDirectionCoeffs(pan, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; - } } memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); @@ -713,11 +705,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec if(!(length > FLT_EPSILON)) { for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; State->Late.PanGain[i&3][i] = AmbientGains[i] * LateGain; - } } else { @@ -731,11 +719,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec CalcDirectionCoeffs(pan, coeffs); ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); for(i = 0;i < Device->NumChannels;i++) - { - if(Device->ChannelName[i] == LFE) - continue; State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; - } } } -- cgit v1.2.3 From c533060875d37021462c9f6e034a724dffeb3fa4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 14:07:53 -0800 Subject: Remove an unnecessary variable and move duplicate code to a common spot --- Alc/effects/reverb.c | 60 ++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ddf4689b..7fe8c8b6 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -71,7 +71,7 @@ typedef struct ALreverbState { ALfloat Depth; ALfloat Coeff; ALfloat Filter; - } Mod; + } Mod; // EAX only // Initial effect delay. DelayLine Delay; @@ -80,9 +80,6 @@ typedef struct ALreverbState { ALuint DelayTap[2]; struct { - // Output gain for early reflections. - ALfloat Gain; - // Early reflections are done with 4 delay lines. ALfloat Coeff[4]; DelayLine Delay[4]; @@ -152,7 +149,7 @@ typedef struct ALreverbState { // Echo mixing coefficient. ALfloat MixCoeff; - } Echo; + } Echo; // EAX only // The current read offset for all delay lines. ALuint Offset; @@ -538,9 +535,6 @@ static ALvoid UpdateEarlyLines(ALfloat lateDelay, ALreverbState *State) { ALuint index; - // Calculate the early reflections with a constant attenuation of 0.5. - State->Early.Gain = 0.5f; - // Calculate the gain (coefficient) for each early delay line using the // late delay time. This expands the early reflections to the start of // the late reverb. @@ -975,11 +969,13 @@ static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat DelayLineIn(&State->Early.Delay[2], offset, f[2]); DelayLineIn(&State->Early.Delay[3], offset, f[3]); - // Output the results of the junction for all four channels. - out[i][0] = State->Early.Gain * f[0]; - out[i][1] = State->Early.Gain * f[1]; - out[i][2] = State->Early.Gain * f[2]; - out[i][3] = State->Early.Gain * f[3]; + /* Output the results of the junction for all four channels with a + * constant attenuation of 0.5. + */ + out[i][0] = f[0] * 0.5f; + out[i][1] = f[1] * 0.5f; + out[i][2] = f[2] * 0.5f; + out[i][3] = f[3] * 0.5f; } } @@ -1022,18 +1018,29 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res ALfloat d[4], f[4]; ALuint i; + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; + ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * + State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, offset, sample); + } + for(i = 0;i < todo;i++) { ALuint offset = State->Offset+i; + /* Obtain four decorrelated input samples. */ f[0] = DelayLineOut(&State->Decorrelator, offset); f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); - // Obtain the decayed results of the cyclical delay lines, and add the - // corresponding input channels. Then pass the results through the - // low-pass filters. + /* Add the decayed results of the cyclical delay lines, then pass the + * results through the low-pass filters. + */ f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; @@ -1156,16 +1163,6 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat * // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); - // Feed the decorrelator from the energy-attenuated output of the second - // delay tap. - for(i = 0;i < todo;i++) - { - ALuint offset = State->Offset+i; - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); - } - // Calculate the late reverb from the decorrelator taps. LateReverb(State, todo, late); @@ -1196,16 +1193,6 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); - // Feed the decorrelator from the energy-attenuated output of the second - // delay tap. - for(i = 0;i < todo;i++) - { - ALuint offset = State->Offset+i; - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); - } - // Calculate the late reverb from the decorrelator taps. LateReverb(State, todo, late); @@ -1331,7 +1318,6 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f 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; -- cgit v1.2.3 From 3ee42d9826ba6e1d4ee49e76fa56a4e6f4f1df68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Feb 2016 15:39:31 -0800 Subject: Avoid an extra sample of delay in the reverb modulator --- Alc/effects/reverb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7fe8c8b6..f63d3591 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -911,14 +911,16 @@ static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat State->Mod.Coeff); // Calculate the read offset and fraction between it and the next sample. - frac = modff(State->Mod.Filter*sinus + 1.0f, &fdelay); + frac = modff(State->Mod.Filter*sinus, &fdelay); delay = fastf2u(fdelay); - // Get the two samples crossed by the offset, and feed the delay line - // with the next input sample. + /* Add the incoming sample to the delay line first, so a 0 delay gets the + * incoming sample. + */ + DelayLineIn(&State->Mod.Delay, offset, in); + /* Get the two samples crossed by the offset delay */ out0 = DelayLineOut(&State->Mod.Delay, offset - delay); out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); - DelayLineIn(&State->Mod.Delay, offset, in); // The output is obtained by linearly interpolating the two samples that // were acquired above. -- cgit v1.2.3 From fd54f4f03d4bad4f06e334089a3707f71f801d6a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Feb 2016 18:05:27 -0800 Subject: Only apply the +3dB reverb gain boost to the ambient response. --- Alc/effects/reverb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f63d3591..6f7c7655 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -665,8 +665,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec ALuint i; /* Apply a boost of about 3dB to better match the expected stereo output volume. */ - Gain *= 1.414213562f; - ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain, AmbientGains); + ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain*1.414213562f, AmbientGains); memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); -- cgit v1.2.3 From 6105d36fd79357053b8bbe7af207a58be8a73f04 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Feb 2016 22:54:03 -0800 Subject: Add special HRTF handling for reverb This is pretty hacky. Since HRTF normally renders to B-Format with two "extra" channels for the real stereo output, the panning interpolates between a panned reverb channel on B-Format, and two non-panned reverb channels on stereo output, given the panning vector length. --- Alc/effects/reverb.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 6f7c7655..d1419d82 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -48,6 +48,7 @@ typedef struct ALreverbState { DERIVE_FROM_TYPE(ALeffectState); ALboolean IsEax; + ALuint ExtraChannels; // For HRTF // All delay lines are allocated as a single buffer to reduce memory // fragmentation and management code. @@ -363,6 +364,8 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; + State->ExtraChannels = (Device->Hrtf ? 2 : 0); + // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the // resulting filter response over time is consistent across all sample @@ -656,6 +659,70 @@ static ALvoid UpdateEchoLine(ALfloat echoTime, ALfloat decayTime, ALfloat diffus } // Update the early and late 3D panning gains. +static ALvoid UpdateHrtfPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) +{ + ALfloat DirGains[MAX_OUTPUT_CHANNELS]; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat length; + ALuint i; + + /* With HRTF, the normal output provides a panned reverb channel when a + * non-0-length vector is specified, while the real stereo output provides + * two other "direct" non-panned reverb channels. + */ + memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < 2;i++) + State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain; + } + else + { + /* Note that EAX Reverb's panning vectors are using right-handed + * coordinates, rather that the OpenAL's left-handed coordinates. + * Negate Z to fix this. + */ + ALfloat pan[3] = { + ReflectionsPan[0] / length, + ReflectionsPan[1] / length, + -ReflectionsPan[2] / length, + }; + length = minf(length, 1.0f); + + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->NumChannels;i++) + State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; + for(i = 0;i < 2;i++) + State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain * (1.0f-length); + } + + memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < 2;i++) + State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain; + } + else + { + ALfloat pan[3] = { + LateReverbPan[0] / length, + LateReverbPan[1] / length, + -LateReverbPan[2] / length, + }; + length = minf(length, 1.0f); + + CalcDirectionCoeffs(pan, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->NumChannels;i++) + State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; + for(i = 0;i < 2;i++) + State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain * (1.0f-length); + } +} + static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) { ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; @@ -859,7 +926,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf || Device->FmtChans == DevFmtBFormat3D) + if(Device->Hrtf) + UpdateHrtfPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, + props->Reverb.ReflectionsGain, + props->Reverb.LateReverbGain, State); + else if(Device->FmtChans == DevFmtBFormat3D) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, @@ -1280,6 +1352,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { + NumChannels += State->ExtraChannels; if(State->IsEax) ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); else @@ -1300,6 +1373,9 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f if(!state) return NULL; SET_VTABLE2(ALreverbState, ALeffectState, state); + state->IsEax = AL_FALSE; + state->ExtraChannels = 0; + state->TotalSamples = 0; state->SampleBuffer = NULL; -- cgit v1.2.3 From f4fa41487c18ece49fddb512e3d9253e6eb1e92b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Feb 2016 16:14:27 -0800 Subject: Replace some CreateEvent calls with CreateEventW --- Alc/backends/dsound.c | 2 +- Alc/backends/mmdevapi.c | 12 ++++++------ common/threads.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index f27ab37b..c01e42ae 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -357,7 +357,7 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de } hr = DS_OK; - self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if(self->NotifyEvent == NULL) hr = E_FAIL; diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 0134a46c..c47ddee6 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -672,8 +672,8 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi { HRESULT hr = S_OK; - self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if(self->NotifyEvent == NULL || self->MsgEvent == NULL) { ERR("Failed to create message events: %lu\n", GetLastError()); @@ -1308,8 +1308,8 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device { HRESULT hr = S_OK; - self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if(self->NotifyEvent == NULL || self->MsgEvent == NULL) { ERR("Failed to create message events: %lu\n", GetLastError()); @@ -1739,7 +1739,7 @@ static BOOL MMDevApiLoad(void) ThreadRequest req; InitResult = E_FAIL; - req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL); + req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); if(req.FinishedEvt == NULL) ERR("Failed to create event: %lu\n", GetLastError()); else @@ -1796,7 +1796,7 @@ static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory* UNUSED(self), e { ThreadRequest req = { NULL, 0 }; - req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL); + req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); if(req.FinishedEvt == NULL) ERR("Failed to create event: %lu\n", GetLastError()); else diff --git a/common/threads.c b/common/threads.c index 127b9083..6272dd9f 100644 --- a/common/threads.c +++ b/common/threads.c @@ -306,8 +306,8 @@ int alcnd_init(alcnd_t *cond) InitRef(&icond->wait_count, 0); - icond->events[SIGNAL] = CreateEvent(NULL, FALSE, FALSE, NULL); - icond->events[BROADCAST] = CreateEvent(NULL, TRUE, FALSE, NULL); + icond->events[SIGNAL] = CreateEventW(NULL, FALSE, FALSE, NULL); + icond->events[BROADCAST] = CreateEventW(NULL, TRUE, FALSE, NULL); if(!icond->events[SIGNAL] || !icond->events[BROADCAST]) { if(icond->events[SIGNAL]) -- cgit v1.2.3 From 000ced37951795d4ded85b37a5337dbfdee90be1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Feb 2016 17:47:52 -0800 Subject: Avoid underflow in alcnd_timedwait if the time point is already passed --- common/threads.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/common/threads.c b/common/threads.c index 6272dd9f..5a177a2c 100644 --- a/common/threads.c +++ b/common/threads.c @@ -264,10 +264,19 @@ int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_poi if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) return althrd_error; - sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; - sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000; - if(SleepConditionVariableCS(cond, mtx, sleeptime) != 0) - return althrd_success; + if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && + curtime.tv_nsec >= time_point->tv_nsec)) + { + if(SleepConditionVariableCS(cond, mtx, 0) != 0) + return althrd_success; + } + else + { + sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; + sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000; + if(SleepConditionVariableCS(cond, mtx, sleeptime) != 0) + return althrd_success; + } return (GetLastError()==ERROR_TIMEOUT) ? althrd_timedout : althrd_error; } @@ -364,8 +373,15 @@ int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_poi if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) return althrd_error; - sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; - sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000; + + if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && + curtime.tv_nsec >= time_point->tv_nsec)) + sleeptime = 0; + else + { + sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; + sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000; + } IncrementRef(&icond->wait_count); LeaveCriticalSection(mtx); -- cgit v1.2.3 From a9135ec39d8722502e92fc5141661c3479d877d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Feb 2016 21:42:24 -0800 Subject: Don't pass the channel count to GetBFormatHrtfCoeffs Since it's hard-coded anyway, there's no need to specify it. --- Alc/hrtf.c | 10 ++++------ Alc/hrtf.h | 2 +- Alc/panning.c | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 467232d7..43a111bb 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -319,15 +319,13 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a * Note that these will decode a B-Format output mix, which uses FuMa ordering * and scaling, not N3D! */ -void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list) +void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat (*coeffs_list[4])[2], ALuint *delay_list[4]) { ALuint elev_idx, azi_idx; ALfloat scale; ALuint i, c; - assert(num_chans <= 4); - - for(c = 0;c < num_chans;c++) + for(c = 0;c < 4;c++) { ALfloat (*coeffs)[2] = coeffs_list[c]; ALuint *delay = delay_list[c]; @@ -377,7 +375,7 @@ void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALflo ambi_coeffs[2] = y; ambi_coeffs[3] = z; - for(c = 0;c < num_chans;c++) + for(c = 0;c < 4;c++) { ALfloat (*coeffs)[2] = coeffs_list[c]; ALuint *delay = delay_list[c]; @@ -402,7 +400,7 @@ void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALflo scale = 1.0f/scale; - for(c = 0;c < num_chans;c++) + for(c = 0;c < 4;c++) { ALfloat (*coeffs)[2] = coeffs_list[c]; ALuint *delay = delay_list[c]; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 6dcd6948..9f3f0ade 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -35,6 +35,6 @@ ALuint GetHrtfIrSize(const struct Hrtf *Hrtf); void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep); -void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list); +void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat (*coeffs_list[4])[2], ALuint *delay_list[4]); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 8464efd6..5013ec16 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -505,7 +505,7 @@ ALvoid aluInitPanning(ALCdevice *device) coeffs_list[i] = device->Hrtf_Params[chan].Coeffs; delay_list[i] = device->Hrtf_Params[chan].Delay; } - GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list); + GetBFormatHrtfCoeffs(device->Hrtf, coeffs_list, delay_list); return; } -- cgit v1.2.3 From 25732d0895cc4d320472fc50cd74302d91b24a0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Feb 2016 01:22:01 -0800 Subject: Calculate channel gain stepping just before mixing --- Alc/ALc.c | 8 -- Alc/ALu.c | 282 +++++++++----------------------------------- Alc/mixer.c | 99 ++++++++++++++-- OpenAL32/Include/alSource.h | 3 + OpenAL32/Include/alu.h | 20 ++-- OpenAL32/alSource.c | 9 +- 6 files changed, 165 insertions(+), 256 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f69f6ecc..d116650f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2155,14 +2155,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALvoice *voice = &context->Voices[pos]; ALsource *source = voice->Source; - ALuint s = device->NumAuxSends; - - while(s < MAX_SENDS) - { - voice->Send[s].Moving = AL_FALSE; - voice->Send[s].Counter = 0; - s++; - } if(source) { diff --git a/Alc/ALu.c b/Alc/ALu.c index e0c96175..4b1f0164 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -323,85 +323,6 @@ static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *o } -static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps) -{ - ALfloat delta; - ALuint i, j; - - if(steps < 2) - { - for(i = 0;i < num_chans;i++) - { - MixGains *gains = params->Gains[i]; - for(j = 0;j < params->OutChannels;j++) - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - params->Counter = 0; - return; - } - - delta = 1.0f / (ALfloat)steps; - for(i = 0;i < num_chans;i++) - { - MixGains *gains = params->Gains[i]; - for(j = 0;j < params->OutChannels;j++) - { - ALfloat diff = gains[j].Target - gains[j].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = diff * delta; - else - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - } - params->Counter = steps; -} - -static void UpdateWetStepping(SendParams *params, ALuint num_chans, ALuint steps) -{ - ALfloat delta; - ALuint i, j; - - if(steps < 2) - { - for(i = 0;i < num_chans;i++) - { - MixGains *gains = params->Gains[i]; - for(j = 0;j < params->OutChannels;j++) - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - params->Counter = 0; - return; - } - - delta = 1.0f / (ALfloat)steps; - for(i = 0;i < num_chans;i++) - { - MixGains *gains = params->Gains[i]; - for(j = 0;j < params->OutChannels;j++) - { - ALfloat diff = gains[j].Target - gains[j].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = diff * delta; - else - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - } - params->Counter = steps; -} - - static ALvoid CalcListenerParams(ALlistener *Listener) { ALdouble N[3], V[3], U[3], P[3]; @@ -659,16 +580,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ); for(c = 0;c < num_channels;c++) - { - MixGains *gains = voice->Direct.Gains[c]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - - ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, Target); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - gains[i].Target = Target[i]; - } - UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); - voice->Direct.Moving = AL_TRUE; + ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, + voice->Direct.Gains[c].Target); /* Rebuild the matrix, without the second- or third-order output * scaling (effects take first-order content, and will do the scaling @@ -684,9 +597,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { for(c = 0;c < num_channels;c++) { - MixGains *gains = voice->Send[i].Gains[c]; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[c].Target[j] = 0.0f; } } else @@ -694,24 +606,18 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A for(c = 0;c < num_channels;c++) { const ALeffectslot *Slot = SendSlots[i]; - MixGains *gains = voice->Send[i].Gains[c]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - ALuint j; - - ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, - matrix.m[c], WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c], + WetGain[i], voice->Send[i].Gains[c].Target); } } - UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; } voice->IsHrtf = AL_FALSE; } else { + ALfloat coeffs[MAX_AMBI_COEFFS]; + if(DirectChannels) { if(Device->Hrtf) @@ -724,65 +630,46 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.OutChannels = 2; for(c = 0;c < num_channels;c++) { - MixGains *gains = voice->Direct.Gains[c]; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Direct.Gains[c].Target[j] = 0.0f; if(chans[c].channel == FrontLeft) - gains[0].Target = DryGain; + voice->Direct.Gains[c].Target[0] = DryGain; else if(chans[c].channel == FrontRight) - gains[1].Target = DryGain; + voice->Direct.Gains[c].Target[1] = DryGain; } } else for(c = 0;c < num_channels;c++) { - MixGains *gains = voice->Direct.Gains[c]; int idx; - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Direct.Gains[c].Target[j] = 0.0f; if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) - gains[idx].Target = DryGain; + voice->Direct.Gains[c].Target[idx] = DryGain; } /* Auxiliary sends still use normal panning since they mix to B-Format, which can't * channel-match. */ for(c = 0;c < num_channels;c++) { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[c]; if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[c].Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - ALuint j; - - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, - coeffs, WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } - UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); - voice->Direct.Moving = AL_TRUE; - for(i = 0;i < NumSends;i++) - { - UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; - } - voice->IsHrtf = AL_FALSE; } else if(Device->Hrtf_Mode == FullHrtf) @@ -804,54 +691,42 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f; voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f; } + + for(i = 0;i < NumSends;i++) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Gains[c].Target[j] = 0.0f; + } + + continue; } - else - { - /* Get the static HRIR coefficients and delays for this - * channel. */ - GetLerpedHrtfCoeffs(Device->Hrtf, - chans[c].elevation, chans[c].angle, 1.0f, DryGain, - voice->Direct.Hrtf[c].Params.Coeffs, - voice->Direct.Hrtf[c].Params.Delay - ); - } - } - voice->Direct.Counter = 0; - voice->Direct.Moving = AL_TRUE; - /* Normal panning for auxiliary sends. */ - for(c = 0;c < num_channels;c++) - { - ALfloat coeffs[MAX_AMBI_COEFFS]; + /* Get the static HRIR coefficients and delays for this channel. */ + GetLerpedHrtfCoeffs(Device->Hrtf, + chans[c].elevation, chans[c].angle, 1.0f, DryGain, + voice->Direct.Hrtf[c].Params.Coeffs, + voice->Direct.Hrtf[c].Params.Delay + ); + /* Normal panning for auxiliary sends. */ CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[c]; if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[c].Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - ALuint j; - - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, - coeffs, WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } - for(i = 0;i < NumSends;i++) - { - UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; - } + voice->Direct.HrtfCounter = 0; voice->IsHrtf = AL_TRUE; } @@ -860,64 +735,45 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Basic or no HRTF rendering. Use normal panning to the output. */ for(c = 0;c < num_channels;c++) { - MixGains *gains = voice->Direct.Gains[c]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - ALfloat coeffs[MAX_AMBI_COEFFS]; - /* Special-case LFE */ if(chans[c].channel == LFE) { int idx; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - gains[i].Target = 0.0f; + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Gains[c].Target[j] = 0.0f; if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) - gains[idx].Target = DryGain; + voice->Direct.Gains[c].Target[idx] = DryGain; for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[c]; ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[c].Target[j] = 0.0f; } continue; } CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, Target); - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - gains[i].Target = Target[i]; + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, voice->Direct.Gains[c].Target); for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[c]; - ALuint j; - if(!SendSlots[i]) { + ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[c].Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, - coeffs, WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } - UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); - voice->Direct.Moving = AL_TRUE; - for(i = 0;i < NumSends;i++) - { - UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; - } - voice->IsHrtf = AL_FALSE; } } @@ -995,7 +851,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat Pitch; ALuint Frequency; ALint NumSends; - ALint i, j; + ALint i; DryGainHF = 1.0f; DryGainLF = 1.0f; @@ -1304,7 +1160,6 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; ALfloat dirfact = 1.0f; - ALfloat Target[MAX_OUTPUT_CHANNELS]; ALfloat coeffs[MAX_AMBI_COEFFS]; voice->Direct.OutBuffer += voice->Direct.OutChannels; @@ -1332,7 +1187,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } /* Check to see if the HRIR is already moving. */ - if(voice->Direct.Moving) + if(voice->Moving) { ALfloat delta; delta = CalcFadeTime(voice->Direct.LastGain, DryGain, @@ -1343,11 +1198,11 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte if(delta > 0.000015f) { ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf, - ev, az, dirfact, DryGain, delta, voice->Direct.Counter, + ev, az, dirfact, DryGain, delta, voice->Direct.HrtfCounter, voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay, voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep ); - voice->Direct.Counter = counter; + voice->Direct.HrtfCounter = counter; voice->Direct.LastGain = DryGain; voice->Direct.LastDir = dir; } @@ -1358,8 +1213,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay); - voice->Direct.Counter = 0; - voice->Direct.Moving = AL_TRUE; + voice->Direct.HrtfCounter = 0; voice->Direct.LastGain = DryGain; voice->Direct.LastDir = dir; } @@ -1371,25 +1225,18 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[0]; - ALuint j; - if(!SendSlots[i]) { + ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[0].Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, - coeffs, WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[0].Target); } - - UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; } voice->IsHrtf = AL_TRUE; @@ -1397,10 +1244,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { /* Basic or no HRTF rendering. Use normal panning to the output. */ - MixGains *gains = voice->Direct.Gains[0]; ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; - ALfloat Target[MAX_OUTPUT_CHANNELS]; ALfloat coeffs[MAX_AMBI_COEFFS]; /* Get the localized direction, and compute panned gains. */ @@ -1423,34 +1268,23 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, Target); - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - gains[j].Target = Target[j]; - - UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0)); - voice->Direct.Moving = AL_TRUE; + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, + voice->Direct.Gains[0].Target); for(i = 0;i < NumSends;i++) { - MixGains *gains = voice->Send[i].Gains[0]; - ALuint j; - if(!SendSlots[i]) { + ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = 0.0f; + voice->Send[i].Gains[0].Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, - coeffs, WetGain[i], Target); - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - gains[j].Target = Target[j]; + ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[0].Target); } - - UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); - voice->Send[i].Moving = AL_TRUE; } voice->IsHrtf = AL_FALSE; diff --git a/Alc/mixer.c b/Alc/mixer.c index ddcf6f6b..4688c89e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -401,6 +401,19 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos = 0; do { ALuint SrcBufferSize, DstBufferSize; + ALuint Counter; + ALfloat Delta; + + if(!voice->Moving) + { + Counter = 0; + Delta = 0.0f; + } + else + { + Counter = SamplesToDo - OutPos; + Delta = 1.0f / (ALfloat)Counter; + } /* Figure out how many buffer samples will be needed */ DataSize64 = SamplesToDo-OutPos; @@ -549,10 +562,46 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam parms->Filters[chan].ActiveType ); if(!voice->IsHrtf) - MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan], - parms->Counter, OutPos, DstBufferSize); + { + ALfloat *restrict currents = parms->Gains[chan].Current; + const ALfloat *targets = parms->Gains[chan].Target; + MixGains gains[MAX_OUTPUT_CHANNELS]; + + if(!Counter) + { + for(j = 0;j < parms->OutChannels;j++) + { + gains[j].Target = targets[j]; + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + else + { + for(j = 0;j < parms->OutChannels;j++) + { + ALfloat diff; + gains[j].Target = targets[j]; + gains[j].Current = currents[j]; + diff = gains[j].Target - gains[j].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + gains[j].Step = diff * Delta; + else + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + } + + MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains, + Counter, OutPos, DstBufferSize); + + for(j = 0;j < parms->OutChannels;j++) + currents[j] = gains[j].Current; + } else - MixHrtfSamples(parms->OutBuffer, samples, parms->Counter, voice->Offset, + MixHrtfSamples(parms->OutBuffer, samples, parms->HrtfCounter, voice->Offset, OutPos, IrSize, &parms->Hrtf[chan].Params, &parms->Hrtf[chan].State, DstBufferSize); } @@ -560,6 +609,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam for(j = 0;j < Device->NumAuxSends;j++) { SendParams *parms = &voice->Send[j]; + ALfloat *restrict currents = parms->Gains[chan].Current; + const ALfloat *targets = parms->Gains[chan].Target; + MixGains gains[MAX_OUTPUT_CHANNELS]; const ALfloat *samples; if(!parms->OutBuffer) @@ -570,8 +622,39 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Device->FilteredData, ResampledData, DstBufferSize, parms->Filters[chan].ActiveType ); - MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan], - parms->Counter, OutPos, DstBufferSize); + + if(!Counter) + { + for(j = 0;j < parms->OutChannels;j++) + { + gains[j].Target = targets[j]; + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + else + { + for(j = 0;j < parms->OutChannels;j++) + { + ALfloat diff; + gains[j].Target = targets[j]; + gains[j].Current = currents[j]; + diff = gains[j].Target - gains[j].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + gains[j].Step = diff * Delta; + else + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + } + + MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains, + Counter, OutPos, DstBufferSize); + + for(j = 0;j < parms->OutChannels;j++) + currents[j] = gains[j].Current; } } /* Update positions */ @@ -581,9 +664,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos += DstBufferSize; voice->Offset += DstBufferSize; - voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize; - for(j = 0;j < Device->NumAuxSends;j++) - voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize; + voice->Direct.HrtfCounter = maxu(voice->Direct.HrtfCounter, DstBufferSize) - DstBufferSize; /* Handle looping sources */ while(1) @@ -630,6 +711,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } while(State == AL_PLAYING && OutPos < SamplesToDo); + voice->Moving = AL_TRUE; + /* Update source info */ Source->state = State; ATOMIC_STORE(&Source->current_buffer, BufferListItem); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 253cd05f..bf589e8d 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -30,6 +30,9 @@ typedef struct ALvoice { /** Current target parameters used for mixing. */ ALint Step; + /* If not 'moving', gain/coefficients are set directly without fading. */ + ALboolean Moving; + ALboolean IsHrtf; ALuint Offset; /* Number of output samples mixed since starting. */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index eb2ea534..50ef1f5e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -143,13 +143,10 @@ typedef struct DirectParams { ALfloat (*OutBuffer)[BUFFERSIZE]; ALuint OutChannels; - /* If not 'moving', gain/coefficients are set directly without fading. */ - ALboolean Moving; - /* Stepping counter for gain/coefficient fading. */ - ALuint Counter; /* Last direction (relative to listener) and gain of a moving source. */ aluVector LastDir; ALfloat LastGain; + ALuint HrtfCounter; struct { enum ActiveFilters ActiveType; @@ -161,22 +158,27 @@ typedef struct DirectParams { HrtfParams Params; HrtfState State; } Hrtf[MAX_INPUT_CHANNELS]; - MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS]; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains[MAX_INPUT_CHANNELS]; } DirectParams; typedef struct SendParams { ALfloat (*OutBuffer)[BUFFERSIZE]; ALuint OutChannels; - ALboolean Moving; - ALuint Counter; - struct { enum ActiveFilters ActiveType; ALfilterState LowPass; ALfilterState HighPass; } Filters[MAX_INPUT_CHANNELS]; - MixGains Gains[MAX_INPUT_CHANNELS][MAX_EFFECT_CHANNELS]; + + struct { + ALfloat Current[MAX_OUTPUT_CHANNELS]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; + } Gains[MAX_INPUT_CHANNELS]; } SendParams; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index d31a0377..f742e1fe 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2640,8 +2640,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(discontinuity) memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - voice->Direct.Moving = AL_FALSE; - voice->Direct.Counter = 0; + voice->Moving = AL_FALSE; + voice->Direct.HrtfCounter = 0; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { ALsizei j; @@ -2653,11 +2653,6 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f; } } - for(i = 0;i < (ALsizei)device->NumAuxSends;i++) - { - voice->Send[i].Moving = AL_FALSE; - voice->Send[i].Counter = 0; - } if(BufferList->buffer->FmtChannels == FmtMono) voice->Update = CalcSourceParams; -- cgit v1.2.3 From ecdc93f3ca3b12ab0b226864cf8cd579140f1484 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Feb 2016 03:23:06 -0800 Subject: Calculate HRTF stepping params right before mixing This means we track the current params and the target params, rather than the target params and the stepping. This closer matches the non-HRTF mixers. --- Alc/ALu.c | 93 ++++++-------------------------- Alc/hrtf.c | 134 ---------------------------------------------- Alc/hrtf.h | 1 - Alc/mixer.c | 40 ++++++++++++-- Alc/mixer_c.c | 12 ----- Alc/mixer_defs.h | 8 +-- Alc/mixer_inc.c | 58 ++++++++++---------- Alc/mixer_neon.c | 19 ------- Alc/mixer_sse.c | 17 ------ OpenAL32/Include/alMain.h | 2 - OpenAL32/Include/alu.h | 18 ++++--- OpenAL32/alSource.c | 1 - 12 files changed, 99 insertions(+), 304 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 4b1f0164..b36e2248 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -287,42 +287,6 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) } -/* Calculates the fade time from the changes in gain and listener to source - * angle between updates. The result is a the time, in seconds, for the - * transition to complete. - */ -static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *olddir, const aluVector *newdir) -{ - ALfloat gainChange, angleChange, change; - - /* Calculate the normalized dB gain change. */ - newGain = maxf(newGain, 0.0001f); - oldGain = maxf(oldGain, 0.0001f); - gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f)); - - /* Calculate the angle change only when there is enough gain to notice it. */ - angleChange = 0.0f; - if(gainChange > 0.0001f || newGain > 0.0001f) - { - /* No angle change when the directions are equal or degenerate (when - * both have zero length). - */ - if(newdir->v[0] != olddir->v[0] || newdir->v[1] != olddir->v[1] || newdir->v[2] != olddir->v[2]) - { - ALfloat dotp = aluDotproduct(olddir, newdir); - angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI; - } - } - - /* Use the largest of the two changes, and apply a significance shaping - * function to it. The result is then scaled to cover a 15ms transition - * range. - */ - change = maxf(angleChange * 25.0f, gainChange) * 2.0f; - return minf(change, 1.0f) * 0.015f; -} - - static ALvoid CalcListenerParams(ALlistener *Listener) { ALdouble N[3], V[3], U[3], P[3]; @@ -684,12 +648,12 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A if(chans[c].channel == LFE) { /* Skip LFE */ - voice->Direct.Hrtf[c].Params.Delay[0] = 0; - voice->Direct.Hrtf[c].Params.Delay[1] = 0; + voice->Direct.Hrtf[c].Target.Delay[0] = 0; + voice->Direct.Hrtf[c].Target.Delay[1] = 0; for(i = 0;i < HRIR_LENGTH;i++) { - voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f; - voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f; + voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f; + voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f; } for(i = 0;i < NumSends;i++) @@ -704,8 +668,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Get the static HRIR coefficients and delays for this channel. */ GetLerpedHrtfCoeffs(Device->Hrtf, chans[c].elevation, chans[c].angle, 1.0f, DryGain, - voice->Direct.Hrtf[c].Params.Coeffs, - voice->Direct.Hrtf[c].Params.Delay + voice->Direct.Hrtf[c].Target.Coeffs, + voice->Direct.Hrtf[c].Target.Delay ); /* Normal panning for auxiliary sends. */ @@ -726,7 +690,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } } } - voice->Direct.HrtfCounter = 0; voice->IsHrtf = AL_TRUE; } @@ -1186,37 +1149,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte dirfact *= 1.0f - (asinf(radius / Distance) / F_PI); } - /* Check to see if the HRIR is already moving. */ - if(voice->Moving) - { - ALfloat delta; - delta = CalcFadeTime(voice->Direct.LastGain, DryGain, - &voice->Direct.LastDir, &dir); - /* If the delta is large enough, get the moving HRIR target - * coefficients, target delays, steppping values, and counter. - */ - if(delta > 0.000015f) - { - ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf, - ev, az, dirfact, DryGain, delta, voice->Direct.HrtfCounter, - voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay, - voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep - ); - voice->Direct.HrtfCounter = counter; - voice->Direct.LastGain = DryGain; - voice->Direct.LastDir = dir; - } - } - else - { - /* Get the initial (static) HRIR coefficients and delays. */ - GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, - voice->Direct.Hrtf[0].Params.Coeffs, - voice->Direct.Hrtf[0].Params.Delay); - voice->Direct.HrtfCounter = 0; - voice->Direct.LastGain = DryGain; - voice->Direct.LastDir = dir; - } + /* Get the HRIR coefficients and delays. */ + GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, + voice->Direct.Hrtf[0].Target.Coeffs, + voice->Direct.Hrtf[0].Target.Delay); dir.v[0] *= dirfact; dir.v[1] *= dirfact; @@ -1537,11 +1473,16 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { HrtfMixerFunc HrtfMix = SelectHrtfMixer(); ALuint irsize = GetHrtfIrSize(device->Hrtf); + MixHrtfParams hrtfparams; + memset(&hrtfparams, 0, sizeof(hrtfparams)); for(c = 0;c < device->NumChannels;c++) + { + hrtfparams.Current = &device->Hrtf_Params[c]; + hrtfparams.Target = &device->Hrtf_Params[c]; HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset, - 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c], - SamplesToDo + 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo ); + } device->Hrtf_Offset += SamplesToDo; } else if(device->Bs2b) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 43a111bb..33e58dfb 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -181,140 +181,6 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi } } -/* Calculates the moving HRIR target coefficients, target delays, and - * stepping values for the given polar elevation and azimuth in radians. - * Linear interpolation is used to increase the apparent resolution of the - * HRIR data set. The coefficients are also normalized and attenuated by the - * specified gain. Stepping resolution and count is determined using the - * given delta factor between 0.0 and 1.0. - */ -ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) -{ - ALuint evidx[2], lidx[4], ridx[4]; - ALfloat mu[3], blend[4]; - ALfloat left, right; - ALfloat steps; - ALuint i; - - /* Claculate elevation indices and interpolation factor. */ - CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]); - - for(i = 0;i < 2;i++) - { - ALuint azcount = Hrtf->azCount[evidx[i]]; - ALuint evoffset = Hrtf->evOffset[evidx[i]]; - ALuint azidx[2]; - - /* Calculate azimuth indices and interpolation factor for this elevation. */ - CalcAzIndices(azcount, azimuth, azidx, &mu[i]); - - /* Calculate a set of linear HRIR indices for left and right channels. */ - lidx[i*2 + 0] = evoffset + azidx[0]; - lidx[i*2 + 1] = evoffset + azidx[1]; - ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount); - ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount); - } - - // Calculate the stepping parameters. - steps = maxf(floorf(delta*Hrtf->sampleRate + 0.5f), 1.0f); - delta = 1.0f / steps; - - /* Calculate 4 blending weights for 2D bilinear interpolation. */ - blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); - blend[1] = ( mu[0]) * (1.0f-mu[2]); - blend[2] = (1.0f-mu[1]) * ( mu[2]); - blend[3] = ( mu[1]) * ( mu[2]); - - /* Calculate the HRIR delays using linear interpolation. Then calculate - * the delay stepping values using the target and previous running - * delays. - */ - left = (ALfloat)(delays[0] - (delayStep[0] * counter)); - right = (ALfloat)(delays[1] - (delayStep[1] * counter)); - - delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + - Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + - Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - - delayStep[0] = fastf2i(delta * (delays[0] - left)); - delayStep[1] = fastf2i(delta * (delays[1] - right)); - - /* Calculate the sample offsets for the HRIR indices. */ - lidx[0] *= Hrtf->irSize; - lidx[1] *= Hrtf->irSize; - lidx[2] *= Hrtf->irSize; - lidx[3] *= Hrtf->irSize; - ridx[0] *= Hrtf->irSize; - ridx[1] *= Hrtf->irSize; - ridx[2] *= Hrtf->irSize; - ridx[3] *= Hrtf->irSize; - - /* Calculate the normalized and attenuated target HRIR coefficients using - * linear interpolation when there is enough gain to warrant it. Zero - * the target coefficients if gain is too low. Then calculate the - * coefficient stepping values using the target and previous running - * coefficients. - */ - if(gain > 0.0001f) - { - ALfloat c; - - i = 0; - left = coeffs[i][0] - (coeffStep[i][0] * counter); - right = coeffs[i][1] - (coeffStep[i][1] * counter); - - c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + - Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); - c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + - Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); - - coeffStep[i][0] = delta * (coeffs[i][0] - left); - coeffStep[i][1] = delta * (coeffs[i][1] - right); - - for(i = 1;i < Hrtf->irSize;i++) - { - left = coeffs[i][0] - (coeffStep[i][0] * counter); - right = coeffs[i][1] - (coeffStep[i][1] * counter); - - c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + - Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); - c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + - Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); - - coeffStep[i][0] = delta * (coeffs[i][0] - left); - coeffStep[i][1] = delta * (coeffs[i][1] - right); - } - } - else - { - for(i = 0;i < Hrtf->irSize;i++) - { - left = coeffs[i][0] - (coeffStep[i][0] * counter); - right = coeffs[i][1] - (coeffStep[i][1] * counter); - - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - - coeffStep[i][0] = delta * -left; - coeffStep[i][1] = delta * -right; - } - } - - /* The stepping count is the number of samples necessary for the HRIR to - * complete its transition. The mixer will only apply stepping for this - * many samples. - */ - return fastf2u(steps); -} - - /* Calculates HRTF coefficients for B-Format channels (only up to first-order). * Note that these will decode a B-Format output mix, which uses FuMa ordering * and scaling, not N3D! diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 9f3f0ade..794d6abc 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -34,7 +34,6 @@ ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf); ALuint GetHrtfIrSize(const struct Hrtf *Hrtf); void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); -ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep); void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat (*coeffs_list[4])[2], ALuint *delay_list[4]); #endif /* ALC_HRTF_H */ diff --git a/Alc/mixer.c b/Alc/mixer.c index 4688c89e..6b5272ea 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -601,9 +601,42 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam currents[j] = gains[j].Current; } else - MixHrtfSamples(parms->OutBuffer, samples, parms->HrtfCounter, voice->Offset, - OutPos, IrSize, &parms->Hrtf[chan].Params, - &parms->Hrtf[chan].State, DstBufferSize); + { + MixHrtfParams hrtfparams; + if(!Counter) + { + parms->Hrtf[chan].Current = parms->Hrtf[chan].Target; + for(j = 0;j < HRIR_LENGTH;j++) + { + hrtfparams.Steps.Coeffs[j][0] = 0.0f; + hrtfparams.Steps.Coeffs[j][1] = 0.0f; + } + hrtfparams.Steps.Delay[0] = 0; + hrtfparams.Steps.Delay[1] = 0; + } + else + { + ALfloat coeffdiff; + ALint delaydiff; + for(j = 0;j < HRIR_LENGTH;j++) + { + coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][0] - parms->Hrtf[chan].Current.Coeffs[j][0]; + hrtfparams.Steps.Coeffs[j][0] = coeffdiff * Delta; + coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][1] - parms->Hrtf[chan].Current.Coeffs[j][1]; + hrtfparams.Steps.Coeffs[j][1] = coeffdiff * Delta; + } + delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[0] - parms->Hrtf[chan].Current.Delay[0]); + hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * Delta); + delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[1] - parms->Hrtf[chan].Current.Delay[1]); + hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * Delta); + } + hrtfparams.Target = &parms->Hrtf[chan].Target; + hrtfparams.Current = &parms->Hrtf[chan].Current; + + MixHrtfSamples(parms->OutBuffer, samples, Counter, voice->Offset, + OutPos, IrSize, &hrtfparams, &parms->Hrtf[chan].State, + DstBufferSize); + } } for(j = 0;j < Device->NumAuxSends;j++) @@ -664,7 +697,6 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos += DstBufferSize; voice->Offset += DstBufferSize; - voice->Direct.HrtfCounter = maxu(voice->Direct.HrtfCounter, DstBufferSize) - DstBufferSize; /* Handle looping sources */ while(1) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index ef37b730..e9d26140 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -101,18 +101,6 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const } -static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], - const HrtfParams *hrtfparams, - ALuint IrSize, ALuint Counter) -{ - ALuint c; - for(c = 0;c < IrSize;c++) - { - OutCoeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter); - OutCoeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter); - } -} - static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 3c32278b..3fecab87 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -8,7 +8,7 @@ struct MixGains; -struct HrtfParams; +struct MixHrtfParams; struct HrtfState; /* C resamplers */ @@ -23,7 +23,7 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, A /* C mixers */ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, + const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); @@ -31,7 +31,7 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B /* SSE mixers */ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, + const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); @@ -72,7 +72,7 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *sr /* Neon mixers */ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, + const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index a82930cc..d69becc9 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -6,11 +6,9 @@ #include "hrtf.h" #include "mixer_defs.h" #include "align.h" +#include "alu.h" -static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], - const HrtfParams *hrtfparams, - ALuint IrSize, ALuint Counter); static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint irSize, ALfloat (*restrict Coeffs)[2], @@ -24,39 +22,45 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize) + const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize) { - alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - ALuint Delay[2]; + ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; + ALuint Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; ALfloat left, right; ALuint pos; - SetupCoeffs(Coeffs, hrtfparams, IrSize, Counter); - Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter); - Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter); - pos = 0; - for(;pos < BufferSize && pos < Counter;pos++) + if(pos < Counter) { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; - left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], - (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], - (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + for(;pos < BufferSize && pos < Counter;pos++) + { + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; + left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], + hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], + (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], + hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], + (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - Delay[0] += hrtfparams->DelayStep[0]; - Delay[1] += hrtfparams->DelayStep[1]; + Delay[0] += hrtfparams->Steps.Delay[0]; + Delay[1] += hrtfparams->Steps.Delay[1]; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; - ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right); - OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; - OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; - OutPos++; + ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->Steps.Coeffs, left, right); + OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; + OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; + OutPos++; + } + + if(pos == Counter) + { + *hrtfparams->Current = *hrtfparams->Target; + Delay[0] = hrtfparams->Target->Delay[0]; + Delay[1] = hrtfparams->Target->Delay[1]; + } } Delay[0] >>= HRTFDELAY_BITS; diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index a89caeae..96936ef5 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -9,25 +9,6 @@ #include "hrtf.h" -static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], - const HrtfParams *hrtfparams, - ALuint IrSize, ALuint Counter) -{ - ALuint c; - float32x4_t counter4; - { - float32x2_t counter2 = vdup_n_f32(-(float)Counter); - counter4 = vcombine_f32(counter2, counter2); - } - for(c = 0;c < IrSize;c += 2) - { - float32x4_t step4 = vld1q_f32((float32_t*)hrtfparams->CoeffStep[c]); - float32x4_t coeffs = vld1q_f32((float32_t*)hrtfparams->Coeffs[c]); - coeffs = vmlaq_f32(coeffs, step4, counter4); - vst1q_f32((float32_t*)OutCoeffs[c], coeffs); - } -} - static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 090b7a5a..942e0453 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -71,23 +71,6 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, } -static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], - const HrtfParams *hrtfparams, - ALuint IrSize, ALuint Counter) -{ - const __m128 counter4 = _mm_set1_ps((float)Counter); - __m128 coeffs, step4; - ALuint i; - - for(i = 0;i < IrSize;i += 2) - { - step4 = _mm_load_ps(&hrtfparams->CoeffStep[i][0]); - coeffs = _mm_load_ps(&hrtfparams->Coeffs[i][0]); - coeffs = _mm_sub_ps(coeffs, _mm_mul_ps(step4, counter4)); - _mm_store_ps(&OutCoeffs[i][0], coeffs); - } -} - static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8f1fd956..89936f85 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -404,9 +404,7 @@ typedef struct HrtfState { typedef struct HrtfParams { alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2]; ALuint Delay[2]; - ALint DelayStep[2]; } HrtfParams; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 50ef1f5e..af2ea857 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -138,16 +138,19 @@ typedef struct MixGains { ALfloat Target; } MixGains; +typedef struct MixHrtfParams { + const HrtfParams *Target; + HrtfParams *Current; + struct { + alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; + ALint Delay[2]; + } Steps; +} MixHrtfParams; typedef struct DirectParams { ALfloat (*OutBuffer)[BUFFERSIZE]; ALuint OutChannels; - /* Last direction (relative to listener) and gain of a moving source. */ - aluVector LastDir; - ALfloat LastGain; - ALuint HrtfCounter; - struct { enum ActiveFilters ActiveType; ALfilterState LowPass; @@ -155,7 +158,8 @@ typedef struct DirectParams { } Filters[MAX_INPUT_CHANNELS]; struct { - HrtfParams Params; + HrtfParams Current; + HrtfParams Target; HrtfState State; } Hrtf[MAX_INPUT_CHANNELS]; @@ -191,7 +195,7 @@ typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALuint Counter, ALuint OutPos, ALuint BufferSize); typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const HrtfParams *hrtfparams, + const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f742e1fe..250c9d1e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2641,7 +2641,6 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); voice->Moving = AL_FALSE; - voice->Direct.HrtfCounter = 0; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { ALsizei j; -- cgit v1.2.3 From 6b1f3222201fd0072e46e1d95aa00abf95d32cec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Feb 2016 13:30:03 -0800 Subject: Only calculate steps for the used coefficients --- Alc/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 6b5272ea..779d69e0 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -618,7 +618,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { ALfloat coeffdiff; ALint delaydiff; - for(j = 0;j < HRIR_LENGTH;j++) + for(j = 0;j < IrSize;j++) { coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][0] - parms->Hrtf[chan].Current.Coeffs[j][0]; hrtfparams.Steps.Coeffs[j][0] = coeffdiff * Delta; -- cgit v1.2.3 From ee9917fe9687f6d67e80e7484f98f3722a2b3b32 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Feb 2016 02:42:43 -0800 Subject: Remove a dead assignment --- Alc/effects/reverb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index d1419d82..103db906 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -840,7 +840,6 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection LateReverbPan[1] / length, -LateReverbPan[2] / length, }; - length = 1.0f; for(i = 0;i < 4;i++) { ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; -- cgit v1.2.3 From 7ff5cf782013e710f7a8b37b1262ef060fafc1c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Feb 2016 19:56:44 -0800 Subject: Allocate each HRTF as a single chunk --- Alc/hrtf.c | 60 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 33e58dfb..c4cacf87 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -416,7 +416,13 @@ static struct Hrtf *LoadHrtf00(FILE *f) if(!failed) { - Hrtf = malloc(sizeof(struct Hrtf)); + size_t total = sizeof(struct Hrtf); + total += sizeof(azCount[0])*evCount; + total += sizeof(evOffset[0])*evCount; + total += sizeof(coeffs[0])*irSize*irCount; + total += sizeof(delays[0])*irCount; + + Hrtf = malloc(total); if(Hrtf == NULL) { ERR("Out of memory.\n"); @@ -429,20 +435,24 @@ static struct Hrtf *LoadHrtf00(FILE *f) Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->evCount = evCount; - Hrtf->azCount = azCount; - Hrtf->evOffset = evOffset; - Hrtf->coeffs = coeffs; - Hrtf->delays = delays; + Hrtf->azCount = ((ALubyte*)(Hrtf+1)); + Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); + Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); + Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); AL_STRING_INIT(Hrtf->filename); Hrtf->next = NULL; - return Hrtf; + + memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); + memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); + memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); + memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); } free(azCount); free(evOffset); free(coeffs); free(delays); - return NULL; + return Hrtf; } @@ -556,7 +566,13 @@ static struct Hrtf *LoadHrtf01(FILE *f) if(!failed) { - Hrtf = malloc(sizeof(struct Hrtf)); + size_t total = sizeof(struct Hrtf); + total += sizeof(azCount[0])*evCount; + total += sizeof(evOffset[0])*evCount; + total += sizeof(coeffs[0])*irSize*irCount; + total += sizeof(delays[0])*irCount; + + Hrtf = malloc(total); if(Hrtf == NULL) { ERR("Out of memory.\n"); @@ -569,20 +585,24 @@ static struct Hrtf *LoadHrtf01(FILE *f) Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->evCount = evCount; - Hrtf->azCount = azCount; - Hrtf->evOffset = evOffset; - Hrtf->coeffs = coeffs; - Hrtf->delays = delays; + Hrtf->azCount = ((ALubyte*)(Hrtf+1)); + Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); + Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); + Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); AL_STRING_INIT(Hrtf->filename); Hrtf->next = NULL; - return Hrtf; + + memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); + memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); + memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); + memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); } free(azCount); free(evOffset); free(coeffs); free(delays); - return NULL; + return Hrtf; } @@ -749,16 +769,14 @@ ALuint GetHrtfIrSize(const struct Hrtf *Hrtf) void FreeHrtfs(void) { - struct Hrtf *Hrtf = NULL; + struct Hrtf *Hrtf = LoadedHrtfs; + LoadedHrtfs = NULL; - while((Hrtf=LoadedHrtfs) != NULL) + while(Hrtf != NULL) { - LoadedHrtfs = Hrtf->next; - free((void*)Hrtf->azCount); - free((void*)Hrtf->evOffset); - free((void*)Hrtf->coeffs); - free((void*)Hrtf->delays); + struct Hrtf *next = Hrtf->next; al_string_deinit(&Hrtf->filename); free(Hrtf); + Hrtf = next; } } -- cgit v1.2.3 From 670aeec59aec9d0bd11c206c049448233fcd0279 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 18 Feb 2016 06:11:54 -0800 Subject: Fix default makehrtf output name And clean up the parameter processing. --- utils/makehrtf.c | 308 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 169 insertions(+), 139 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 57d8a91a..fef1533a 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -2512,146 +2512,176 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin return (1); } -// Standard command line dispatch. -int main (const int argc, const char * argv []) { - const char * inName = NULL, * outName = NULL; - OutputFormatT outFormat; - int argi; - uint outRate, fftSize; - int equalize, surface; - double limit; - uint truncSize; - HeadModelT model; - double radius; - char * end = NULL; - - if (argc < 2) { - fprintf (stderr, "Error: No command specified. See '%s -h' for help.\n", argv [0]); - return (-1); - } - if ((strcmp (argv [1], "--help") == 0) || (strcmp (argv [1], "-h") == 0)) { - fprintf (stdout, "HRTF Processing and Composition Utility\n\n"); - fprintf (stdout, "Usage: %s [ + + + 564 + 454 + + + + + 564 + 454 + + OpenAL Soft Configuration @@ -198,339 +210,475 @@ to stereo output. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 280 + 50 + 81 + 21 + + + + Stereo Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 370 + 50 + 78 + 22 + + + + How to treat stereo output. As headphones, HRTF or crossfeed +filters may be used to improve binaural quality, which may not +otherwise be suitable for speakers. + + - 10 - 180 - 511 - 191 + -11 + 200 + 551 + 181 - HRTF (Stereo only) + Advanced Settings - + + Qt::AlignCenter + + 20 30 - 391 - 121 - - - - A list of files containing HRTF data sets. The listed data sets -are used in place of the default sets. The filenames may -contain these markers, which will be replaced as needed: -%r - Device sampling rate -%s - Non-greedy string (up to the following matching characters) -%% - Percent sign (%) - - - false - - - QAbstractItemView::InternalMove - - - true - - - QAbstractItemView::ExtendedSelection - - - Qt::ElideNone - - - - - - 420 - 30 - 81 - 25 + 511 + 91 - - Add... - - - - - + + Buffer Metrics - - false + + Qt::AlignCenter + + + + 260 + 20 + 241 + 51 + + + + 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. + + + + + 20 + 0 + 201 + 21 + + + + Period Count + + + Qt::AlignCenter + + + + + + 70 + 20 + 160 + 23 + + + + 1 + + + 16 + + + 1 + + + 2 + + + 1 + + + true + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 1 + + + + + + 20 + 20 + 51 + 22 + + + + 4 + + + + + + + 10 + 20 + 241 + 51 + + + + The update period size, in sample frames. This is the number of +frames needed for each mixing update. + + + + + 60 + 20 + 160 + 23 + + + + 0 + + + 8192 + + + 64 + + + 1024 + + + 0 + + + true + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 512 + + + + + + 10 + 0 + 201 + 21 + + + + Period Samples + + + Qt::AlignCenter + + + + + + 10 + 20 + 51 + 22 + + + + 1024 + + + - + + + + + 90 + 80 + 351 + 81 + + + + Resampler Quality + + + Qt::AlignCenter + + - 420 - 60 - 81 - 25 + 20 + 50 + 311 + 21 - Remove - - - - - - - - - - - 110 - 160 - 161 - 22 - + Default - - QComboBox::AdjustToContentsOnFirstShow + + Qt::AlignCenter - - - Application preference - - - - - Force on - - - - - Force off - - - + - 30 - 160 - 71 - 21 + 20 + 30 + 311 + 23 - - HRTF Mode: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + Qt::Horizontal - + + + + HRTF + + - 10 - 90 - 511 - 91 + -10 + 200 + 551 + 181 - Buffer Metrics + Advanced Settings + + + Qt::AlignCenter + + + false + + + false - + - 260 - 20 - 241 - 51 + 20 + 30 + 511 + 141 - - 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. + + HRTF Profiles - + + Qt::AlignCenter + + 20 - 0 - 201 - 21 - - - - Period Count - - - Qt::AlignCenter - - - - - - 70 20 - 160 - 23 + 391 + 81 - - 1 - - - 16 - - - 1 + + A list of files containing HRTF data sets. The listed data sets +are used in place of the default sets. The filenames may +contain these markers, which will be replaced as needed: +%r - Device sampling rate +%s - Non-greedy string (up to the following matching characters) +%% - Percent sign (%) - - 2 + + false - - 1 + + QAbstractItemView::InternalMove - + true - - Qt::Horizontal + + QAbstractItemView::ExtendedSelection - - QSlider::TicksBelow - - - 1 + + Qt::ElideNone - + - 20 + 420 20 - 51 - 22 + 81 + 25 - - 4 - - - - - - - 10 - 20 - 241 - 51 - - - - The update period size, in sample frames. This is the number of -frames needed for each mixing update. - - - - - 60 - 20 - 160 - 23 - - - - 0 - - - 8192 - - - 64 - - - 1024 - - - 0 - - - true - - - Qt::Horizontal + + Add... - - QSlider::TicksBelow + + + + - - 512 + + false - + - 10 - 0 - 201 + 180 + 110 + 151 21 - Period Samples + Include Default Paths - - Qt::AlignCenter + + true - + - 10 - 20 - 51 - 22 + 420 + 50 + 81 + 25 - - 1024 + + Remove + + + + + - + - 280 + 40 50 - 81 + 71 21 - Stereo Mode: + HRTF Mode: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - 370 + 130 50 - 78 + 161 22 - - How to treat stereo output. As headphones, HRTF or crossfeed -filters may be used to improve binaural quality, which may not -otherwise be suitable for speakers. + + QComboBox::AdjustToContentsOnFirstShow + + + + Application preference + + + + + Force on + + + + + Force off + + + + + + + 20 + 20 + 91 + 21 + + + + Preferred HRTF: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 130 + 20 + 161 + 22 + @@ -662,40 +810,11 @@ value currently possible is 4. Auto - - - - 30 - 120 - 71 - 21 - - - - Resampler: - - - - - - 110 - 120 - 78 - 22 - - - - The resampling method used when mixing sources. - - - QComboBox::AdjustToContents - - 10 - 150 + 120 511 121 -- cgit v1.2.3 From 840fa1b5e8fe8c677a3cb3ed1178c222848317e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Feb 2016 07:56:05 -0800 Subject: Add a warning if closing alsoft-config with unsaved changes --- utils/alsoft-config/mainwindow.cpp | 124 +++++++++++++++++++++++++++++-------- utils/alsoft-config/mainwindow.h | 8 +++ utils/alsoft-config/mainwindow.ui | 16 +++++ 3 files changed, 123 insertions(+), 25 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index c05e343e..3b123ccf 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include "mainwindow.h" @@ -173,7 +174,8 @@ MainWindow::MainWindow(QWidget *parent) : mSourceCountValidator(NULL), mEffectSlotValidator(NULL), mSourceSendValidator(NULL), - mSampleRateValidator(NULL) + mSampleRateValidator(NULL), + mNeedsSave(false) { ui->setupUi(this); @@ -251,8 +253,15 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); + connect(ui->closeCancelButton, SIGNAL(clicked()), this, SLOT(cancelCloseAction())); connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig())); + connect(ui->channelConfigCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleFormatCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->stereoModeCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleRateCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleRateCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->resamplerSlider, SIGNAL(valueChanged(int)), this, SLOT(updateResamplerLabel(int))); connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int))); @@ -260,15 +269,41 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); + connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton())); + connect(ui->defaultHrtfPathsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->srcCountLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + connect(ui->srcSendLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + connect(ui->effectSlotLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + + connect(ui->enableSSECheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE2CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE3CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE41CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableNeonCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); 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->backendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->defaultReverbComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->emulateEaxCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEaxReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableStdReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableChorusCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableCompressorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableDistortionCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); loadConfig(getDefaultConfigName()); } @@ -284,6 +319,32 @@ MainWindow::~MainWindow() delete mSampleRateValidator; } +void MainWindow::closeEvent(QCloseEvent *event) +{ + if(!mNeedsSave) + event->accept(); + else + { + QMessageBox::StandardButton btn = QMessageBox::warning(this, + tr("Apply changes?"), tr("Save changes before quitting?"), + QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel + ); + if(btn == QMessageBox::Save) + saveCurrentConfig(); + if(btn == QMessageBox::Cancel) + event->ignore(); + else + event->accept(); + } +} + +void MainWindow::cancelCloseAction() +{ + mNeedsSave = false; + close(); +} + + void MainWindow::loadConfigFromFile() { QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); @@ -501,11 +562,18 @@ void MainWindow::loadConfig(const QString &fname) ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); + + ui->applyButton->setEnabled(false); + ui->closeCancelButton->setText(tr("Close")); + mNeedsSave = false; } void MainWindow::saveCurrentConfig() { saveConfig(getDefaultConfigName()); + ui->applyButton->setEnabled(false); + ui->closeCancelButton->setText(tr("Close")); + mNeedsSave = false; QMessageBox::information(this, tr("Information"), tr("Applications using OpenAL need to be restarted for changes to take effect.")); } @@ -514,7 +582,11 @@ void MainWindow::saveConfigAsFile() { QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); if(fname.isEmpty() == false) + { saveConfig(fname); + ui->applyButton->setEnabled(false); + mNeedsSave = false; + } } void MainWindow::saveConfig(const QString &fname) const @@ -665,9 +737,19 @@ void MainWindow::saveConfig(const QString &fname) const } +void MainWindow::enableApplyButton() +{ + if(!mNeedsSave) + ui->applyButton->setEnabled(true); + mNeedsSave = true; + ui->closeCancelButton->setText(tr("Cancel")); +} + + void MainWindow::updateResamplerLabel(int num) { ui->resamplerLabel->setText(resamplerList[num].name); + enableApplyButton(); } @@ -679,6 +761,7 @@ void MainWindow::updatePeriodSizeEdit(int size) size = (size+32)&~0x3f; ui->periodSizeEdit->insert(QString::number(size)); } + enableApplyButton(); } void MainWindow::updatePeriodSizeSlider() @@ -690,6 +773,7 @@ void MainWindow::updatePeriodSizeSlider() pos = 8192; ui->periodSizeSlider->setSliderPosition(pos); } + enableApplyButton(); } void MainWindow::updatePeriodCountEdit(int count) @@ -697,6 +781,7 @@ void MainWindow::updatePeriodCountEdit(int count) ui->periodCountEdit->clear(); if(count >= 2) ui->periodCountEdit->insert(QString::number(count)); + enableApplyButton(); } void MainWindow::updatePeriodCountSlider() @@ -707,6 +792,7 @@ void MainWindow::updatePeriodCountSlider() else if(pos > 16) pos = 16; ui->periodCountSlider->setSliderPosition(pos); + enableApplyButton(); } @@ -719,36 +805,20 @@ void MainWindow::addHrtfFile() if(fnames.isEmpty() == false) { for(QStringList::iterator iter = fnames.begin();iter != fnames.end();iter++) - { - QStringList::const_iterator path = datapaths.constBegin(); - for(;path != datapaths.constEnd();path++) - { - QDir hrtfdir(*path); - if(!hrtfdir.isAbsolute()) - continue; - - const QString relname = hrtfdir.relativeFilePath(*iter); - if(!relname.startsWith("..")) - { - // If filename is within this path, use the relative pathname - ui->hrtfFileList->addItem(relname); - break; - } - } - if(path == datapaths.constEnd()) - { - // Filename is not within any data path, use the absolute pathname - ui->hrtfFileList->addItem(*iter); - } - } + ui->hrtfFileList->addItem(*iter); + enableApplyButton(); } } void MainWindow::removeHrtfFile() { QList selected = ui->hrtfFileList->selectedItems(); - foreach(QListWidgetItem *item, selected) - delete item; + if(!selected.isEmpty()) + { + foreach(QListWidgetItem *item, selected) + delete item; + enableApplyButton(); + } } void MainWindow::updateHrtfRemoveButton() @@ -782,12 +852,14 @@ void MainWindow::showEnabledBackendMenu(QPoint pt) QList selected = ui->enabledBackendList->selectedItems(); foreach(QListWidgetItem *item, selected) delete item; + enableApplyButton(); } else if(gotAction != NULL) { QMap::const_iterator iter = actionMap.find(gotAction); if(iter != actionMap.end()) ui->enabledBackendList->addItem(iter.value()); + enableApplyButton(); } } @@ -817,11 +889,13 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) QList selected = ui->disabledBackendList->selectedItems(); foreach(QListWidgetItem *item, selected) delete item; + enableApplyButton(); } else if(gotAction != NULL) { QMap::const_iterator iter = actionMap.find(gotAction); if(iter != actionMap.end()) ui->disabledBackendList->addItem(iter.value()); + enableApplyButton(); } } diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 0f94c0ce..dfa69ca2 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -17,11 +17,15 @@ public: ~MainWindow(); private slots: + void cancelCloseAction(); + void saveCurrentConfig(); void saveConfigAsFile(); void loadConfigFromFile(); + void enableApplyButton(); + void updateResamplerLabel(int num); void updatePeriodSizeEdit(int size); @@ -47,6 +51,10 @@ private: QValidator *mSourceSendValidator; QValidator *mSampleRateValidator; + bool mNeedsSave; + + void closeEvent(QCloseEvent *event); + void loadConfig(const QString &fname); void saveConfig(const QString &fname) const; }; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 30e53d15..9e09cddb 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1375,6 +1375,22 @@ added by the ALC_EXT_DEDICATED extension. + + + + 370 + 405 + 91 + 25 + + + + Cancel + + + + + -- cgit v1.2.3 From 2c6e59c4ca50f186d19e1fd95fe058ea352c8900 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Feb 2016 08:12:09 -0800 Subject: Fix when ESTRPIPE and EPIPE are the same --- Alc/backends/alsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 43c46484..b5715e18 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -588,7 +588,9 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) { case -EAGAIN: continue; +#if ESTRPIPE != EPIPE case -ESTRPIPE: +#endif case -EPIPE: case -EINTR: ret = snd_pcm_recover(self->pcmHandle, ret, 1); -- cgit v1.2.3 From 6512dcb23392872531886e728111b50d685cde86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 01:46:38 -0800 Subject: Don't bother with a maximum size for the window --- utils/alsoft-config/mainwindow.ui | 6 ------ 1 file changed, 6 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 9e09cddb..7e23c966 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -16,12 +16,6 @@ 454 - - - 564 - 454 - - OpenAL Soft Configuration -- cgit v1.2.3 From ae1a2fa9c0948ce5dee197a11816992b8b64f7d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 06:52:13 -0800 Subject: Allow selecting a preferred HRTF in alsoft-config This currently only checks the default paths when they're being used. --- Alc/hrtf.c | 2 +- alsoftrc.sample | 4 +- utils/alsoft-config/mainwindow.cpp | 103 ++++++++++++++++++++++++------------- utils/alsoft-config/mainwindow.h | 2 + 4 files changed, 71 insertions(+), 40 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9de6da2e..beb67e76 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -641,7 +641,7 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) } } - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default_hrtf", &defaulthrtf)) + if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) { const HrtfEntry *iter; /* Find the preferred HRTF and move it to the front of the list. */ diff --git a/alsoftrc.sample b/alsoftrc.sample index c29fae49..9eb9740e 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -96,11 +96,11 @@ # respectively. #hrtf = auto -## default_hrtf: +## default-hrtf: # Specifies the default HRTF to use. When multiple HRTFs are available, this # determines the preferred one to use if none are specifically requested. Note # that this is the enumerated HRTF name, not necessarily the filename. -#default_hrtf = +#default-hrtf = ## hrtf_tables: # Specifies a comma-separated list of files containing HRTF data sets. The diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 3b123ccf..315ef491 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -269,6 +269,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); + connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); @@ -345,6 +346,24 @@ void MainWindow::cancelCloseAction() } +QStringList MainWindow::collectDefaultHrtfs() +{ + QStringList ret; + QStringList paths = getAllDataPaths("/openal/hrtf"); + foreach(const QString &name, paths) + { + QDir dir(name); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable); + foreach(const QString &fname, fnames) + { + if(fname.endsWith(".mhr", Qt::CaseInsensitive)) + ret.push_back(fname); + } + } + return ret; +} + + void MainWindow::loadConfigFromFile() { QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); @@ -364,15 +383,8 @@ void MainWindow::loadConfig(const QString &fname) { if(sampletype == sampleTypeList[i].value) { - for(int j = 1;j < ui->sampleFormatCombo->count();j++) - { - QString item = ui->sampleFormatCombo->itemText(j); - if(item == sampleTypeList[i].name) - { - ui->sampleFormatCombo->setCurrentIndex(j); - break; - } - } + int j = ui->sampleFormatCombo->findText(sampleTypeList[i].name); + if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j); break; } } @@ -386,15 +398,8 @@ void MainWindow::loadConfig(const QString &fname) { if(channelconfig == speakerModeList[i].value) { - for(int j = 1;j < ui->channelConfigCombo->count();j++) - { - QString item = ui->channelConfigCombo->itemText(j); - if(item == speakerModeList[i].name) - { - ui->channelConfigCombo->setCurrentIndex(j); - break; - } - } + int j = ui->channelConfigCombo->findText(speakerModeList[i].name); + if(j > 0) ui->channelConfigCombo->setCurrentIndex(j); break; } } @@ -439,15 +444,8 @@ void MainWindow::loadConfig(const QString &fname) { if(stereomode == stereoModeList[i].value) { - for(int j = 1;j < ui->stereoModeCombo->count();j++) - { - QString item = ui->stereoModeCombo->itemText(j); - if(item == stereoModeList[i].name) - { - ui->stereoModeCombo->setCurrentIndex(j); - break; - } - } + int j = ui->stereoModeCombo->findText(stereoModeList[i].name); + if(j > 0) ui->stereoModeCombo->setCurrentIndex(j); break; } } @@ -480,16 +478,6 @@ void MainWindow::loadConfig(const QString &fname) ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive)); ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); - if(settings.value("hrtf").toString() == QString()) - ui->hrtfStateComboBox->setCurrentIndex(0); - else - { - if(settings.value("hrtf", true).toBool()) - ui->hrtfStateComboBox->setCurrentIndex(1); - else - ui->hrtfStateComboBox->setCurrentIndex(2); - } - QStringList hrtf_tables = settings.value("hrtf_tables").toStringList(); if(hrtf_tables.size() == 1) hrtf_tables = hrtf_tables[0].split(QChar(',')); @@ -507,6 +495,39 @@ void MainWindow::loadConfig(const QString &fname) ui->hrtfFileList->addItems(hrtf_tables); updateHrtfRemoveButton(); + QString hrtfstate = settings.value("hrtf").toString().toLower(); + if(hrtfstate == "true") + ui->hrtfStateComboBox->setCurrentIndex(1); + else if(hrtfstate == "false") + ui->hrtfStateComboBox->setCurrentIndex(2); + else + ui->hrtfStateComboBox->setCurrentIndex(0); + + ui->preferredHrtfComboBox->clear(); + ui->preferredHrtfComboBox->addItem("- Any -"); + if(ui->defaultHrtfPathsCheckBox->isChecked()) + { + QStringList hrtfs = collectDefaultHrtfs(); + foreach(const QString &name, hrtfs) + ui->preferredHrtfComboBox->addItem(name); + } + + QString defaulthrtf = settings.value("default-hrtf").toString(); + ui->preferredHrtfComboBox->setCurrentIndex(0); + if(defaulthrtf.isEmpty() == false) + { + int i = ui->preferredHrtfComboBox->findText(defaulthrtf); + if(i > 0) + ui->preferredHrtfComboBox->setCurrentIndex(i); + else + { + i = ui->preferredHrtfComboBox->count(); + ui->preferredHrtfComboBox->addItem(defaulthrtf); + ui->preferredHrtfComboBox->setCurrentIndex(i); + } + } + ui->preferredHrtfComboBox->adjustSize(); + ui->enabledBackendList->clear(); ui->disabledBackendList->clear(); QStringList drivers = settings.value("drivers").toStringList(); @@ -666,6 +687,14 @@ void MainWindow::saveConfig(const QString &fname) const else settings.setValue("hrtf", QString()); + if(ui->preferredHrtfComboBox->currentIndex() == 0) + settings.setValue("default-hrtf", QString()); + else + { + str = ui->preferredHrtfComboBox->currentText(); + settings.setValue("default-hrtf", str); + } + strlist.clear(); QList items = ui->hrtfFileList->findItems("*", Qt::MatchWildcard); foreach(const QListWidgetItem *item, items) diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index dfa69ca2..66b4c650 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -55,6 +55,8 @@ private: void closeEvent(QCloseEvent *event); + QStringList collectDefaultHrtfs(); + void loadConfig(const QString &fname); void saveConfig(const QString &fname) const; }; -- cgit v1.2.3 From dea880dbf451e1b0ae1cdbff8643d3eb9208f536 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 07:29:07 -0800 Subject: Better handle duplicate HRTF names in alsoft-config --- utils/alsoft-config/mainwindow.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 315ef491..17407498 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -357,7 +357,23 @@ QStringList MainWindow::collectDefaultHrtfs() foreach(const QString &fname, fnames) { if(fname.endsWith(".mhr", Qt::CaseInsensitive)) - ret.push_back(fname); + { + if(!ret.contains(fname)) + ret.push_back(fname); + else + { + size_t i = 1; + do { + QString s = fname+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); + } + } } } return ret; -- cgit v1.2.3 From e7ed3e2f72232dcf00c1f7b14f40d9c6e00c3633 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 07:41:17 -0800 Subject: Remove an unused function --- Alc/helpers.c | 149 ---------------------------------------------- OpenAL32/Include/alMain.h | 2 - 2 files changed, 151 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 9a9273c4..c98f121f 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -476,84 +476,6 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -FILE *OpenDataFile(const char *fname, const char *subdir) -{ - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - WCHAR *wname=NULL, *wsubdir=NULL; - FILE *f; - size_t i; - - wname = FromUTF8(fname); - if(!wname) - { - ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname); - return NULL; - } - - /* If the path is absolute, open it directly. */ - if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2])) - { - f = _wfopen(wname, L"rb"); - if(f) TRACE("Opened %s\n", fname); - else WARN("Could not open %s\n", fname); - free(wname); - return f; - } - - /* Try the current directory first before the data directories. */ - if((f=_wfopen(wname, L"rb")) != NULL) - { - TRACE("Opened %s\n", fname); - free(wname); - return f; - } - - wsubdir = FromUTF8(subdir); - if(!wsubdir) - { - ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir); - free(wname); - return NULL; - } - - for(i = 0;i < COUNTOF(ids);i++) - { - WCHAR buffer[PATH_MAX]; - size_t len; - - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE) - continue; - - len = lstrlenW(buffer); - if(len > 0 && is_slash(buffer[len-1])) - buffer[--len] = '\0'; - _snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname); - len = lstrlenW(buffer); - while(len > 0) - { - --len; - if(buffer[len] == '/') - buffer[len] = '\\'; - } - - if((f=_wfopen(buffer, L"rb")) != NULL) - { - al_string filepath = AL_STRING_INIT_STATIC(); - al_string_copy_wcstr(&filepath, buffer); - TRACE("Opened %s\n", al_string_get_cstr(filepath)); - al_string_deinit(&filepath); - break; - } - } - free(wname); - free(wsubdir); - - if(f == NULL) - WARN("Could not open %s\\%s\n", subdir, fname); - return f; -} - - static size_t strlenW(const WCHAR *str) { const WCHAR *end = str; @@ -955,77 +877,6 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -FILE *OpenDataFile(const char *fname, const char *subdir) -{ - char buffer[PATH_MAX] = ""; - const char *str, *next; - FILE *f; - - if(fname[0] == '/') - { - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - WARN("Could not open %s\n", fname); - return NULL; - } - - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - - if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') - snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname); - else if((str=getenv("HOME")) != NULL && str[0] != '\0') - snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", str, subdir, fname); - if(buffer[0]) - { - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } - } - - if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') - str = "/usr/local/share/:/usr/share/"; - - next = str; - while((str=next) != NULL && str[0] != '\0') - { - size_t len; - next = strchr(str, ':'); - - if(!next) - len = strlen(str); - else - { - len = next - str; - next++; - } - - if(len > sizeof(buffer)-1) - len = sizeof(buffer)-1; - strncpy(buffer, str, len); - buffer[len] = '\0'; - snprintf(buffer+len, sizeof(buffer)-len, "/%s/%s", subdir, fname); - - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } - } - WARN("Could not open %s/%s\n", subdir, fname); - - return NULL; -} - - static int MatchFilter(const char *name, const char *match) { int ret = 1; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4c0e9213..78475fa5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -732,8 +732,6 @@ enum { void FillCPUCaps(ALuint capfilter); -FILE *OpenDataFile(const char *fname, const char *subdir); - vector_al_string SearchDataFiles(const char *match, const char *subdir); /* Small hack to use a pointer-to-array type as a normal argument type. -- cgit v1.2.3 From 68a2ae4024909a6ef785d702ffb90480aac6f0cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 10:54:42 -0800 Subject: Replace the hrtf_tables option with hrtf-paths --- Alc/helpers.c | 547 ++++++------------------------------- Alc/hrtf.c | 49 ++-- alsoftrc.sample | 18 +- utils/alsoft-config/mainwindow.cpp | 49 ++-- utils/alsoft-config/mainwindow.ui | 2 +- 5 files changed, 144 insertions(+), 521 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index c98f121f..20cd8900 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -476,301 +476,69 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -static size_t strlenW(const WCHAR *str) -{ - const WCHAR *end = str; - while(*end) ++end; - return end-str; -} - -static const WCHAR *strchrW(const WCHAR *str, WCHAR ch) -{ - for(;*str != 0;++str) - { - if(*str == ch) - return str; - } - return NULL; -} - -static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch) -{ - const WCHAR *ret = NULL; - for(;*str != 0;++str) - { - if(*str == ch) - ret = str; - } - return ret; -} - -static const WCHAR *strstrW(const WCHAR *haystack, const WCHAR *needle) -{ - size_t len = strlenW(needle); - while(*haystack != 0) - { - if(CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - haystack, len, needle, len) == CSTR_EQUAL) - return haystack; - - do { - ++haystack; - } while(((*haystack)&0xC000) == 0x8000); - } - return NULL; -} - - -/* Compares the filename in the find data with the match string. The match - * string may contain the "%r" marker to signifiy a sample rate (really any - * positive integer), "%%" to signify a single '%', or "%s" for a (non-greedy) - * string. - */ -static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) -{ - const WCHAR *name = fdata->cFileName; - int ret = 1; - - do { - const WCHAR *p = strchrW(match, '%'); - if(!p) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, -1, name, -1) == CSTR_EQUAL; - else - { - int len = p-match; - ret = lstrlenW(name) >= len; - if(ret) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, len, name, len) == CSTR_EQUAL; - if(ret) - { - match += len; - name += len; - - ++p; - if(*p == 'r') - { - unsigned long l = 0; - while(*name >= '0' && *name <= '9') - { - l = l*10 + (*name-'0'); - ++name; - } - ret = l > 0; - ++p; - } - else if(*p == 's') - { - const WCHAR *next = p+1; - if(*next != '\0' && *next != '%') - { - const WCHAR *next_p = strchrW(next, '%'); - const WCHAR *m; - - if(!next_p) - m = strstrW(name, next); - else - { - WCHAR *tmp = malloc((next_p - next + 1) * 2); - memcpy(tmp, next, (next_p - next) * 2); - tmp[next_p - next] = 0; - - m = strstrW(name, tmp); - - free(tmp); - } - - ret = !!m; - if(ret) - { - size_t l; - if(next_p) l = next_p - next; - else l = strlenW(next); - - name = m + l; - next += l; - } - } - p = next; - } - } - } - - match = p; - } while(ret && match && *match); - - return ret; -} - -static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { + al_string pathstr = AL_STRING_INIT_STATIC(); WIN32_FIND_DATAW fdata; - const WCHAR *sep, *p; + WCHAR *wpath; HANDLE hdl; - if(!match[0]) - return; - - /* Find the last directory separator and the next '%' marker in the match - * string. */ - sep = strrchrW(match, '\\'); - p = strchrW(match, '%'); - - /* If there's no separator, test the files in the specified path against - * the match string, and add the results. */ - if(!sep) - { - al_string pathstr = AL_STRING_INIT_STATIC(); - WCHAR *wpath; - - TRACE("Searching %s for %ls\n", path, match); - - al_string_append_cstr(&pathstr, path); - al_string_append_cstr(&pathstr, "\\*.*"); - wpath = FromUTF8(al_string_get_cstr(pathstr)); - - hdl = FindFirstFileW(wpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - size_t base = VECTOR_SIZE(*results); - do { - if(MatchFilter(match, &fdata)) - { - al_string str = AL_STRING_INIT_STATIC(); - al_string_copy_cstr(&str, path); - al_string_append_char(&str, '\\'); - al_string_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", al_string_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } + al_string_copy_cstr(&pathstr, path); + al_string_append_cstr(&pathstr, "\\*"); + al_string_append_cstr(&pathstr, ext); - free(wpath); - al_string_deinit(&pathstr); + TRACE("Searching %s\n", al_string_get_cstr(pathstr)); - return; - } + wpath = FromUTF8(al_string_get_cstr(pathstr)); - /* If there's no '%' marker, or it's after the final separator, append the - * remaining directories to the path and recurse into it with the remaining - * filename portion. */ - if(!p || p-sep >= 0) + hdl = FindFirstFileW(wpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) { - al_string npath = AL_STRING_INIT_STATIC(); - al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - - TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1); - RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); + size_t base = VECTOR_SIZE(*results); + do { + al_string str = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&str, path); + al_string_append_char(&str, '\\'); + al_string_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); - al_string_deinit(&npath); - return; + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } - /* Look for the last separator before the '%' marker, and the first - * separator after it. */ - sep = strchrW(match, '\\'); - if(sep-p >= 0) sep = NULL; - for(;;) - { - const WCHAR *next = strchrW(sep?sep+1:match, '\\'); - if(next-p < 0) - { - al_string npath = AL_STRING_INIT_STATIC(); - WCHAR *nwpath, *nwmatch; - - /* Append up to the last directory before the one with a '%'. */ - al_string_copy_cstr(&npath, path); - if(sep) - { - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - } - al_string_append_cstr(&npath, "\\*.*"); - nwpath = FromUTF8(al_string_get_cstr(npath)); - - /* Take the directory name containing a '%' as a new string to - * match against. */ - if(!sep) - { - nwmatch = calloc(2, next-match+1); - memcpy(nwmatch, match, (next-match)*2); - } - else - { - nwmatch = calloc(2, next-(sep+1)+1); - memcpy(nwmatch, sep+1, (next-(sep+1))*2); - } - - /* For each matching directory name, recurse into it with the - * remaining string. */ - TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch); - hdl = FindFirstFileW(nwpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - do { - if(MatchFilter(nwmatch, &fdata)) - { - al_string ndir = AL_STRING_INIT_STATIC(); - al_string_copy(&ndir, npath); - al_string_append_char(&ndir, '\\'); - al_string_append_wcstr(&ndir, fdata.cFileName); - TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1); - RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); - al_string_deinit(&ndir); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - } - - free(nwmatch); - free(nwpath); - al_string_deinit(&npath); - break; - } - sep = next; - } + free(wpath); + al_string_deinit(&pathstr); } -vector_al_string SearchDataFiles(const char *match, const char *subdir) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); - WCHAR *wmatch; size_t i; while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) althrd_yield(); - wmatch = FromUTF8(match); - if(!wmatch) - { - ERR("Failed to convert UTF-8 filename: \"%s\"\n", match); - return results; - } - for(i = 0;wmatch[i];++i) - { - if(wmatch[i] == '/') - wmatch[i] = '\\'; - } - /* If the path is absolute, use it directly. */ - if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2])) + if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { - char drv[3] = { (char)wmatch[0], ':', 0 }; - RecurseDirectorySearch(drv, wmatch+3, &results); + al_string path = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + DirectorySearch(al_string_get_cstr(path), ext, &results); + + al_string_deinit(&path); } - else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\') - RecurseDirectorySearch("\\\\?", wmatch+4, &results); + else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + DirectorySearch(subdir, ext, &results); else { al_string path = AL_STRING_INIT_STATIC(); @@ -801,7 +569,7 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); /* Search the local and global data dirs. */ for(i = 0;i < COUNTOF(ids);i++) @@ -817,14 +585,13 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); } } al_string_deinit(&path); } - free(wmatch); ATOMIC_STORE(&search_lock, 0); return results; @@ -877,192 +644,46 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -static int MatchFilter(const char *name, const char *match) -{ - int ret = 1; - - do { - const char *p = strchr(match, '%'); - if(!p) - ret = strcmp(match, name) == 0; - else - { - size_t len = p-match; - ret = strncmp(match, name, len) == 0; - if(ret) - { - match += len; - name += len; - - ++p; - if(*p == 'r') - { - char *end; - ret = strtoul(name, &end, 10) > 0; - if(ret) name = end; - ++p; - } - else if(*p == 's') - { - const char *next = p+1; - if(*next != '\0' && *next != '%') - { - const char *next_p = strchr(next, '%'); - const char *m; - - if(!next_p) - m = strstr(name, next); - else - { - char *tmp = malloc(next_p - next + 1); - memcpy(tmp, next, next_p - next); - tmp[next_p - next] = 0; - - m = strstr(name, tmp); - - free(tmp); - } - - ret = !!m; - if(ret) - { - size_t l; - if(next_p) l = next_p - next; - else l = strlen(next); - - name = m + l; - next += l; - } - } - p = next; - } - } - } - - match = p; - } while(ret && match && *match); - - return ret; -} - -static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { - char *sep, *p; - - if(!match[0]) - return; - - sep = strrchr(match, '/'); - p = strchr(match, '%'); - - if(!sep) - { - DIR *dir; - - TRACE("Searching %s for %s\n", path?path:"/", match); - dir = opendir(path?path:"/"); - if(dir != NULL) - { - size_t base = VECTOR_SIZE(*results); - struct dirent *dirent; - while((dirent=readdir(dir)) != NULL) - { - al_string str; - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || - !MatchFilter(dirent->d_name, match)) - continue; - - AL_STRING_INIT(str); - if(path) al_string_copy_cstr(&str, path); - al_string_append_char(&str, '/'); - al_string_append_cstr(&str, dirent->d_name); - TRACE("Got result %s\n", al_string_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - closedir(dir); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } - - return; - } - - if(!p || p-sep >= 0) - { - al_string npath = AL_STRING_INIT_STATIC(); - if(path) al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '/'); - al_string_append_range(&npath, match, sep); - - TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1); - RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); - - al_string_deinit(&npath); - return; - } + size_t extlen = strlen(ext); + DIR *dir; - sep = strchr(match, '/'); - if(sep-p >= 0) sep = NULL; - for(;;) + TRACE("Searching %s for *%s\n", path, ext); + dir = opendir(path); + if(dir != NULL) { - char *next = strchr(sep?sep+1:match, '/'); - if(next-p < 0) + size_t base = VECTOR_SIZE(*results); + struct dirent *dirent; + while((dirent=readdir(dir)) != NULL) { - al_string npath = AL_STRING_INIT_STATIC(); - al_string nmatch = AL_STRING_INIT_STATIC(); - const char *tomatch; - DIR *dir; - - if(!sep) - { - al_string_append_cstr(&npath, path?path:"/."); - tomatch = match; - } - else - { - if(path) al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '/'); - al_string_append_range(&npath, match, sep); - - al_string_append_range(&nmatch, sep+1, next); - tomatch = al_string_get_cstr(nmatch); - } - - TRACE("Searching %s for %s\n", al_string_get_cstr(npath), tomatch); - dir = opendir(path?path:"/"); - if(dir != NULL) - { - al_string ndir = AL_STRING_INIT_STATIC(); - struct dirent *dirent; - - while((dirent=readdir(dir)) != NULL) - { - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || - !MatchFilter(dirent->d_name, tomatch)) - continue; - al_string_copy(&ndir, npath); - al_string_append_char(&ndir, '/'); - al_string_append_cstr(&ndir, dirent->d_name); - TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1); - RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); - } - closedir(dir); - - al_string_deinit(&ndir); - } - - al_string_deinit(&nmatch); - al_string_deinit(&npath); - break; + al_string str; + size_t len; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + len = strlen(dirent->d_name); + if(!(len > extlen)) + continue; + if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; + + AL_STRING_INIT(str); + al_string_copy_cstr(&str, path); + al_string_append_char(&str, '/'); + al_string_append_cstr(&str, dirent->d_name); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); } + closedir(dir); - sep = next; + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } } -vector_al_string SearchDataFiles(const char *match, const char *subdir) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); @@ -1070,8 +691,8 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) althrd_yield(); - if(match[0] == '/') - RecurseDirectorySearch(NULL, match+1, &results); + if(subdir[0] == '/') + DirectorySearch(subdir, ext, &results); else { al_string path = AL_STRING_INIT_STATIC(); @@ -1080,29 +701,27 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) /* Search the app-local directory. */ if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') - { - strncpy(cwdbuf, str, sizeof(cwdbuf)-1); - cwdbuf[sizeof(cwdbuf)-1] = '\0'; - } - else if(!getcwd(cwdbuf, sizeof(cwdbuf))) - strcpy(cwdbuf, "."); - RecurseDirectorySearch(cwdbuf, match, &results); + DirectorySearch(str, ext, &results); + else if(getcwd(cwdbuf, sizeof(cwdbuf))) + DirectorySearch(cwdbuf, ext, &results); + else + DirectorySearch(".", ext, &results); // Search local data dir if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') { - al_string_append_cstr(&path, str); + al_string_copy_cstr(&path, str); al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); + DirectorySearch(al_string_get_cstr(path), ext, &results); } else if((str=getenv("HOME")) != NULL && str[0] != '\0') { - al_string_append_cstr(&path, str); + al_string_copy_cstr(&path, str); al_string_append_cstr(&path, "/.local/share/"); al_string_append_cstr(&path, subdir); + DirectorySearch(al_string_get_cstr(path), ext, &results); } - if(!al_string_empty(path)) - RecurseDirectorySearch(al_string_get_cstr(path), match, &results); // Search global data dirs if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') @@ -1125,7 +744,7 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); - RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); } } diff --git a/Alc/hrtf.c b/Alc/hrtf.c index beb67e76..eeb4be41 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -603,43 +603,58 @@ done: vector_HrtfEntry EnumerateHrtf(const_al_string devname) { vector_HrtfEntry list = VECTOR_INIT_STATIC(); - const char *fnamelist = "%s.mhr"; const char *defaulthrtf = ""; + const char *pathlist = ""; + bool usedefaults = true; - ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist); - while(fnamelist && *fnamelist) + if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) { - while(isspace(*fnamelist) || *fnamelist == ',') - fnamelist++; - if(*fnamelist != '\0') + while(pathlist && *pathlist) { const char *next, *end; - next = strchr(fnamelist, ','); - if(!next) - end = fnamelist + strlen(fnamelist); - else + while(isspace(*pathlist) || *pathlist == ',') + pathlist++; + if(*pathlist == '\0') + continue; + + next = strchr(pathlist, ','); + if(next) end = next++; + else + { + end = pathlist + strlen(pathlist); + usedefaults = false; + } - while(end != fnamelist && isspace(*(end-1))) + while(end != pathlist && isspace(*(end-1))) --end; - if(end != fnamelist) + if(end != pathlist) { - al_string fname = AL_STRING_INIT_STATIC(); + al_string pname = AL_STRING_INIT_STATIC(); vector_al_string flist; - al_string_append_range(&fname, fnamelist, end); + al_string_append_range(&pname, pathlist, end); - flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf"); + flist = SearchDataFiles(".mhr", al_string_get_cstr(pname)); VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); VECTOR_DEINIT(flist); - al_string_deinit(&fname); + al_string_deinit(&pname); } - fnamelist = next; + pathlist = next; } } + else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables")) + ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); + + if(usedefaults) + { + vector_al_string flist = SearchDataFiles(".mhr", "openal/hrtf"); + VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); + VECTOR_DEINIT(flist); + } if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) { diff --git a/alsoftrc.sample b/alsoftrc.sample index 9eb9740e..7d73b7c6 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -102,22 +102,18 @@ # that this is the enumerated HRTF name, not necessarily the filename. #default-hrtf = -## hrtf_tables: -# Specifies a comma-separated list of files containing HRTF data sets. The -# format of the files are described in hrtf.txt. The filenames may contain -# these markers, which will be replaced as needed: -# %r - Device sampling rate -# %s - Non-greedy string (up to the following matching characters) -# %% - Percent sign (%) -# The listed files are relative to system-dependant data directories. On -# Windows this is: +## hrtf-paths: +# Specifies a comma-separated list of paths containing HRTF data sets. The +# format of the files are described in hrtf.txt. The files within the +# directories must have the .mhr file extension to be recognized. By default, +# OS-dependent data paths will be used. They will also be used if the list +# ends with a comma. On Windows this is: # $AppData\openal\hrtf # And on other systems, it's (in order): # $XDG_DATA_HOME/openal/hrtf (defaults to $HOME/.local/share/openal/hrtf) # $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and # /usr/share/openal/hrtf) -# An absolute path may also be specified, if the given file is elsewhere. -#hrtf_tables = %s.mhr +#hrtf-paths = ## cf_level: # Sets the crossfeed level for stereo output. Valid values are: diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 17407498..382520af 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -494,21 +494,21 @@ void MainWindow::loadConfig(const QString &fname) ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive)); ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); - 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)); - hrtf_tables.removeDuplicates(); - if(!hrtf_tables.empty() && !hrtf_tables.contains("%s.mhr")) + QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); + if(hrtf_paths.size() == 1) + hrtf_paths = hrtf_paths[0].split(QChar(',')); + std::transform(hrtf_paths.begin(), hrtf_paths.end(), + hrtf_paths.begin(), std::mem_fun_ref(&QString::trimmed)); + if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty()) ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked); else { - hrtf_tables.removeOne("%s.mhr"); + hrtf_paths.removeAll(QString()); ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Checked); } + hrtf_paths.removeDuplicates(); ui->hrtfFileList->clear(); - ui->hrtfFileList->addItems(hrtf_tables); + ui->hrtfFileList->addItems(hrtf_paths); updateHrtfRemoveButton(); QString hrtfstate = settings.value("hrtf").toString().toLower(); @@ -712,20 +712,17 @@ void MainWindow::saveConfig(const QString &fname) const } strlist.clear(); - QList items = ui->hrtfFileList->findItems("*", Qt::MatchWildcard); - foreach(const QListWidgetItem *item, items) - strlist.append(item->text()); + for(int i = 0;i < ui->hrtfFileList->count();i++) + strlist.append(ui->hrtfFileList->item(i)->text()); if(!strlist.empty() && ui->defaultHrtfPathsCheckBox->isChecked()) - strlist.append("%s.mhr"); - settings.setValue("hrtf_tables", strlist.join(QChar(','))); + strlist.append(QString()); + settings.setValue("hrtf-paths", 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()); + for(int i = 0;i < ui->enabledBackendList->count();i++) + strlist.append(ui->enabledBackendList->item(i)->text()); + for(int i = 0;i < ui->disabledBackendList->count();i++) + strlist.append(QChar('-')+ui->disabledBackendList->item(i)->text()); if(strlist.size() == 0 && !ui->backendCheckBox->isChecked()) strlist.append("-all"); else if(ui->backendCheckBox->isChecked()) @@ -843,14 +840,10 @@ void MainWindow::updatePeriodCountSlider() void MainWindow::addHrtfFile() { - const QStringList datapaths = getAllDataPaths("/openal/hrtf"); - QStringList fnames = QFileDialog::getOpenFileNames(this, tr("Select Files"), - datapaths.empty() ? QString() : datapaths[0], - "HRTF Datasets(*.mhr);;All Files(*.*)"); - if(fnames.isEmpty() == false) - { - for(QStringList::iterator iter = fnames.begin();iter != fnames.end();iter++) - ui->hrtfFileList->addItem(*iter); + QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path")); + if(path.isEmpty() == false && !getAllDataPaths("/openal/hrtf").contains(path)) + { + ui->hrtfFileList->addItem(path); enableApplyButton(); } } diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 7e23c966..8c6a679d 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -510,7 +510,7 @@ frames needed for each mixing update. - HRTF Profiles + HRTF Profile Paths Qt::AlignCenter -- cgit v1.2.3 From c9b2a0ae26aa60c26506901be97b209ca772d368 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 11:03:58 -0800 Subject: Collect HRTF names from the paths list for alsoft-config --- utils/alsoft-config/mainwindow.cpp | 41 +++++++++++++++++++++++++++++++++----- utils/alsoft-config/mainwindow.h | 2 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 382520af..498be083 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -346,13 +346,13 @@ void MainWindow::cancelCloseAction() } -QStringList MainWindow::collectDefaultHrtfs() +QStringList MainWindow::collectHrtfs() { QStringList ret; - QStringList paths = getAllDataPaths("/openal/hrtf"); - foreach(const QString &name, paths) + + for(int i = 0;i < ui->hrtfFileList->count();i++) { - QDir dir(name); + QDir dir(ui->hrtfFileList->item(i)->text()); QStringList fnames = dir.entryList(QDir::Files | QDir::Readable); foreach(const QString &fname, fnames) { @@ -376,6 +376,37 @@ QStringList MainWindow::collectDefaultHrtfs() } } } + + if(ui->defaultHrtfPathsCheckBox->isChecked()) + { + QStringList paths = getAllDataPaths("/openal/hrtf"); + foreach(const QString &name, paths) + { + QDir dir(name); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable); + foreach(const QString &fname, fnames) + { + if(fname.endsWith(".mhr", Qt::CaseInsensitive)) + { + if(!ret.contains(fname)) + ret.push_back(fname); + else + { + size_t i = 1; + do { + QString s = fname+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); + } + } + } + } + } return ret; } @@ -523,7 +554,7 @@ void MainWindow::loadConfig(const QString &fname) ui->preferredHrtfComboBox->addItem("- Any -"); if(ui->defaultHrtfPathsCheckBox->isChecked()) { - QStringList hrtfs = collectDefaultHrtfs(); + QStringList hrtfs = collectHrtfs(); foreach(const QString &name, hrtfs) ui->preferredHrtfComboBox->addItem(name); } diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 66b4c650..69c2fda4 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -55,7 +55,7 @@ private: void closeEvent(QCloseEvent *event); - QStringList collectDefaultHrtfs(); + QStringList collectHrtfs(); void loadConfig(const QString &fname); void saveConfig(const QString &fname) const; -- cgit v1.2.3 From 93d73aae4d66ac558c7f6bdd601d9d4b371448ca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Feb 2016 11:12:57 -0800 Subject: Add speed and quality labels for the resampler slider And space out the buffer metric sliders from the edit boxes --- utils/alsoft-config/mainwindow.ui | 45 ++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 8c6a679d..96dae74d 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -299,7 +299,7 @@ mixed and being heard. - 70 + 80 20 160 23 @@ -416,7 +416,7 @@ frames needed for each mixing update. - 10 + 0 20 51 22 @@ -432,9 +432,9 @@ frames needed for each mixing update. - 90 + 60 80 - 351 + 421 81 @@ -447,9 +447,9 @@ frames needed for each mixing update. - 20 + 50 50 - 311 + 321 21 @@ -463,9 +463,9 @@ frames needed for each mixing update. - 20 + 80 30 - 311 + 251 23 @@ -473,6 +473,35 @@ frames needed for each mixing update. Qt::Horizontal + + + + 20 + 30 + 51 + 21 + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 340 + 30 + 51 + 21 + + + + Quality + + -- cgit v1.2.3 From d04970e568de8747a152db1ab036bbbfbf70f7f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Feb 2016 04:21:03 -0800 Subject: Exclude the file extension from the HRTF name --- Alc/hrtf.c | 10 +++++++++- utils/alsoft-config/mainwindow.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index eeb4be41..9436ee55 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -514,6 +514,7 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) struct Hrtf *hrtf = NULL; const HrtfEntry *iter; const char *name; + const char *ext; ALchar magic[8]; FILE *f; int i; @@ -575,10 +576,17 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ + ext = strrchr(name, '.'); i = 0; do { - al_string_copy_cstr(&entry.name, name); + if(!ext) + al_string_copy_cstr(&entry.name, name); + else + { + al_string_clear(&entry.name); + al_string_append_range(&entry.name, name, ext); + } if(i != 0) { char str[64]; diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 498be083..79c52a56 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -359,12 +359,12 @@ QStringList MainWindow::collectHrtfs() if(fname.endsWith(".mhr", Qt::CaseInsensitive)) { if(!ret.contains(fname)) - ret.push_back(fname); + ret.push_back(fname.left(fname.length()-4)); else { size_t i = 1; do { - QString s = fname+" #"+QString::number(i); + QString s = fname.left(fname.length()-4)+" #"+QString::number(i); if(!ret.contains(s)) { ret.push_back(s); @@ -389,12 +389,12 @@ QStringList MainWindow::collectHrtfs() if(fname.endsWith(".mhr", Qt::CaseInsensitive)) { if(!ret.contains(fname)) - ret.push_back(fname); + ret.push_back(fname.left(fname.length()-4)); else { size_t i = 1; do { - QString s = fname+" #"+QString::number(i); + QString s = fname.left(fname.length()-4)+" #"+QString::number(i); if(!ret.contains(s)) { ret.push_back(s); -- cgit v1.2.3 From b6824ca7168d20e7aada4b45a32aa93f48fc689c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Feb 2016 04:53:32 -0800 Subject: Add and use a copy-range string function --- Alc/alstring.h | 1 + Alc/helpers.c | 28 ++++++++++++++++++++-------- Alc/hrtf.c | 5 +---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Alc/alstring.h b/Alc/alstring.h index f53d2c57..6167f5ce 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -32,6 +32,7 @@ int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2); void al_string_copy(al_string *str, const_al_string from); void al_string_copy_cstr(al_string *str, const al_string_char_type *from); +void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); void al_string_append_char(al_string *str, const al_string_char_type c); void al_string_append_cstr(al_string *str, const al_string_char_type *from); diff --git a/Alc/helpers.c b/Alc/helpers.c index 20cd8900..f596c0d9 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -735,8 +735,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) al_string_copy_cstr(&path, str); else { - al_string_clear(&path); - al_string_append_range(&path, str, next); + al_string_copy_range(&path, str, next); ++next; } if(!al_string_empty(path)) @@ -861,12 +860,16 @@ extern inline const al_string_char_type *al_string_get_cstr(const_al_string str) void al_string_clear(al_string *str) { - /* Reserve one more character than the total size of the string. This is to - * ensure we have space to add a null terminator in the string data so it - * can be used as a C-style string. */ - VECTOR_RESERVE(*str, 1); - VECTOR_RESIZE(*str, 0); - *VECTOR_ITER_END(*str) = 0; + if(!al_string_empty(*str)) + { + /* Reserve one more character than the total size of the string. This + * is to ensure we have space to add a null terminator in the string + * data so it can be used as a C-style string. + */ + VECTOR_RESERVE(*str, 1); + VECTOR_RESIZE(*str, 0); + *VECTOR_ITER_END(*str) = 0; + } } static inline int al_string_compare(const al_string_char_type *str1, size_t str1len, @@ -910,6 +913,15 @@ void al_string_copy_cstr(al_string *str, const al_string_char_type *from) *VECTOR_ITER_END(*str) = 0; } +void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +{ + size_t len = to - from; + VECTOR_RESERVE(*str, len+1); + VECTOR_RESIZE(*str, 0); + VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to); + *VECTOR_ITER_END(*str) = 0; +} + void al_string_append_char(al_string *str, const al_string_char_type c) { VECTOR_RESERVE(*str, al_string_length(*str)+2); diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9436ee55..49c9793b 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -583,10 +583,7 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) if(!ext) al_string_copy_cstr(&entry.name, name); else - { - al_string_clear(&entry.name); - al_string_append_range(&entry.name, name, ext); - } + al_string_copy_range(&entry.name, name, ext); if(i != 0) { char str[64]; -- cgit v1.2.3 From 99a49122b84d69796e1798d758b2de13292edd0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Feb 2016 05:08:39 -0800 Subject: Sort HRTFs in alsoft-config like in the lib --- utils/alsoft-config/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 79c52a56..63a29714 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -353,7 +353,7 @@ QStringList MainWindow::collectHrtfs() for(int i = 0;i < ui->hrtfFileList->count();i++) { QDir dir(ui->hrtfFileList->item(i)->text()); - QStringList fnames = dir.entryList(QDir::Files | QDir::Readable); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); foreach(const QString &fname, fnames) { if(fname.endsWith(".mhr", Qt::CaseInsensitive)) @@ -383,7 +383,7 @@ QStringList MainWindow::collectHrtfs() foreach(const QString &name, paths) { QDir dir(name); - QStringList fnames = dir.entryList(QDir::Files | QDir::Readable); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); foreach(const QString &fname, fnames) { if(fname.endsWith(".mhr", Qt::CaseInsensitive)) -- cgit v1.2.3 From 3c127dc422291e438eade78bc656cec88035db4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Feb 2016 05:37:48 -0800 Subject: Update and add some tooltips --- utils/alsoft-config/mainwindow.ui | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 96dae74d..068db14f 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -554,15 +554,7 @@ frames needed for each mixing update. - A list of files containing HRTF data sets. The listed data sets -are used in place of the default sets. The filenames may -contain these markers, which will be replaced as needed: -%r - Device sampling rate -%s - Non-greedy string (up to the following matching characters) -%% - Percent sign (%) - - - false + A list of additional paths containing HRTF data sets. QAbstractItemView::InternalMove @@ -607,6 +599,10 @@ contain these markers, which will be replaced as needed: 21 + + Include the default system paths in addition to any +listed above. + Include Default Paths @@ -659,6 +655,10 @@ contain these markers, which will be replaced as needed: 22 + + Forces HRTF processing on or off, or leaves it to the +application or system to determine if it should be used. + QComboBox::AdjustToContentsOnFirstShow @@ -703,6 +703,9 @@ contain these markers, which will be replaced as needed: 22 + + The default HRTF to use if the application doesn't request one. + -- cgit v1.2.3 From 67f086d1d4527d1c920d90660124c5592b898354 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Feb 2016 12:57:03 -0800 Subject: Add a function to encode 2-channel UHJ from B-Format --- Alc/uhjfilter.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/uhjfilter.h | 49 +++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + 3 files changed, 141 insertions(+) create mode 100644 Alc/uhjfilter.c create mode 100644 Alc/uhjfilter.h diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c new file mode 100644 index 00000000..63a88aa7 --- /dev/null +++ b/Alc/uhjfilter.c @@ -0,0 +1,91 @@ + +#include "config.h" + +#include "alu.h" +#include "uhjfilter.h" + +/* This is the maximum number of samples processed for each inner loop + * iteration. */ +#define MAX_UPDATE_SAMPLES 256 + + +static const ALfloat Filter1Coeff[4] = { + 0.6923878f, 0.9360654322959f, 0.9882295226860f, 0.9987488452737f +}; +static const ALfloat Filter2Coeff[4] = { + 0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f +}; + +void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +{ + ALuint base, i, c; + + for(base = 0;base < SamplesToDo;) + { + ALfloat D[MAX_UPDATE_SAMPLES], S; + ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES); + + /* D = 0.6554516*Y */ + for(i = 0;i < todo;i++) + { + ALfloat in = 0.6554516f*InSamples[2][base+i]; + for(c = 0;c < 4;c++) + { + ALfloat aa = Filter1Coeff[c]*Filter1Coeff[c]; + ALfloat out = aa*(in + enc->Filter1_Y[c].y[1]) - enc->Filter1_Y[c].x[1]; + enc->Filter1_Y[c].x[1] = enc->Filter1_Y[c].x[0]; + enc->Filter1_Y[c].x[0] = in; + enc->Filter1_Y[c].y[1] = enc->Filter1_Y[c].y[0]; + enc->Filter1_Y[c].y[0] = out; + in = out; + } + /* NOTE: Filter1 requires a 1 sample delay for the base output, so + * take the sample before the last for output. + */ + D[i] = enc->Filter1_Y[3].y[1]; + } + + /* D += j(-0.3420201*W' + 0.5098604*X) */ + for(i = 0;i < todo;i++) + { + ALfloat in = -0.3420201f*1.414213562f*InSamples[0][base+i] + + 0.5098604f*InSamples[1][base+i]; + for(c = 0;c < 4;c++) + { + ALfloat aa = Filter2Coeff[c]*Filter2Coeff[c]; + ALfloat out = aa*(in + enc->Filter2_WX[c].y[1]) - enc->Filter2_WX[c].x[1]; + enc->Filter2_WX[c].x[1] = enc->Filter2_WX[c].x[0]; + enc->Filter2_WX[c].x[0] = in; + enc->Filter2_WX[c].y[1] = enc->Filter2_WX[c].y[0]; + enc->Filter2_WX[c].y[0] = out; + in = out; + } + D[i] += enc->Filter2_WX[3].y[0]; + } + + /* S = 0.9396926*W' + 0.1855740*X + * Left = (S + D)/2.0 + * Right = (S - D)/2.0 + */ + for(i = 0;i < todo;i++) + { + ALfloat in = 0.9396926f*1.414213562f*InSamples[0][base+i] + + 0.1855740f*InSamples[1][base+i]; + for(c = 0;c < 4;c++) + { + ALfloat aa = Filter1Coeff[c]*Filter1Coeff[c]; + ALfloat out = aa*(in + enc->Filter1_WX[c].y[1]) - enc->Filter1_WX[c].x[1]; + enc->Filter1_WX[c].x[1] = enc->Filter1_WX[c].x[0]; + enc->Filter1_WX[c].x[0] = in; + enc->Filter1_WX[c].y[1] = enc->Filter1_WX[c].y[0]; + enc->Filter1_WX[c].y[0] = out; + in = out; + } + S = enc->Filter1_WX[3].y[1]; + OutBuffer[0][base + i] += (S + D[i]) * 0.5f; + OutBuffer[1][base + i] += (S - D[i]) * 0.5f; + } + + base += todo; + } +} diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h new file mode 100644 index 00000000..5238e202 --- /dev/null +++ b/Alc/uhjfilter.h @@ -0,0 +1,49 @@ +#ifndef UHJFILTER_H +#define UHJFILTER_H + +#include "AL/al.h" + +#include "alMain.h" + +typedef struct AllPassState { + ALfloat x[2]; /* Last two input samples */ + ALfloat y[2]; /* Last two output samples */ +} AllPassState; + +/* Encoding 2-channel UHJ from B-Format is done as: + * + * W' = W * sqrt(2) + * S = 0.9396926*W' + 0.1855740*X + * D = j(-0.3420201*W' + 0.5098604*X) + 0.6554516*Y + * + * Left = (S + D)/2.0 + * Right = (S - D)/2.0 + * + * where j is a wide-band +90 degree phase shift. + * + * The phase shift is done using a Hilbert transform, described here: + * https://web.archive.org/web/20060708031958/http://www.biochem.oulu.fi/~oniemita/dsp/hilbert/ + * It works using 2 sets of 4 chained filters. The first filter chain produces + * a phase shift of varying magnitude over a wide range of frequencies, while + * the second filter chain produces a phase shift 90 degrees ahead of the + * first over the same range. + * + * Combining these two stages requires the use of three filter chains. S- + * channel output uses a Filter1 chain on the W and X channel mix, while the D- + * channel output uses a Filter1 chain on the Y channel plus a Filter2 chain on + * the W and X channel mix. This results in the W and X input mix on the D- + * channel output having the required +90 degree phase shift relative to the + * other inputs. + */ + +typedef struct Uhj2Encoder { + AllPassState Filter1_WX[4]; + AllPassState Filter1_Y[4]; + AllPassState Filter2_WX[4]; +} Uhj2Encoder; + +/* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input + * signal. */ +void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); + +#endif /* UHJFILTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5784d351..33eb180e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -643,6 +643,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/helpers.c Alc/bsinc.c Alc/hrtf.c + Alc/uhjfilter.c Alc/panning.c Alc/mixer.c Alc/mixer_c.c -- cgit v1.2.3 From ac91083ceb27892ce1d474a578634bff580b56d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Feb 2016 16:09:06 -0800 Subject: Use 2-channel UHJ for stereo output --- Alc/ALc.c | 33 ++++++++++++++----------- Alc/ALu.c | 61 +++++++++++++++++++++++------------------------ Alc/effects/reverb.c | 12 +++++----- Alc/panning.c | 22 ++++++++++++++++- OpenAL32/Include/alMain.h | 3 +++ 5 files changed, 79 insertions(+), 52 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d116650f..01fc8a34 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -36,6 +36,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "bs2b.h" +#include "uhjfilter.h" #include "alu.h" #include "compat.h" @@ -1846,6 +1847,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->Flags&DEVICE_RUNNING)) return ALC_NO_ERROR; + al_free(device->Uhj_Encoder); + device->Uhj_Encoder = NULL; + + al_free(device->Bs2b); + device->Bs2b = NULL; + al_free(device->DryBuffer); device->DryBuffer = NULL; @@ -1971,9 +1978,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { if(hrtf_appreq == Hrtf_Enable) device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - - free(device->Bs2b); - device->Bs2b = NULL; } else { @@ -2067,8 +2071,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Hrtf_Mode = hrtf_mode; device->Hrtf_Status = hrtf_status; TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); - free(device->Bs2b); - device->Bs2b = NULL; } else { @@ -2080,27 +2082,25 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { - if(!device->Bs2b) - { - device->Bs2b = calloc(1, sizeof(*device->Bs2b)); - bs2b_clear(device->Bs2b); - } + device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); TRACE("BS2B enabled\n"); } else { - free(device->Bs2b); - device->Bs2b = NULL; TRACE("BS2B disabled\n"); } + + device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); } } aluInitPanning(device); /* With HRTF, allocate two extra channels for the post-filter output. */ - size = sizeof(device->DryBuffer[0]) * (device->NumChannels + (device->Hrtf ? 2 : 0)); + size = device->NumChannels * sizeof(device->DryBuffer[0]); + if(device->Hrtf || device->Uhj_Encoder) + size += 2 * sizeof(device->DryBuffer[0]); device->DryBuffer = al_calloc(16, size); if(!device->DryBuffer) { @@ -2235,9 +2235,12 @@ static ALCvoid FreeDevice(ALCdevice *device) AL_STRING_DEINIT(device->Hrtf_Name); FreeHrtfList(&device->Hrtf_List); - free(device->Bs2b); + al_free(device->Bs2b); device->Bs2b = NULL; + al_free(device->Uhj_Encoder); + device->Uhj_Encoder = NULL; + AL_STRING_DEINIT(device->DeviceName); al_free(device->DryBuffer); @@ -3336,6 +3339,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Flags = 0; device->Bs2b = NULL; + device->Uhj_Encoder = NULL; VECTOR_INIT(device->Hrtf_List); AL_STRING_INIT(device->Hrtf_Name); device->Hrtf_Mode = DisabledHrtf; @@ -3782,6 +3786,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN VECTOR_INIT(device->Hrtf_List); AL_STRING_INIT(device->Hrtf_Name); device->Bs2b = NULL; + device->Uhj_Encoder = NULL; device->Hrtf_Mode = DisabledHrtf; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; diff --git a/Alc/ALu.c b/Alc/ALu.c index d4dac1ab..41d9a3fb 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -34,6 +34,7 @@ #include "alu.h" #include "bs2b.h" #include "hrtf.h" +#include "uhjfilter.h" #include "static_assert.h" #include "mixer_defs.h" @@ -100,19 +101,18 @@ extern inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33); -/* NOTE: HRTF is set up a bit special in the device. By default, without HRTF, - * the device's DryBuffer, NumChannels, ChannelName, and Channel fields - * correspond to the output format, and the DryBuffer is then converted and - * written to the backend's audio buffer. +/* NOTE: HRTF and UHJ are set up a bit special in the device. Normally the + * device's DryBuffer, NumChannels, ChannelName, and Channel fields correspond + * to the output format, and the DryBuffer is then converted and written to the + * backend's audio buffer. * - * With HRTF, these fields correspond to a virtual format, and the actual - * output is stored in DryBuffer[NumChannels] for the left channel and + * With HRTF or UHJ, these fields correspond to a virtual format, and the + * actual output is stored in DryBuffer[NumChannels] for the left channel and * DryBuffer[NumChannels+1] for the right. As a final output step, - * the virtual channels will have HRTF applied and written to the actual - * output. Things like effects and B-Format decoding will want to write to the - * virtual channels so that they can be mixed with HRTF in full 3D. + * the virtual channels will have HRTF filters or UHJ encoding applied and + * written to the actual output. * - * Sources that get mixed using HRTF directly (or that want to skip HRTF + * Sources that get mixed using HRTF directly (or that want to skip HRTF or UHJ * completely) will need to offset the output buffer so that they skip the * virtual output and write to the actual output channels. This is the reason * you'll see @@ -327,9 +327,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A }, StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } - }, StereoWideMap[2] = { - { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }, RearMap[2] = { { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } @@ -459,13 +456,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A break; case FmtStereo: - /* HACK: Place the stereo channels at +/-90 degrees when using non- - * HRTF stereo output. This helps reduce the "monoization" caused - * by them panning towards the center. */ - if(Device->FmtChans == DevFmtStereo && !Device->Hrtf) - chans = StereoWideMap; - else - chans = StereoMap; + chans = StereoMap; num_channels = 2; break; @@ -584,7 +575,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A if(DirectChannels) { - if(Device->Hrtf) + if(Device->Hrtf || Device->Uhj_Encoder) { /* DirectChannels with HRTF enabled. Skip the virtual channels * and write FrontLeft and FrontRight inputs to the first and @@ -1384,7 +1375,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) SamplesToDo = minu(size, BUFFERSIZE); for(c = 0;c < OutChannels;c++) memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Hrtf) + if(device->Hrtf || device->Uhj_Encoder) { /* Set OutBuffer/OutChannels to correspond to the actual output * with HRTF. Make sure to clear them too. */ @@ -1485,17 +1476,25 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } device->Hrtf_Offset += SamplesToDo; } - else if(device->Bs2b) + else { - /* Apply binaural/crossfeed filter */ - for(i = 0;i < SamplesToDo;i++) + if(device->Uhj_Encoder) { - float samples[2]; - samples[0] = device->DryBuffer[0][i]; - samples[1] = device->DryBuffer[1][i]; - bs2b_cross_feed(device->Bs2b, samples); - device->DryBuffer[0][i] = samples[0]; - device->DryBuffer[1][i] = samples[1]; + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo); + } + if(device->Bs2b) + { + /* Apply binaural/crossfeed filter */ + for(i = 0;i < SamplesToDo;i++) + { + float samples[2]; + samples[0] = OutBuffer[0][i]; + samples[1] = OutBuffer[1][i]; + bs2b_cross_feed(device->Bs2b, samples); + OutBuffer[0][i] = samples[0]; + OutBuffer[1][i] = samples[1]; + } } } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 103db906..7bbdb8a7 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -659,7 +659,7 @@ static ALvoid UpdateEchoLine(ALfloat echoTime, ALfloat decayTime, ALfloat diffus } // Update the early and late 3D panning gains. -static ALvoid UpdateHrtfPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) +static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) { ALfloat DirGains[MAX_OUTPUT_CHANNELS]; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -925,11 +925,11 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf) - UpdateHrtfPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, - props->Reverb.ReflectionsGain, - props->Reverb.LateReverbGain, State); + if(Device->Hrtf || Device->Uhj_Encoder) + UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, + props->Reverb.ReflectionsGain, + props->Reverb.LateReverbGain, State); else if(Device->FmtChans == DevFmtBFormat3D) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, diff --git a/Alc/panning.c b/Alc/panning.c index 9f1e87d7..b17df007 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -484,6 +484,10 @@ ALvoid aluInitPanning(ALCdevice *device) { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, + }, BFormat2D[3] = { + { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } }, }, BFormat3D[4] = { { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } }, @@ -493,6 +497,7 @@ ALvoid aluInitPanning(ALCdevice *device) const ChannelMap *chanmap = NULL; ALfloat ambiscale = 1.0f; size_t count = 0; + ALuint i; device->AmbiScale = 1.0f; memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs)); @@ -514,7 +519,6 @@ ALvoid aluInitPanning(ALCdevice *device) { LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) }, { LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) }, }; - ALuint i; count = COUNTOF(Cube8Cfg); chanmap = Cube8Cfg; @@ -536,6 +540,22 @@ ALvoid aluInitPanning(ALCdevice *device) } return; } + if(device->Uhj_Encoder) + { + count = COUNTOF(BFormat2D); + chanmap = BFormat2D; + ambiscale = FIRST_ORDER_SCALE; + + for(i = 0;i < count;i++) + device->ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->ChannelName[i] = InvalidChannel; + SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, + &device->NumChannels, AL_TRUE); + device->AmbiScale = ambiscale; + + return; + } if(LoadChannelSetup(device)) return; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 78475fa5..f9532727 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -470,6 +470,9 @@ struct ALCdevice_struct HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS]; ALuint Hrtf_Offset; + /* UHJ encoder state */ + struct Uhj2Encoder *Uhj_Encoder; + // Stereo-to-binaural filter struct bs2b *Bs2b; -- cgit v1.2.3 From 99f685d20d0e9bece99a6019a98d8cb3aecef227 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Feb 2016 21:48:03 -0800 Subject: Add an option for pair-wise stereo panning --- Alc/ALc.c | 34 ++++++++++++++++++++++-------- Alc/ALu.c | 53 ++++++++++++++++++++++++++++++++++++----------- OpenAL32/Include/alMain.h | 12 ++++++----- alsoftrc.sample | 8 +++++++ 4 files changed, 81 insertions(+), 26 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 01fc8a34..fd44ed28 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1972,8 +1972,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } device->Hrtf = NULL; - device->Hrtf_Mode = DisabledHrtf; al_string_clear(&device->Hrtf_Name); + device->Render_Mode = NormalRender; if(device->FmtChans != DevFmtStereo) { if(hrtf_appreq == Hrtf_Enable) @@ -1982,7 +1982,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) else { bool headphones = device->IsHeadphones; - enum HrtfMode hrtf_mode = FullHrtf; + enum RenderMode render_mode = HrtfRender; ALCenum hrtf_status = device->Hrtf_Status; const char *mode; int bs2blevel; @@ -2003,9 +2003,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) - hrtf_mode = FullHrtf; + render_mode = HrtfRender; else if(strcasecmp(mode, "basic") == 0) - hrtf_mode = BasicHrtf; + render_mode = NormalRender; else ERR("Unexpected hrtf-mode: %s\n", mode); } @@ -2068,8 +2068,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(device->Hrtf) { - device->Hrtf_Mode = hrtf_mode; device->Hrtf_Status = hrtf_status; + device->Render_Mode = render_mode; TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); } else @@ -2084,14 +2084,30 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + device->Render_Mode = StereoPair; TRACE("BS2B enabled\n"); } else { TRACE("BS2B disabled\n"); - } - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + render_mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) + { + if(strcasecmp(mode, "paired") == 0) + render_mode = StereoPair; + else if(strcasecmp(mode, "uhj") != 0) + ERR("Unexpected stereo-panning: %s\n", mode); + } + device->Render_Mode = render_mode; + if(render_mode == NormalRender) + { + device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + TRACE("UHJ enabled\n"); + } + else + TRACE("UHJ disabled\n"); + } } } @@ -3342,7 +3358,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Uhj_Encoder = NULL; VECTOR_INIT(device->Hrtf_List); AL_STRING_INIT(device->Hrtf_Name); - device->Hrtf_Mode = DisabledHrtf; + device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; @@ -3787,7 +3803,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN AL_STRING_INIT(device->Hrtf_Name); device->Bs2b = NULL; device->Uhj_Encoder = NULL; - device->Hrtf_Mode = DisabledHrtf; + device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; diff --git a/Alc/ALu.c b/Alc/ALu.c index 41d9a3fb..38a4ef71 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -577,9 +577,9 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { if(Device->Hrtf || Device->Uhj_Encoder) { - /* DirectChannels with HRTF enabled. Skip the virtual channels - * and write FrontLeft and FrontRight inputs to the first and - * second outputs. + /* DirectChannels with HRTF or UHJ enabled. Skip the virtual + * channels and write FrontLeft and FrontRight inputs to the + * first and second outputs. */ voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; @@ -627,7 +627,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->IsHrtf = AL_FALSE; } - else if(Device->Hrtf_Mode == FullHrtf) + else if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render each * input channel to the real outputs. @@ -686,7 +686,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } else { - /* Basic or no HRTF rendering. Use normal panning to the output. */ + /* Non-HRTF rendering. Use normal panning to the output. */ for(c = 0;c < num_channels;c++) { /* Special-case LFE */ @@ -707,9 +707,24 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A continue; } - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + if(Device->Render_Mode == StereoPair) + { + /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ + ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); + coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5; + voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain; + voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain; + for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Gains[c].Target[j] = 0.0f; - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, voice->Direct.Gains[c].Target); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + } + else + { + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, + voice->Direct.Gains[c].Target); + } for(i = 0;i < NumSends;i++) { @@ -1105,7 +1120,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte BufferListItem = BufferListItem->next; } - if(Device->Hrtf_Mode == FullHrtf) + if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. @@ -1170,7 +1185,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } else { - /* Basic or no HRTF rendering. Use normal panning to the output. */ + /* Non-HRTF rendering. */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -1193,10 +1208,24 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte dir[1] *= dirfact; dir[2] *= dirfact; } - CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, - voice->Direct.Gains[0].Target); + if(Device->Render_Mode == StereoPair) + { + /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ + coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5; + voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain; + voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain; + for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) + voice->Direct.Gains[0].Target[i] = 0.0f; + + CalcDirectionCoeffs(dir, coeffs); + } + else + { + CalcDirectionCoeffs(dir, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, + voice->Direct.Gains[0].Target); + } for(i = 0;i < NumSends;i++) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f9532727..8c75cb83 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -387,10 +387,10 @@ enum DeviceType { }; -enum HrtfMode { - DisabledHrtf, - BasicHrtf, - FullHrtf +enum RenderMode { + NormalRender, + StereoPair, + HrtfRender }; @@ -465,7 +465,6 @@ struct ALCdevice_struct al_string Hrtf_Name; const struct Hrtf *Hrtf; ALCenum Hrtf_Status; - enum HrtfMode Hrtf_Mode; HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS]; HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS]; ALuint Hrtf_Offset; @@ -476,6 +475,9 @@ struct ALCdevice_struct // Stereo-to-binaural filter struct bs2b *Bs2b; + /* Rendering mode. */ + enum RenderMode Render_Mode; + // Device flags ALuint Flags; diff --git a/alsoftrc.sample b/alsoftrc.sample index 7d73b7c6..255f82d0 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -86,6 +86,14 @@ # Valid settings are auto, speakers, and headphones. #stereo-mode = auto +## stereo-panning: +# Specifies the panning method for non-HRTF stereo output. uhj (default) +# creates stereo-compatible two-channel UHJ output, which encodes some +# surround sound information, while paired uses standard pair-wise panning +# between -30 and +30 degrees. If crossfeed filters are used, uhj panning is +# disabled. +#stereo-panning = uhj + ## hrtf: # Controls HRTF processing. These filters provide better spatialization of # sounds while using headphones, but do require a bit more CPU power. The -- cgit v1.2.3 From adce176a3579b548be1193137583234bd622b6a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 10:53:56 -0800 Subject: Separate the left and right output writes with UHJ encoding --- Alc/uhjfilter.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index 63a88aa7..cb1a4348 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -22,8 +22,8 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf for(base = 0;base < SamplesToDo;) { - ALfloat D[MAX_UPDATE_SAMPLES], S; - ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES); + ALfloat D[MAX_UPDATE_SAMPLES/2], S[MAX_UPDATE_SAMPLES/2]; + ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES/2); /* D = 0.6554516*Y */ for(i = 0;i < todo;i++) @@ -63,10 +63,7 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf D[i] += enc->Filter2_WX[3].y[0]; } - /* S = 0.9396926*W' + 0.1855740*X - * Left = (S + D)/2.0 - * Right = (S - D)/2.0 - */ + /* S = 0.9396926*W' + 0.1855740*X */ for(i = 0;i < todo;i++) { ALfloat in = 0.9396926f*1.414213562f*InSamples[0][base+i] + @@ -81,11 +78,17 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf enc->Filter1_WX[c].y[0] = out; in = out; } - S = enc->Filter1_WX[3].y[1]; - OutBuffer[0][base + i] += (S + D[i]) * 0.5f; - OutBuffer[1][base + i] += (S - D[i]) * 0.5f; + S[i] = enc->Filter1_WX[3].y[1]; } + /* Left = (S + D)/2.0 + * Right = (S - D)/2.0 + */ + for(i = 0;i < todo;i++) + OutBuffer[0][base + i] += (S[i] + D[i]) * 0.5f; + for(i = 0;i < todo;i++) + OutBuffer[1][base + i] += (S[i] - D[i]) * 0.5f; + base += todo; } } -- cgit v1.2.3 From 0e1edc151d410a73be29f01f2320812ab916a62b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 12:39:25 -0800 Subject: Move the Backends tab over --- utils/alsoft-config/mainwindow.ui | 160 +++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 068db14f..a362d845 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -708,6 +708,86 @@ application or system to determine if it should be used. + + + Backends + + + + + 170 + 200 + 161 + 21 + + + + When checked, allows all other available backends not listed in the priority or disabled lists. + + + Allow Other Backends + + + true + + + + + + 40 + 40 + 191 + 151 + + + + The backend driver list order. Unknown backends and +duplicated names are ignored. + + + QAbstractItemView::InternalMove + + + + + + 40 + 20 + 191 + 20 + + + + Priority Backends: + + + + + + 270 + 40 + 191 + 151 + + + + Disabled backend driver list. + + + + + + 270 + 20 + 191 + 20 + + + + Disabled Backends: + + + Resources @@ -948,86 +1028,6 @@ be useful for preventing those extensions from being used. - - - Backends - - - - - 170 - 200 - 161 - 21 - - - - When checked, allows all other available backends not listed in the priority or disabled lists. - - - Allow Other Backends - - - true - - - - - - 40 - 40 - 191 - 151 - - - - The backend driver list order. Unknown backends and -duplicated names are ignored. - - - QAbstractItemView::InternalMove - - - - - - 40 - 20 - 191 - 20 - - - - Priority Backends: - - - - - - 270 - 40 - 191 - 151 - - - - Disabled backend driver list. - - - - - - 270 - 20 - 191 - 20 - - - - Disabled Backends: - - - Effects -- cgit v1.2.3 From a12c420c591ef90dd50aabd435a9e995681232a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 19:18:57 -0800 Subject: Reorganize the Backends tab and add a PulseAudio section --- utils/alsoft-config/mainwindow.cpp | 26 +++- utils/alsoft-config/mainwindow.ui | 236 +++++++++++++++++++++++++++---------- 2 files changed, 199 insertions(+), 63 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 63a29714..f1516e4b 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -306,6 +306,13 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + ui->backendListWidget->setCurrentRow(0); + ui->tabWidget->setCurrentIndex(0); + loadConfig(getDefaultConfigName()); } @@ -631,6 +638,10 @@ void MainWindow::loadConfig(const QString &fname) ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); + ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool()); + ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); + ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); + ui->applyButton->setEnabled(false); ui->closeCancelButton->setText(tr("Close")); mNeedsSave = false; @@ -772,7 +783,7 @@ void MainWindow::saveConfig(const QString &fname) const if(ui->emulateEaxCheckBox->isChecked()) settings.setValue("reverb/emulate-eax", "true"); else - settings.setValue("reverb/emulate-eax", QString()/*"false"*/); + settings.remove("reverb/emulate-eax"/*, "false"*/); strlist.clear(); if(!ui->enableEaxReverbCheck->isChecked()) @@ -807,6 +818,19 @@ void MainWindow::saveConfig(const QString &fname) const if(str == QString()) settings.remove(key); } + + if(ui->pulseAutospawnCheckBox->isChecked()) + settings.remove("pulse/spawn-server"/*, "true"*/); + else + settings.setValue("pulse/spawn-server", "false"); + if(ui->pulseAllowMovesCheckBox->isChecked()) + settings.setValue("pulse/allow-moves", "true"); + else + settings.remove("pulse/allow-moves"/*, "false"*/); + if(ui->pulseFixRateCheckBox->isChecked()) + settings.setValue("pulse/fix-rate", "true"); + else + settings.remove("pulse/fix-rate"/*, "false"*/); } diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index a362d845..888546ce 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -712,80 +712,176 @@ application or system to determine if it should be used. Backends - + - 170 - 200 - 161 - 21 + 0 + 11 + 111 + 361 - - When checked, allows all other available backends not listed in the priority or disabled lists. - - - Allow Other Backends - - + true + + + General + + + + + PulseAudio + + - - - - 40 - 40 - 191 - 151 - - - - The backend driver list order. Unknown backends and -duplicated names are ignored. - - - QAbstractItemView::InternalMove - - - - - - 40 - 20 - 191 - 20 - - - - Priority Backends: - - - - - - 270 - 40 - 191 - 151 - - - - Disabled backend driver list. - - - + - 270 - 20 - 191 - 20 + 110 + 10 + 411 + 361 - - Disabled Backends: + + 0 + + + + + 20 + 190 + 391 + 21 + + + + When checked, allows all other available backends not listed in the priority or disabled lists. + + + Allow Other Backends + + + true + + + + + + 220 + 30 + 191 + 151 + + + + Disabled backend driver list. + + + + + + 20 + 30 + 191 + 151 + + + + The backend driver list order. Unknown backends and +duplicated names are ignored. + + + QAbstractItemView::InternalMove + + + + + + 230 + 10 + 171 + 20 + + + + Disabled Backends: + + + + + + 30 + 10 + 171 + 20 + + + + Priority Backends: + + + + + + + + 20 + 10 + 141 + 21 + + + + Automatically spawn a PulseAudio server if one +is not already running. + + + AutoSpawn Server + + + true + + + + + + 20 + 40 + 161 + 21 + + + + Allows moving PulseAudio streams to different +devices during playback or capture. Note that the +device specifier and device format will not change +to match the new device. + + + Allow Moving Streams + + + + + + 20 + 70 + 121 + 21 + + + + When checked, fix the OpenAL device's sample +rate to match the PulseAudio device. + + + Fix Sample Rate + + + @@ -1494,6 +1590,22 @@ added by the ALC_EXT_DEDICATED extension. + + backendListWidget + currentRowChanged(int) + backendStackedWidget + setCurrentIndex(int) + + + 69 + 233 + + + 329 + 232 + + + ShowHRTFContextMenu(QPoint) -- cgit v1.2.3 From 6d664367bcc6ae4214b95874c15427735334ab00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 19:37:42 -0800 Subject: Generalize the backend list --- utils/alsoft-config/mainwindow.cpp | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index f1516e4b..f0afbced 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -12,51 +12,51 @@ namespace { static const struct { char backend_name[16]; - char menu_string[32]; -} backendMenuList[] = { + char full_string[32]; +} backendList[] = { #ifdef HAVE_JACK - { "jack", "Add JACK" }, + { "jack", "JACK" }, #endif #ifdef HAVE_PULSEAUDIO - { "pulse", "Add PulseAudio" }, + { "pulse", "PulseAudio" }, #endif #ifdef HAVE_ALSA - { "alsa", "Add ALSA" }, + { "alsa", "ALSA" }, #endif #ifdef HAVE_COREAUDIO - { "core", "Add CoreAudio" }, + { "core", "CoreAudio" }, #endif #ifdef HAVE_OSS - { "oss", "Add OSS" }, + { "oss", "OSS" }, #endif #ifdef HAVE_SOLARIS - { "solaris", "Add Solaris" }, + { "solaris", "Solaris" }, #endif #ifdef HAVE_SNDIO - { "sndio", "Add SndIO" }, + { "sndio", "SoundIO" }, #endif #ifdef HAVE_QSA - { "qsa", "Add QSA" }, + { "qsa", "QSA" }, #endif #ifdef HAVE_MMDEVAPI - { "mmdevapi", "Add MMDevAPI" }, + { "mmdevapi", "MMDevAPI" }, #endif #ifdef HAVE_DSOUND - { "dsound", "Add DirectSound" }, + { "dsound", "DirectSound" }, #endif #ifdef HAVE_WINMM - { "winmm", "Add Windows Multimedia" }, + { "winmm", "Windows Multimedia" }, #endif #ifdef HAVE_PORTAUDIO - { "port", "Add PortAudio" }, + { "port", "PortAudio" }, #endif #ifdef HAVE_OPENSL - { "opensl", "Add OpenSL" }, + { "opensl", "OpenSL" }, #endif - { "null", "Add Null Output" }, + { "null", "Null Output" }, #ifdef HAVE_WAVE - { "wave", "Add Wave Writer" }, + { "wave", "Wave Writer" }, #endif { "", "" } }; @@ -930,12 +930,12 @@ void MainWindow::showEnabledBackendMenu(QPoint pt) if(ui->enabledBackendList->selectedItems().size() == 0) removeAction->setEnabled(false); ctxmenu.addSeparator(); - for(size_t i = 0;backendMenuList[i].backend_name[0];i++) + for(size_t i = 0;backendList[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) + QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string); + actionMap[action] = backendList[i].backend_name; + if(ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 || + ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } @@ -967,12 +967,12 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) if(ui->disabledBackendList->selectedItems().size() == 0) removeAction->setEnabled(false); ctxmenu.addSeparator(); - for(size_t i = 0;backendMenuList[i].backend_name[0];i++) + for(size_t i = 0;backendList[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) + QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string); + actionMap[action] = backendList[i].backend_name; + if(ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 || + ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } -- cgit v1.2.3 From 96520520be367cc0e2f708de0f2fb71b7cbb1223 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 21:52:36 -0800 Subject: Show the full name in the backend lists --- utils/alsoft-config/mainwindow.cpp | 67 ++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index f0afbced..30168773 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -598,10 +598,29 @@ void MainWindow::loadConfig(const QString &fname) foreach(const QString &backend, drivers) { lastWasEmpty = backend.isEmpty(); - if(!backend.startsWith(QChar('-')) && !lastWasEmpty) - ui->enabledBackendList->addItem(backend); + if(lastWasEmpty) continue; + + if(!backend.startsWith(QChar('-'))) + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(backend == backendList[j].backend_name) + { + ui->enabledBackendList->addItem(backendList[j].full_string); + break; + } + } else if(backend.size() > 1) - ui->disabledBackendList->addItem(backend.right(backend.size()-1)); + { + QStringRef backendref = backend.rightRef(backend.size()-1); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(backendref == backendList[j].backend_name) + { + ui->disabledBackendList->addItem(backendList[j].full_string); + break; + } + } + } } ui->backendCheckBox->setChecked(lastWasEmpty); } @@ -762,9 +781,29 @@ void MainWindow::saveConfig(const QString &fname) const strlist.clear(); for(int i = 0;i < ui->enabledBackendList->count();i++) - strlist.append(ui->enabledBackendList->item(i)->text()); + { + QString label = ui->enabledBackendList->item(i)->text(); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(label == backendList[j].full_string) + { + strlist.append(backendList[j].backend_name); + break; + } + } + } for(int i = 0;i < ui->disabledBackendList->count();i++) - strlist.append(QChar('-')+ui->disabledBackendList->item(i)->text()); + { + QString label = ui->disabledBackendList->item(i)->text(); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(label == backendList[j].full_string) + { + strlist.append(QChar('-')+QString(backendList[j].backend_name)); + break; + } + } + } if(strlist.size() == 0 && !ui->backendCheckBox->isChecked()) strlist.append("-all"); else if(ui->backendCheckBox->isChecked()) @@ -932,10 +971,11 @@ void MainWindow::showEnabledBackendMenu(QPoint pt) ctxmenu.addSeparator(); for(size_t i = 0;backendList[i].backend_name[0];i++) { - QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string); - actionMap[action] = backendList[i].backend_name; - if(ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 || - ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0) + QString backend = backendList[i].full_string; + QAction *action = ctxmenu.addAction(QString("Add ")+backend); + actionMap[action] = backend; + if(ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || + ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } @@ -969,10 +1009,11 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) ctxmenu.addSeparator(); for(size_t i = 0;backendList[i].backend_name[0];i++) { - QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string); - actionMap[action] = backendList[i].backend_name; - if(ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 || - ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0) + QString backend = backendList[i].full_string; + QAction *action = ctxmenu.addAction(QString("Add ")+backend); + actionMap[action] = backend; + if(ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || + ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) action->setEnabled(false); } -- cgit v1.2.3 From 11acbfebf7e1b49c5a420dcfd5505ac4c70b46ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Feb 2016 22:12:53 -0800 Subject: Hide backend list items for backends that aren't available --- utils/alsoft-config/mainwindow.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 30168773..127350f1 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -313,6 +313,17 @@ MainWindow::MainWindow(QWidget *parent) : ui->backendListWidget->setCurrentRow(0); ui->tabWidget->setCurrentIndex(0); + for(int i = 1;i < ui->backendListWidget->count();i++) + ui->backendListWidget->setRowHidden(i, true); + for(int i = 0;backendList[i].backend_name[0];i++) + { + QList items = ui->backendListWidget->findItems( + backendList[i].full_string, Qt::MatchFixedString + ); + foreach(const QListWidgetItem *item, items) + ui->backendListWidget->setItemHidden(item, false); + } + loadConfig(getDefaultConfigName()); } -- cgit v1.2.3 From 9e3a1942a39efedf685c74f49763f917ca404269 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Feb 2016 09:27:52 -0800 Subject: Add an ALSA backend tab --- utils/alsoft-config/mainwindow.cpp | 27 ++++++++++ utils/alsoft-config/mainwindow.ui | 107 ++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 127350f1..44302e53 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -310,6 +310,11 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->alsaDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->alsaDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->alsaResamplerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->alsaMmapCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + ui->backendListWidget->setCurrentRow(0); ui->tabWidget->setCurrentIndex(0); @@ -672,6 +677,11 @@ void MainWindow::loadConfig(const QString &fname) ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); + ui->alsaDefaultDeviceLine->setText(settings.value("alsa/device", QString()).toString()); + ui->alsaDefaultCaptureLine->setText(settings.value("alsa/capture", QString()).toString()); + ui->alsaResamplerCheckBox->setChecked(settings.value("alsa/allow-resampler", false).toBool()); + ui->alsaMmapCheckBox->setChecked(settings.value("alsa/mmap", true).toBool()); + ui->applyButton->setEnabled(false); ui->closeCancelButton->setText(tr("Close")); mNeedsSave = false; @@ -881,6 +891,23 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("pulse/fix-rate", "true"); else settings.remove("pulse/fix-rate"/*, "false"*/); + + str = ui->alsaDefaultDeviceLine->text(); + if(str.isEmpty()) settings.remove("alsa/device"); + else settings.setValue("alsa/device", str); + + str = ui->alsaDefaultCaptureLine->text(); + if(str.isEmpty()) settings.remove("alsa/capture"); + else settings.setValue("alsa/capture", str); + + if(ui->alsaResamplerCheckBox->isChecked()) + settings.setValue("alsa/allow-resampler", "true"); + else + settings.remove("alsa/allow-resampler"); + if(ui->alsaMmapCheckBox->isChecked()) + settings.remove("alsa/mmap"); + else + settings.setValue("alsa/mmap", "false"); } diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 888546ce..3c6629f0 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -734,13 +734,18 @@ application or system to determine if it should be used. PulseAudio + + + ALSA + + 110 10 - 411 + 421 361 @@ -882,6 +887,106 @@ rate to match the PulseAudio device. + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 30 + 231 + 21 + + + + default + + + + + + 10 + 60 + 141 + 21 + + + + Default Capture Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 60 + 231 + 21 + + + + default + + + + + + 20 + 100 + 191 + 21 + + + + Allow use of ALSA's software resampler. This lets +the OpenAL device to be set to a different sample +rate than the backend device, but incurs another +resample pass on top of OpenAL's resampler. + + + Allow Resampler + + + + + + 210 + 100 + 191 + 21 + + + + Accesses the audio device buffer through an mmap, +potentially avoiding an extra sample buffer copy +during updates. + + + MMap Buffer + + + true + + + -- cgit v1.2.3 From 81384949e2f3672ecd25797a31fbaa2d842492cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Feb 2016 09:34:02 -0800 Subject: Properly check for preexisting HRTF names --- utils/alsoft-config/mainwindow.cpp | 66 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 44302e53..81b3a8e8 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -379,23 +379,24 @@ QStringList MainWindow::collectHrtfs() QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); foreach(const QString &fname, fnames) { - if(fname.endsWith(".mhr", Qt::CaseInsensitive)) + if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) + continue; + + QString name = fname.left(fname.length()-4); + if(!ret.contains(name)) + ret.push_back(name); + else { - if(!ret.contains(fname)) - ret.push_back(fname.left(fname.length()-4)); - else - { - size_t i = 1; - do { - QString s = fname.left(fname.length()-4)+" #"+QString::number(i); - if(!ret.contains(s)) - { - ret.push_back(s); - break; - } - ++i; - } while(1); - } + size_t i = 1; + do { + QString s = name+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); } } } @@ -409,23 +410,24 @@ QStringList MainWindow::collectHrtfs() QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); foreach(const QString &fname, fnames) { - if(fname.endsWith(".mhr", Qt::CaseInsensitive)) + if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) + continue; + + QString name = fname.left(fname.length()-4); + if(!ret.contains(name)) + ret.push_back(name); + else { - if(!ret.contains(fname)) - ret.push_back(fname.left(fname.length()-4)); - else - { - size_t i = 1; - do { - QString s = fname.left(fname.length()-4)+" #"+QString::number(i); - if(!ret.contains(s)) - { - ret.push_back(s); - break; - } - ++i; - } while(1); - } + size_t i = 1; + do { + QString s = name+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); } } } -- cgit v1.2.3 From abf6a9260a18bc5d4e69e9c7b8bce35509ade816 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Feb 2016 20:55:41 -0800 Subject: Add an option to select between UHJ and pair-wise mixing. --- utils/alsoft-config/mainwindow.cpp | 17 ++++++++++++++ utils/alsoft-config/mainwindow.ui | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 81b3a8e8..f072773a 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -269,6 +269,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); + connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); @@ -539,6 +541,14 @@ void MainWindow::loadConfig(const QString &fname) updatePeriodCountSlider(); } + QString stereopan = settings.value("stereo-panning").toString(); + if(stereopan == "uhj") + ui->stereoPanningComboBox->setCurrentIndex(1); + else if(stereopan == "paired") + ui->stereoPanningComboBox->setCurrentIndex(2); + else + ui->stereoPanningComboBox->setCurrentIndex(0); + QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); if(disabledCpuExts.size() == 1) disabledCpuExts = disabledCpuExts[0].split(QChar(',')); @@ -767,6 +777,13 @@ void MainWindow::saveConfig(const QString &fname) const } } + if(ui->stereoPanningComboBox->currentIndex() == 1) + settings.setValue("stereo-panning", "uhj"); + else if(ui->stereoPanningComboBox->currentIndex() == 2) + settings.setValue("stereo-panning", "paired"); + else + settings.remove("stereo-panning"); + QStringList strlist; if(!ui->enableSSECheckBox->isChecked()) strlist.append("sse"); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 3c6629f0..8eb3162c 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -428,6 +428,54 @@ frames needed for each mixing update. + + + + 130 + 130 + 131 + 22 + + + + Selects the panning method for non-HRTF stereo +mixing. UHJ creates stereo-compatible two-channel +output, which encodes some surround information. +Pair-Wise uses standard pair-wise panning between +-30 and +30 degrees. The default is UHJ. + + + + Default + + + + + UHJ + + + + + Pair-Wise + + + + + + + 20 + 130 + 101 + 21 + + + + Stereo Panning: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + -- cgit v1.2.3 From c89511b95e6e6920c3be3086c98463284090de65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Feb 2016 21:55:58 -0800 Subject: Properly remove empty config values --- utils/alsoft-config/mainwindow.cpp | 49 +++++++++++++++----------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index f072773a..1fd6f81e 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -887,6 +887,25 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("dedicated"); settings.setValue("excludefx", strlist.join(QChar(','))); + settings.setValue("pulse/spawn-server", + ui->pulseAutospawnCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + settings.setValue("pulse/allow-moves", + ui->pulseAllowMovesCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("pulse/fix-rate", + ui->pulseFixRateCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + + settings.setValue("alsa/device", ui->alsaDefaultDeviceLine->text()); + settings.setValue("alsa/capture", ui->alsaDefaultCaptureLine->text()); + settings.setValue("alsa/allow-resampler", + ui->alsaResamplerCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("alsa/mmap", + ui->alsaMmapCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + /* Remove empty keys * FIXME: Should only remove keys whose value matches the globally-specified value. */ @@ -897,36 +916,6 @@ void MainWindow::saveConfig(const QString &fname) const if(str == QString()) settings.remove(key); } - - if(ui->pulseAutospawnCheckBox->isChecked()) - settings.remove("pulse/spawn-server"/*, "true"*/); - else - settings.setValue("pulse/spawn-server", "false"); - if(ui->pulseAllowMovesCheckBox->isChecked()) - settings.setValue("pulse/allow-moves", "true"); - else - settings.remove("pulse/allow-moves"/*, "false"*/); - if(ui->pulseFixRateCheckBox->isChecked()) - settings.setValue("pulse/fix-rate", "true"); - else - settings.remove("pulse/fix-rate"/*, "false"*/); - - str = ui->alsaDefaultDeviceLine->text(); - if(str.isEmpty()) settings.remove("alsa/device"); - else settings.setValue("alsa/device", str); - - str = ui->alsaDefaultCaptureLine->text(); - if(str.isEmpty()) settings.remove("alsa/capture"); - else settings.setValue("alsa/capture", str); - - if(ui->alsaResamplerCheckBox->isChecked()) - settings.setValue("alsa/allow-resampler", "true"); - else - settings.remove("alsa/allow-resampler"); - if(ui->alsaMmapCheckBox->isChecked()) - settings.remove("alsa/mmap"); - else - settings.setValue("alsa/mmap", "false"); } -- cgit v1.2.3 From 9fdca9e29f15e05c26d9b80ec4ba97a34b7b5277 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Mar 2016 13:37:12 -0800 Subject: Remove the extra scaling on W for UHJ encoding There seems to be some inconsistent info about whether W should be scaled by sqrt(2) for encoding. Not applying the scaling results in a wider stereo image, which seems more appropriate. --- Alc/uhjfilter.c | 33 ++++++++++++++++++++++++++------- Alc/uhjfilter.h | 5 ++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index cb1a4348..b410967a 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -16,6 +16,26 @@ static const ALfloat Filter2Coeff[4] = { 0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f }; +/* NOTE: There seems to be a bit of an inconsistency in how this encoding is + * supposed to work. Some references, such as + * + * http://members.tripod.com/martin_leese/Ambisonic/UHJ_file_format.html + * + * specify a pre-scaling of sqrt(2) on the W channel input, while other + * references, such as + * + * https://en.wikipedia.org/wiki/Ambisonic_UHJ_format#Encoding.5B1.5D + * and + * https://wiki.xiph.org/Ambisonics#UHJ_format + * + * do not. The sqrt(2) scaling is in line with B-Format decoder coefficients + * which include such a scaling for the W channel input, however the original + * source for this equation is a 1985 paper by Michael Gerzon, which does not + * apparently include the scaling. Applying the extra scaling creates a louder + * result with a narrower stereo image compared to not scaling, and I don't + * know which is the intended result. + */ + void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { ALuint base, i, c; @@ -45,10 +65,10 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf D[i] = enc->Filter1_Y[3].y[1]; } - /* D += j(-0.3420201*W' + 0.5098604*X) */ + /* D += j(-0.3420201*W + 0.5098604*X) */ for(i = 0;i < todo;i++) { - ALfloat in = -0.3420201f*1.414213562f*InSamples[0][base+i] + + ALfloat in = -0.3420201f*InSamples[0][base+i] + 0.5098604f*InSamples[1][base+i]; for(c = 0;c < 4;c++) { @@ -63,10 +83,10 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf D[i] += enc->Filter2_WX[3].y[0]; } - /* S = 0.9396926*W' + 0.1855740*X */ + /* S = 0.9396926*W + 0.1855740*X */ for(i = 0;i < todo;i++) { - ALfloat in = 0.9396926f*1.414213562f*InSamples[0][base+i] + + ALfloat in = 0.9396926f*InSamples[0][base+i] + 0.1855740f*InSamples[1][base+i]; for(c = 0;c < 4;c++) { @@ -81,11 +101,10 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf S[i] = enc->Filter1_WX[3].y[1]; } - /* Left = (S + D)/2.0 - * Right = (S - D)/2.0 - */ + /* Left = (S + D)/2.0 */ for(i = 0;i < todo;i++) OutBuffer[0][base + i] += (S[i] + D[i]) * 0.5f; + /* Right = (S - D)/2.0 */ for(i = 0;i < todo;i++) OutBuffer[1][base + i] += (S[i] - D[i]) * 0.5f; diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 5238e202..a5aa9275 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -12,9 +12,8 @@ typedef struct AllPassState { /* Encoding 2-channel UHJ from B-Format is done as: * - * W' = W * sqrt(2) - * S = 0.9396926*W' + 0.1855740*X - * D = j(-0.3420201*W' + 0.5098604*X) + 0.6554516*Y + * S = 0.9396926*W + 0.1855740*X + * D = j(-0.3420201*W + 0.5098604*X) + 0.6554516*Y * * Left = (S + D)/2.0 * Right = (S - D)/2.0 -- cgit v1.2.3 From 71d927333f15c2c43ec0f1974c819cd277386dfa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Mar 2016 12:08:22 -0800 Subject: Add OSS and Solaris config pages --- utils/alsoft-config/mainwindow.cpp | 48 +++++++++++++ utils/alsoft-config/mainwindow.h | 5 ++ utils/alsoft-config/mainwindow.ui | 140 +++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 1fd6f81e..1a7c7fef 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -317,6 +317,14 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->alsaResamplerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->alsaMmapCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->ossDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ossPlaybackPushButton, SIGNAL(pressed()), this, SLOT(selectOSSPlayback())); + connect(ui->ossDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ossCapturePushButton, SIGNAL(pressed()), this, SLOT(selectOSSCapture())); + + connect(ui->solarisDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->solarisPlaybackPushButton, SIGNAL(pressed()), this, SLOT(selectSolarisPlayback())); + ui->backendListWidget->setCurrentRow(0); ui->tabWidget->setCurrentIndex(0); @@ -694,6 +702,11 @@ void MainWindow::loadConfig(const QString &fname) ui->alsaResamplerCheckBox->setChecked(settings.value("alsa/allow-resampler", false).toBool()); ui->alsaMmapCheckBox->setChecked(settings.value("alsa/mmap", true).toBool()); + ui->ossDefaultDeviceLine->setText(settings.value("oss/device", QString()).toString()); + ui->ossDefaultCaptureLine->setText(settings.value("oss/capture", QString()).toString()); + + ui->solarisDefaultDeviceLine->setText(settings.value("solaris/device", QString()).toString()); + ui->applyButton->setEnabled(false); ui->closeCancelButton->setText(tr("Close")); mNeedsSave = false; @@ -906,6 +919,11 @@ void MainWindow::saveConfig(const QString &fname) const ui->alsaMmapCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") ); + settings.setValue("oss/device", ui->ossDefaultDeviceLine->text()); + settings.setValue("oss/capture", ui->ossDefaultCaptureLine->text()); + + settings.setValue("solaris/device", ui->solarisDefaultDeviceLine->text()); + /* Remove empty keys * FIXME: Should only remove keys whose value matches the globally-specified value. */ @@ -1079,3 +1097,33 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) enableApplyButton(); } } + +void MainWindow::selectOSSPlayback() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device")); + if(!fname.isEmpty()) + { + ui->ossDefaultDeviceLine->setText(fname); + enableApplyButton(); + } +} + +void MainWindow::selectOSSCapture() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Select Capture Device")); + if(!fname.isEmpty()) + { + ui->ossDefaultCaptureLine->setText(fname); + enableApplyButton(); + } +} + +void MainWindow::selectSolarisPlayback() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device")); + if(!fname.isEmpty()) + { + ui->solarisDefaultDeviceLine->setText(fname); + enableApplyButton(); + } +} diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 69c2fda4..78285dfa 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -41,6 +41,11 @@ private slots: void showEnabledBackendMenu(QPoint pt); void showDisabledBackendMenu(QPoint pt); + void selectOSSPlayback(); + void selectOSSCapture(); + + void selectSolarisPlayback(); + private: Ui::MainWindow *ui; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 8eb3162c..5adfc89c 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -787,6 +787,16 @@ application or system to determine if it should be used. ALSA + + + OSS + + + + + Solaris + + @@ -1035,6 +1045,136 @@ during updates. + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 30 + 151 + 21 + + + + /dev/dsp + + + + + + 10 + 60 + 141 + 21 + + + + Default Capture Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 60 + 151 + 21 + + + + /dev/dsp + + + + + + 320 + 30 + 91 + 22 + + + + Browse... + + + + + + 320 + 60 + 91 + 22 + + + + Browse... + + + + + + + + 160 + 30 + 151 + 21 + + + + /dev/audio + + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 320 + 30 + 91 + 22 + + + + Browse... + + + -- cgit v1.2.3 From 773e2846e735c55c123cecb2ff57a50f64e90aa7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Mar 2016 15:31:14 -0800 Subject: Add a Wave Writer backend config page --- utils/alsoft-config/mainwindow.cpp | 24 +++++++++++++ utils/alsoft-config/mainwindow.h | 2 ++ utils/alsoft-config/mainwindow.ui | 72 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 1a7c7fef..dca1816c 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -325,6 +325,10 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->solarisDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->solarisPlaybackPushButton, SIGNAL(pressed()), this, SLOT(selectSolarisPlayback())); + connect(ui->waveOutputLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->waveOutputButton, SIGNAL(pressed()), this, SLOT(selectWaveOutput())); + connect(ui->waveBFormatCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + ui->backendListWidget->setCurrentRow(0); ui->tabWidget->setCurrentIndex(0); @@ -707,6 +711,9 @@ void MainWindow::loadConfig(const QString &fname) ui->solarisDefaultDeviceLine->setText(settings.value("solaris/device", QString()).toString()); + ui->waveOutputLine->setText(settings.value("wave/file", QString()).toString()); + ui->waveBFormatCheckBox->setChecked(settings.value("wave/bformat", false).toBool()); + ui->applyButton->setEnabled(false); ui->closeCancelButton->setText(tr("Close")); mNeedsSave = false; @@ -924,6 +931,11 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("solaris/device", ui->solarisDefaultDeviceLine->text()); + settings.setValue("wave/file", ui->waveOutputLine->text()); + settings.setValue("wave/bformat", + ui->waveBFormatCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + /* Remove empty keys * FIXME: Should only remove keys whose value matches the globally-specified value. */ @@ -1127,3 +1139,15 @@ void MainWindow::selectSolarisPlayback() enableApplyButton(); } } + +void MainWindow::selectWaveOutput() +{ + QString fname = QFileDialog::getSaveFileName(this, tr("Select Wave File Output"), + ui->waveOutputLine->text(), tr("Wave Files (*.wav *.amb);;All Files (*.*)") + ); + if(!fname.isEmpty()) + { + ui->waveOutputLine->setText(fname); + enableApplyButton(); + } +} diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 78285dfa..27f3c252 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -46,6 +46,8 @@ private slots: void selectSolarisPlayback(); + void selectWaveOutput(); + private: Ui::MainWindow *ui; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 5adfc89c..28540a73 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -797,6 +797,11 @@ application or system to determine if it should be used. Solaris + + + Wave Writer + + @@ -1175,6 +1180,73 @@ during updates. + + + + + 10 + 30 + 71 + 21 + + + + Output File: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 90 + 30 + 221 + 21 + + + + + + + 0 + 90 + 421 + 71 + + + + <html><head/><body><p align="center"><span style=" font-style:italic;">Warning: The specified output file will be OVERWRITTEN WITHOUT</span></p><p align="center"><span style=" font-style:italic;">QUESTION when the Wave Writer device is opened.</span></p></body></html> + + + + + + 320 + 30 + 91 + 22 + + + + Browse... + + + + + + 120 + 60 + 191 + 21 + + + + Create .amb (B-Format) files + + + -- cgit v1.2.3 From d169fd859de5f9545d0b78f385aa6f1320925817 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Mar 2016 15:43:51 -0800 Subject: Use the clicked() signal for the Browse buttons --- utils/alsoft-config/mainwindow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index dca1816c..03c1fc5e 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -318,15 +318,15 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->alsaMmapCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->ossDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->ossPlaybackPushButton, SIGNAL(pressed()), this, SLOT(selectOSSPlayback())); + connect(ui->ossPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSPlayback())); connect(ui->ossDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->ossCapturePushButton, SIGNAL(pressed()), this, SLOT(selectOSSCapture())); + connect(ui->ossCapturePushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSCapture())); connect(ui->solarisDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->solarisPlaybackPushButton, SIGNAL(pressed()), this, SLOT(selectSolarisPlayback())); + connect(ui->solarisPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectSolarisPlayback())); connect(ui->waveOutputLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->waveOutputButton, SIGNAL(pressed()), this, SLOT(selectWaveOutput())); + connect(ui->waveOutputButton, SIGNAL(clicked(bool)), this, SLOT(selectWaveOutput())); connect(ui->waveBFormatCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); ui->backendListWidget->setCurrentRow(0); -- cgit v1.2.3 From 457c34c18965611b7b33bc62345e3e74142ec0dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 Mar 2016 23:18:07 -0800 Subject: Add a backend tab page for JACK options --- utils/alsoft-config/mainwindow.cpp | 39 ++++++++++++++++++ utils/alsoft-config/mainwindow.h | 4 ++ utils/alsoft-config/mainwindow.ui | 82 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 03c1fc5e..4eb5f25a 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1,6 +1,8 @@ #include "config.h" +#include + #include #include #include @@ -10,6 +12,7 @@ #include "ui_mainwindow.h" namespace { + static const struct { char backend_name[16]; char full_string[32]; @@ -164,6 +167,7 @@ static QStringList getAllDataPaths(QString append=QString()) } return list; } + } MainWindow::MainWindow(QWidget *parent) : @@ -175,6 +179,7 @@ MainWindow::MainWindow(QWidget *parent) : mEffectSlotValidator(NULL), mSourceSendValidator(NULL), mSampleRateValidator(NULL), + mJackBufferValidator(NULL), mNeedsSave(false) { ui->setupUi(this); @@ -250,6 +255,9 @@ MainWindow::MainWindow(QWidget *parent) : mSampleRateValidator = new QIntValidator(8000, 192000, this); ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator); + mJackBufferValidator = new QIntValidator(0, 8192, this); + ui->jackBufferSizeLine->setValidator(mJackBufferValidator); + connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); @@ -312,6 +320,10 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->jackAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->jackBufferSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateJackBufferSizeEdit(int))); + connect(ui->jackBufferSizeLine, SIGNAL(editingFinished()), this, SLOT(updateJackBufferSizeSlider())); + connect(ui->alsaDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->alsaDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->alsaResamplerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -355,6 +367,7 @@ MainWindow::~MainWindow() delete mEffectSlotValidator; delete mSourceSendValidator; delete mSampleRateValidator; + delete mJackBufferValidator; } void MainWindow::closeEvent(QCloseEvent *event) @@ -701,6 +714,10 @@ void MainWindow::loadConfig(const QString &fname) ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); + ui->jackAutospawnCheckBox->setChecked(settings.value("jack/spawn-server", false).toBool()); + ui->jackBufferSizeLine->setText(settings.value("jack/buffer-size", QString()).toString()); + updateJackBufferSizeSlider(); + ui->alsaDefaultDeviceLine->setText(settings.value("alsa/device", QString()).toString()); ui->alsaDefaultCaptureLine->setText(settings.value("alsa/capture", QString()).toString()); ui->alsaResamplerCheckBox->setChecked(settings.value("alsa/allow-resampler", false).toBool()); @@ -917,6 +934,11 @@ void MainWindow::saveConfig(const QString &fname) const ui->pulseFixRateCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); + settings.setValue("jack/spawn-server", + ui->jackAutospawnCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("jack/buffer-size", ui->jackBufferSizeLine->text()); + settings.setValue("alsa/device", ui->alsaDefaultDeviceLine->text()); settings.setValue("alsa/capture", ui->alsaDefaultCaptureLine->text()); settings.setValue("alsa/allow-resampler", @@ -1008,6 +1030,23 @@ void MainWindow::updatePeriodCountSlider() } +void MainWindow::updateJackBufferSizeEdit(int size) +{ + ui->jackBufferSizeLine->clear(); + if(size > 0) + ui->jackBufferSizeLine->insert(QString::number(1<jackBufferSizeLine->text().toInt(); + int pos = (int)floor(log2(value) + 0.5); + ui->jackBufferSizeSlider->setSliderPosition(pos); + enableApplyButton(); +} + + void MainWindow::addHrtfFile() { QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path")); diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 27f3c252..0ddb9a92 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -33,6 +33,9 @@ private slots: void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); + void updateJackBufferSizeEdit(int size); + void updateJackBufferSizeSlider(); + void addHrtfFile(); void removeHrtfFile(); @@ -57,6 +60,7 @@ private: QValidator *mEffectSlotValidator; QValidator *mSourceSendValidator; QValidator *mSampleRateValidator; + QValidator *mJackBufferValidator; bool mNeedsSave; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 28540a73..28c699f3 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -782,6 +782,11 @@ application or system to determine if it should be used. PulseAudio + + + JACK + + ALSA @@ -950,6 +955,83 @@ rate to match the PulseAudio device. + + + + + 20 + 10 + 141 + 21 + + + + AutoSpawn Server + + + + + + 10 + 40 + 401 + 80 + + + + The update buffer size, in samples, that the backend +will keep buffered to handle the server's real-time +processing requests. Must be a power of 2. + + + Buffer Size + + + Qt::AlignCenter + + + + + 320 + 30 + 71 + 21 + + + + 0 + + + + + + 10 + 30 + 301 + 23 + + + + 13 + + + 1 + + + 4 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 1 + + + + -- cgit v1.2.3 From 4e3fdf9f5d79b45915ea773bf9e70ccfcc3799f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Mar 2016 01:41:42 -0800 Subject: Fix reverb with UHJ encoding --- Alc/effects/reverb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7bbdb8a7..995ad6a5 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -364,7 +364,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; - State->ExtraChannels = (Device->Hrtf ? 2 : 0); + State->ExtraChannels = (Device->Hrtf || Device->Uhj_Encoder) ? 2 : 0; // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the -- cgit v1.2.3 From 1ca45fa3eb1ad303bbcd1e40ec97891ca8c3fab1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Mar 2016 16:45:10 -0800 Subject: Use the correct index for finding an empty string --- utils/alsoft-config/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4eb5f25a..9fef1242 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -493,7 +493,7 @@ void MainWindow::loadConfig(const QString &fname) ui->channelConfigCombo->setCurrentIndex(0); if(channelconfig.isEmpty() == false) { - for(int i = 0;speakerModeList[i].name[i];i++) + for(int i = 0;speakerModeList[i].name[0];i++) { if(channelconfig == speakerModeList[i].value) { @@ -526,7 +526,7 @@ void MainWindow::loadConfig(const QString &fname) * "sinc4". */ if(resampler == "cubic") resampler = "sinc4"; - for(int i = 0;resamplerList[i].name[i];i++) + for(int i = 0;resamplerList[i].name[0];i++) { if(resampler == resamplerList[i].value) { -- cgit v1.2.3 From 58aa1751c3374d500e800499202d8fa528f000fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Mar 2016 19:20:38 -0800 Subject: Handle the stereo panning option dynamically --- utils/alsoft-config/mainwindow.cpp | 47 ++++++++++++++++++++++++++------------ utils/alsoft-config/mainwindow.ui | 15 ------------ 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 9fef1242..a21b8c15 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -103,6 +103,12 @@ static const struct { { "Speakers", "speakers" }, { "Headphones", "headphones" }, + { "", "" } +}, stereoPanList[] = { + { "Default", "" }, + { "UHJ", "uhj" }, + { "Pair-Wise", "paired" }, + { "", "" } }; @@ -193,6 +199,9 @@ MainWindow::MainWindow(QWidget *parent) : for(int i = 0;stereoModeList[i].name[0];i++) ui->stereoModeCombo->addItem(stereoModeList[i].name); ui->stereoModeCombo->adjustSize(); + for(int i = 0;stereoPanList[i].name[0];i++) + ui->stereoPanningComboBox->addItem(stereoPanList[i].name); + ui->stereoPanningComboBox->adjustSize(); int count; for(count = 0;resamplerList[count].name[0];count++) { @@ -478,7 +487,7 @@ void MainWindow::loadConfig(const QString &fname) ui->sampleFormatCombo->setCurrentIndex(0); if(sampletype.isEmpty() == false) { - for(int i = 0;sampleTypeList[i].name[i];i++) + for(int i = 0;sampleTypeList[i].name[0];i++) { if(sampletype == sampleTypeList[i].value) { @@ -539,7 +548,7 @@ void MainWindow::loadConfig(const QString &fname) ui->stereoModeCombo->setCurrentIndex(0); if(stereomode.isEmpty() == false) { - for(int i = 0;stereoModeList[i].name[i];i++) + for(int i = 0;stereoModeList[i].name[0];i++) { if(stereomode == stereoModeList[i].value) { @@ -567,12 +576,19 @@ void MainWindow::loadConfig(const QString &fname) } QString stereopan = settings.value("stereo-panning").toString(); - if(stereopan == "uhj") - ui->stereoPanningComboBox->setCurrentIndex(1); - else if(stereopan == "paired") - ui->stereoPanningComboBox->setCurrentIndex(2); - else - ui->stereoPanningComboBox->setCurrentIndex(0); + ui->stereoPanningComboBox->setCurrentIndex(0); + if(stereopan.isEmpty() == false) + { + for(int i = 0;stereoPanList[i].name[0];i++) + { + if(stereopan == stereoPanList[i].value) + { + int j = ui->stereoPanningComboBox->findText(stereoPanList[i].name); + if(j > 0) ui->stereoPanningComboBox->setCurrentIndex(j); + break; + } + } + } QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); if(disabledCpuExts.size() == 1) @@ -814,12 +830,15 @@ void MainWindow::saveConfig(const QString &fname) const } } - if(ui->stereoPanningComboBox->currentIndex() == 1) - settings.setValue("stereo-panning", "uhj"); - else if(ui->stereoPanningComboBox->currentIndex() == 2) - settings.setValue("stereo-panning", "paired"); - else - settings.remove("stereo-panning"); + str = ui->stereoPanningComboBox->currentText(); + for(int i = 0;stereoPanList[i].name[0];i++) + { + if(str == stereoPanList[i].name) + { + settings.setValue("stereo-panning", stereoPanList[i].value); + break; + } + } QStringList strlist; if(!ui->enableSSECheckBox->isChecked()) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 28c699f3..f6bcc05b 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -444,21 +444,6 @@ output, which encodes some surround information. Pair-Wise uses standard pair-wise panning between -30 and +30 degrees. The default is UHJ. - - - Default - - - - - UHJ - - - - - Pair-Wise - - -- cgit v1.2.3 From 101ae7644e95ad3619d03f59f23b100b9ab01b5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Mar 2016 01:50:49 -0800 Subject: Add a couple helpers for dealing with name-pair lists --- utils/alsoft-config/mainwindow.cpp | 116 +++++++++++++++---------------------- 1 file changed, 46 insertions(+), 70 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index a21b8c15..b94330e1 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -64,7 +64,7 @@ static const struct { { "", "" } }; -static const struct { +static const struct NameValuePair { const char name[64]; const char value[16]; } speakerModeList[] = { @@ -174,6 +174,28 @@ static QStringList getAllDataPaths(QString append=QString()) return list; } +template +static QString getValueFromName(const NameValuePair (&list)[N], const QString &str) +{ + for(size_t i = 0;i < N-1;i++) + { + if(str == list[i].name) + return list[i].value; + } + return QString(); +} + +template +static QString getNameFromValue(const NameValuePair (&list)[N], const QString &str) +{ + for(size_t i = 0;i < N-1;i++) + { + if(str == list[i].value) + return list[i].name; + } + return QString(); +} + } MainWindow::MainWindow(QWidget *parent) : @@ -487,14 +509,11 @@ void MainWindow::loadConfig(const QString &fname) ui->sampleFormatCombo->setCurrentIndex(0); if(sampletype.isEmpty() == false) { - for(int i = 0;sampleTypeList[i].name[0];i++) + QString str = getNameFromValue(sampleTypeList, sampletype); + if(!str.isEmpty()) { - if(sampletype == sampleTypeList[i].value) - { - int j = ui->sampleFormatCombo->findText(sampleTypeList[i].name); - if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j); - break; - } + int j = ui->sampleFormatCombo->findText(str); + if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j); } } @@ -502,14 +521,11 @@ void MainWindow::loadConfig(const QString &fname) ui->channelConfigCombo->setCurrentIndex(0); if(channelconfig.isEmpty() == false) { - for(int i = 0;speakerModeList[i].name[0];i++) + QString str = getNameFromValue(speakerModeList, channelconfig); + if(!str.isEmpty()) { - if(channelconfig == speakerModeList[i].value) - { - int j = ui->channelConfigCombo->findText(speakerModeList[i].name); - if(j > 0) ui->channelConfigCombo->setCurrentIndex(j); - break; - } + int j = ui->channelConfigCombo->findText(str); + if(j > 0) ui->channelConfigCombo->setCurrentIndex(j); } } @@ -548,14 +564,11 @@ void MainWindow::loadConfig(const QString &fname) ui->stereoModeCombo->setCurrentIndex(0); if(stereomode.isEmpty() == false) { - for(int i = 0;stereoModeList[i].name[0];i++) + QString str = getNameFromValue(stereoModeList, stereomode); + if(!str.isEmpty()) { - if(stereomode == stereoModeList[i].value) - { - int j = ui->stereoModeCombo->findText(stereoModeList[i].name); - if(j > 0) ui->stereoModeCombo->setCurrentIndex(j); - break; - } + int j = ui->stereoModeCombo->findText(str); + if(j > 0) ui->stereoModeCombo->setCurrentIndex(j); } } @@ -579,14 +592,11 @@ void MainWindow::loadConfig(const QString &fname) ui->stereoPanningComboBox->setCurrentIndex(0); if(stereopan.isEmpty() == false) { - for(int i = 0;stereoPanList[i].name[0];i++) + QString str = getNameFromValue(stereoPanList, stereopan); + if(!str.isEmpty()) { - if(stereopan == stereoPanList[i].value) - { - int j = ui->stereoPanningComboBox->findText(stereoPanList[i].name); - if(j > 0) ui->stereoPanningComboBox->setCurrentIndex(j); - break; - } + int j = ui->stereoPanningComboBox->findText(str); + if(j > 0) ui->stereoPanningComboBox->setCurrentIndex(j); } } @@ -786,25 +796,8 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue(key, vals.join(QChar(','))); } - QString str = ui->sampleFormatCombo->currentText(); - for(int i = 0;sampleTypeList[i].name[0];i++) - { - if(str == sampleTypeList[i].name) - { - settings.setValue("sample-type", sampleTypeList[i].value); - break; - } - } - - str = ui->channelConfigCombo->currentText(); - for(int i = 0;speakerModeList[i].name[0];i++) - { - if(str == speakerModeList[i].name) - { - settings.setValue("channels", speakerModeList[i].value); - break; - } - } + settings.setValue("sample-type", getValueFromName(sampleTypeList, ui->sampleFormatCombo->currentText())); + settings.setValue("channels", getValueFromName(speakerModeList, ui->channelConfigCombo->currentText())); uint rate = ui->sampleRateCombo->currentText().toUInt(); if(!(rate > 0)) @@ -820,25 +813,8 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("resampler", resamplerList[ui->resamplerSlider->value()].value); - str = ui->stereoModeCombo->currentText(); - for(int i = 0;stereoModeList[i].name[0];i++) - { - if(str == stereoModeList[i].name) - { - settings.setValue("stereo-mode", stereoModeList[i].value); - break; - } - } - - str = ui->stereoPanningComboBox->currentText(); - for(int i = 0;stereoPanList[i].name[0];i++) - { - if(str == stereoPanList[i].name) - { - settings.setValue("stereo-panning", stereoPanList[i].value); - break; - } - } + settings.setValue("stereo-mode", getValueFromName(stereoModeList, ui->stereoModeCombo->currentText())); + settings.setValue("stereo-panning", getValueFromName(stereoPanList, ui->stereoPanningComboBox->currentText())); QStringList strlist; if(!ui->enableSSECheckBox->isChecked()) @@ -864,7 +840,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("default-hrtf", QString()); else { - str = ui->preferredHrtfComboBox->currentText(); + QString str = ui->preferredHrtfComboBox->currentText(); settings.setValue("default-hrtf", str); } @@ -911,7 +887,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("default-reverb", QString()); else { - str = ui->defaultReverbComboBox->currentText().toLower(); + QString str = ui->defaultReverbComboBox->currentText().toLower(); settings.setValue("default-reverb", str); } @@ -983,7 +959,7 @@ void MainWindow::saveConfig(const QString &fname) const allkeys = settings.allKeys(); foreach(const QString &key, allkeys) { - str = settings.value(key).toString(); + QString str = settings.value(key).toString(); if(str == QString()) settings.remove(key); } -- cgit v1.2.3 From 6971e8684718324f641fa0dba9d0fd31bee240f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Mar 2016 02:02:37 -0800 Subject: Add a simple About page that shows the library build version --- utils/alsoft-config/mainwindow.cpp | 10 ++++++++++ utils/alsoft-config/mainwindow.h | 2 ++ utils/alsoft-config/mainwindow.ui | 12 ++++++++++++ 3 files changed, 24 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index b94330e1..73494b11 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -292,6 +292,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); + connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutPage())); + connect(ui->closeCancelButton, SIGNAL(clicked()), this, SLOT(cancelCloseAction())); connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig())); @@ -427,6 +429,14 @@ void MainWindow::cancelCloseAction() } +void MainWindow::showAboutPage() +{ + QMessageBox::information(this, tr("About"), + tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+(ALSOFT_VERSION ".") + ); +} + + QStringList MainWindow::collectHrtfs() { QStringList ret; diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 0ddb9a92..65e6e1b6 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -24,6 +24,8 @@ private slots: void saveConfigAsFile(); void loadConfigFromFile(); + void showAboutPage(); + void enableApplyButton(); void updateResamplerLabel(int num); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index f6bcc05b..9ed7840a 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1964,7 +1964,14 @@ added by the ALC_EXT_DEDICATED extension. + + + &Help + + + + @@ -2002,6 +2009,11 @@ added by the ALC_EXT_DEDICATED extension. Load Configuration File + + + &About... + + -- cgit v1.2.3 From 3b9fe27cbe466ecb2a1aad8013f2dc256d708aaa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Mar 2016 12:03:36 -0800 Subject: Browse with the current or default device already selected --- utils/alsoft-config/mainwindow.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 73494b11..5f57ce0f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1156,7 +1156,9 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) void MainWindow::selectOSSPlayback() { - QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device")); + QString current = ui->ossDefaultDeviceLine->text(); + if(current.isEmpty()) current = ui->ossDefaultDeviceLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); if(!fname.isEmpty()) { ui->ossDefaultDeviceLine->setText(fname); @@ -1166,7 +1168,9 @@ void MainWindow::selectOSSPlayback() void MainWindow::selectOSSCapture() { - QString fname = QFileDialog::getOpenFileName(this, tr("Select Capture Device")); + QString current = ui->ossDefaultCaptureLine->text(); + if(current.isEmpty()) current = ui->ossDefaultCaptureLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Capture Device"), current); if(!fname.isEmpty()) { ui->ossDefaultCaptureLine->setText(fname); @@ -1176,7 +1180,9 @@ void MainWindow::selectOSSCapture() void MainWindow::selectSolarisPlayback() { - QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device")); + QString current = ui->solarisDefaultDeviceLine->text(); + if(current.isEmpty()) current = ui->solarisDefaultDeviceLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); if(!fname.isEmpty()) { ui->solarisDefaultDeviceLine->setText(fname); -- cgit v1.2.3 From 3e2672ec9f5c2a84a0f871bd0379ee387f9a95ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Mar 2016 22:57:38 -0800 Subject: Track the virtual and real output buffers ecplicitly --- Alc/ALc.c | 35 ++++++++++++++++++++++++++++++ Alc/ALu.c | 54 ++++++++++++++++++++--------------------------- Alc/effects/reverb.c | 36 ++++++++++++++++++------------- OpenAL32/Include/alMain.h | 13 +++++++++++- 4 files changed, 91 insertions(+), 47 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fd44ed28..fb9f2caa 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1855,6 +1855,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->DryBuffer); device->DryBuffer = NULL; + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; UpdateClockBase(device); @@ -2124,6 +2128,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } + if(device->Hrtf || device->Uhj_Encoder) + { + device->VirtOut.Buffer = device->DryBuffer; + device->VirtOut.NumChannels = device->NumChannels; + device->RealOut.Buffer = device->DryBuffer + device->NumChannels; + device->RealOut.NumChannels = 2; + } + else + { + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = device->DryBuffer; + device->RealOut.NumChannels = device->NumChannels; + } + SetMixerFPUMode(&oldMode); V0(device->Backend,lock)(); context = ATOMIC_LOAD(&device->ContextList); @@ -2261,6 +2280,10 @@ static ALCvoid FreeDevice(ALCdevice *device) al_free(device->DryBuffer); device->DryBuffer = NULL; + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; al_free(device); } @@ -3361,6 +3384,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; ATOMIC_INIT(&device->ContextList, NULL); @@ -3616,6 +3643,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); @@ -3806,6 +3837,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; + device->VirtOut.Buffer = NULL; + device->VirtOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; ATOMIC_INIT(&device->ContextList, NULL); diff --git a/Alc/ALu.c b/Alc/ALu.c index 38a4ef71..599ba3c2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -581,8 +581,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A * channels and write FrontLeft and FrontRight inputs to the * first and second outputs. */ - voice->Direct.OutBuffer += voice->Direct.OutChannels; - voice->Direct.OutChannels = 2; + voice->Direct.OutBuffer = Device->RealOut.Buffer; + voice->Direct.OutChannels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) @@ -632,8 +632,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Full HRTF rendering. Skip the virtual channels and render each * input channel to the real outputs. */ - voice->Direct.OutBuffer += voice->Direct.OutChannels; - voice->Direct.OutChannels = 2; + voice->Direct.OutBuffer = Device->RealOut.Buffer; + voice->Direct.OutChannels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { if(chans[c].channel == LFE) @@ -1131,8 +1131,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat dirfact = 1.0f; ALfloat coeffs[MAX_AMBI_COEFFS]; - voice->Direct.OutBuffer += voice->Direct.OutChannels; - voice->Direct.OutChannels = 2; + voice->Direct.OutBuffer = Device->RealOut.Buffer; + voice->Direct.OutChannels = Device->RealOut.NumChannels; if(Distance > FLT_EPSILON) { @@ -1393,26 +1393,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { - ALfloat (*OutBuffer)[BUFFERSIZE]; - ALuint OutChannels; - IncrementRef(&device->MixCount); - OutBuffer = device->DryBuffer; - OutChannels = device->NumChannels; - SamplesToDo = minu(size, BUFFERSIZE); - for(c = 0;c < OutChannels;c++) - memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Hrtf || device->Uhj_Encoder) - { - /* Set OutBuffer/OutChannels to correspond to the actual output - * with HRTF. Make sure to clear them too. */ - OutBuffer += OutChannels; - OutChannels = 2; - for(c = 0;c < OutChannels;c++) - memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - } + for(c = 0;c < device->VirtOut.NumChannels;c++) + memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + for(c = 0;c < device->RealOut.NumChannels;c++) + memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); V0(device->Backend,lock)(); @@ -1495,12 +1482,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALuint irsize = GetHrtfIrSize(device->Hrtf); MixHrtfParams hrtfparams; memset(&hrtfparams, 0, sizeof(hrtfparams)); - for(c = 0;c < device->NumChannels;c++) + for(c = 0;c < device->VirtOut.NumChannels;c++) { hrtfparams.Current = &device->Hrtf_Params[c]; hrtfparams.Target = &device->Hrtf_Params[c]; - HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset, - 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo + HrtfMix(device->RealOut.Buffer, device->VirtOut.Buffer[c], 0, + device->Hrtf_Offset, 0, irsize, &hrtfparams, + &device->Hrtf_State[c], SamplesToDo ); } device->Hrtf_Offset += SamplesToDo; @@ -1510,7 +1498,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(device->Uhj_Encoder) { /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo); + EncodeUhj2(device->Uhj_Encoder, device->RealOut.Buffer, + device->VirtOut.Buffer, SamplesToDo); } if(device->Bs2b) { @@ -1518,17 +1507,20 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) for(i = 0;i < SamplesToDo;i++) { float samples[2]; - samples[0] = OutBuffer[0][i]; - samples[1] = OutBuffer[1][i]; + samples[0] = device->RealOut.Buffer[0][i]; + samples[1] = device->RealOut.Buffer[1][i]; bs2b_cross_feed(device->Bs2b, samples); - OutBuffer[0][i] = samples[0]; - OutBuffer[1][i] = samples[1]; + device->RealOut.Buffer[0][i] = samples[0]; + device->RealOut.Buffer[1][i] = samples[1]; } } } if(buffer) { + ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; + ALuint OutChannels = device->RealOut.NumChannels;; + #define WRITE(T, a, b, c, d) do { \ Write_##T((a), (b), (c), (d)); \ buffer = (T*)buffer + (c)*(d); \ diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 995ad6a5..a92fbd5b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -364,6 +364,9 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; + /* WARNING: This assumes the real output follows the virtual output in the + * device's DryBuffer. + */ State->ExtraChannels = (Device->Hrtf || Device->Uhj_Encoder) ? 2 : 0; // Calculate the modulation filter coefficient. Notice that the exponent @@ -666,16 +669,19 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect ALfloat length; ALuint i; - /* With HRTF, the normal output provides a panned reverb channel when a - * non-0-length vector is specified, while the real stereo output provides - * two other "direct" non-panned reverb channels. + /* With HRTF or UHJ, the normal output provides a panned reverb channel + * when a non-0-length vector is specified, while the real stereo output + * provides two other "direct" non-panned reverb channels. + * + * WARNING: This assumes the real output follows the virtual output in the + * device's DryBuffer. */ memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < 2;i++) - State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain; + for(i = 0;i < Device->RealOut.NumChannels;i++) + State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain; } else { @@ -691,19 +697,19 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) + ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->VirtOut.NumChannels;i++) State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; - for(i = 0;i < 2;i++) - State->Early.PanGain[i&3][Device->NumChannels+i] = Gain * EarlyGain * (1.0f-length); + for(i = 0;i < Device->RealOut.NumChannels;i++) + State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain * (1.0f-length); } memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < 2;i++) - State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain; + for(i = 0;i < Device->RealOut.NumChannels;i++) + State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain; } else { @@ -715,11 +721,11 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) + ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->VirtOut.NumChannels;i++) State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; - for(i = 0;i < 2;i++) - State->Late.PanGain[i&3][Device->NumChannels+i] = Gain * LateGain * (1.0f-length); + for(i = 0;i < Device->RealOut.NumChannels;i++) + State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain * (1.0f-length); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8c75cb83..f79002fe 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -494,9 +494,20 @@ struct ALCdevice_struct alignas(16) ALfloat ResampledData[BUFFERSIZE]; alignas(16) ALfloat FilteredData[BUFFERSIZE]; - /* Dry path buffer mix. */ + /* Dry path buffer mix (will be aliased by the virtual or real output). */ alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE]; + /* Virtual output, to be post-processed to the real output. */ + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint NumChannels; + } VirtOut; + /* "Real" output, which will be written to the device buffer. */ + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint NumChannels; + } RealOut; + /* Running count of the mixer invocations, in 31.1 fixed point. This * actually increments *twice* when mixing, first at the start and then at * the end, so the bottom bit indicates if the device is currently mixing -- cgit v1.2.3 From a45715751640992e8caeac8c36b5ecb23ba3c190 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Mar 2016 23:43:57 -0800 Subject: Organize the dry buffer properties into a struct --- Alc/ALc.c | 145 ++++++++++++++++++++++++---------------------- Alc/ALu.c | 30 +++++----- Alc/effects/autowah.c | 2 +- Alc/effects/chorus.c | 4 +- Alc/effects/compressor.c | 4 +- Alc/effects/dedicated.c | 3 +- Alc/effects/distortion.c | 2 +- Alc/effects/echo.c | 6 +- Alc/effects/equalizer.c | 4 +- Alc/effects/flanger.c | 6 +- Alc/effects/modulator.c | 4 +- Alc/effects/reverb.c | 37 ++++++------ Alc/panning.c | 40 ++++++------- OpenAL32/Include/alMain.h | 44 ++++++++------ 14 files changed, 175 insertions(+), 156 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fb9f2caa..2d3af9d5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1433,63 +1433,63 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) ALuint i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->ChannelName[i] = InvalidChannel; + device->Dry.ChannelName[i] = InvalidChannel; switch(device->FmtChans) { case DevFmtMono: - device->ChannelName[0] = FrontCenter; + device->Dry.ChannelName[0] = FrontCenter; break; case DevFmtStereo: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; break; case DevFmtQuad: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = BackLeft; - device->ChannelName[3] = BackRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = BackLeft; + device->Dry.ChannelName[3] = BackRight; break; case DevFmtX51: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = FrontCenter; - device->ChannelName[3] = LFE; - device->ChannelName[4] = SideLeft; - device->ChannelName[5] = SideRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = FrontCenter; + device->Dry.ChannelName[3] = LFE; + device->Dry.ChannelName[4] = SideLeft; + device->Dry.ChannelName[5] = SideRight; break; case DevFmtX51Rear: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = FrontCenter; - device->ChannelName[3] = LFE; - device->ChannelName[4] = BackLeft; - device->ChannelName[5] = BackRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = FrontCenter; + device->Dry.ChannelName[3] = LFE; + device->Dry.ChannelName[4] = BackLeft; + device->Dry.ChannelName[5] = BackRight; break; case DevFmtX61: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = FrontCenter; - device->ChannelName[3] = LFE; - device->ChannelName[4] = BackCenter; - device->ChannelName[5] = SideLeft; - device->ChannelName[6] = SideRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = FrontCenter; + device->Dry.ChannelName[3] = LFE; + device->Dry.ChannelName[4] = BackCenter; + device->Dry.ChannelName[5] = SideLeft; + device->Dry.ChannelName[6] = SideRight; break; case DevFmtX71: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = FrontCenter; - device->ChannelName[3] = LFE; - device->ChannelName[4] = BackLeft; - device->ChannelName[5] = BackRight; - device->ChannelName[6] = SideLeft; - device->ChannelName[7] = SideRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = FrontCenter; + device->Dry.ChannelName[3] = LFE; + device->Dry.ChannelName[4] = BackLeft; + device->Dry.ChannelName[5] = BackRight; + device->Dry.ChannelName[6] = SideLeft; + device->Dry.ChannelName[7] = SideRight; break; case DevFmtBFormat3D: - device->ChannelName[0] = BFormatW; - device->ChannelName[1] = BFormatX; - device->ChannelName[2] = BFormatY; - device->ChannelName[3] = BFormatZ; + device->Dry.ChannelName[0] = BFormatW; + device->Dry.ChannelName[1] = BFormatX; + device->Dry.ChannelName[2] = BFormatY; + device->Dry.ChannelName[3] = BFormatZ; break; } } @@ -1503,27 +1503,27 @@ void SetDefaultChannelOrder(ALCdevice *device) ALuint i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->ChannelName[i] = InvalidChannel; + device->Dry.ChannelName[i] = InvalidChannel; switch(device->FmtChans) { case DevFmtX51Rear: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = BackLeft; - device->ChannelName[3] = BackRight; - device->ChannelName[4] = FrontCenter; - device->ChannelName[5] = LFE; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = BackLeft; + device->Dry.ChannelName[3] = BackRight; + device->Dry.ChannelName[4] = FrontCenter; + device->Dry.ChannelName[5] = LFE; return; case DevFmtX71: - device->ChannelName[0] = FrontLeft; - device->ChannelName[1] = FrontRight; - device->ChannelName[2] = BackLeft; - device->ChannelName[3] = BackRight; - device->ChannelName[4] = FrontCenter; - device->ChannelName[5] = LFE; - device->ChannelName[6] = SideLeft; - device->ChannelName[7] = SideRight; + device->Dry.ChannelName[0] = FrontLeft; + device->Dry.ChannelName[1] = FrontRight; + device->Dry.ChannelName[2] = BackLeft; + device->Dry.ChannelName[3] = BackRight; + device->Dry.ChannelName[4] = FrontCenter; + device->Dry.ChannelName[5] = LFE; + device->Dry.ChannelName[6] = SideLeft; + device->Dry.ChannelName[7] = SideRight; return; /* Same as WFX order */ @@ -1853,8 +1853,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Bs2b); device->Bs2b = NULL; - al_free(device->DryBuffer); - device->DryBuffer = NULL; + al_free(device->Dry.Buffer); + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; device->RealOut.Buffer = NULL; @@ -2118,11 +2119,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitPanning(device); /* With HRTF, allocate two extra channels for the post-filter output. */ - size = device->NumChannels * sizeof(device->DryBuffer[0]); + size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); if(device->Hrtf || device->Uhj_Encoder) - size += 2 * sizeof(device->DryBuffer[0]); - device->DryBuffer = al_calloc(16, size); - if(!device->DryBuffer) + size += 2 * sizeof(device->Dry.Buffer[0]); + device->Dry.Buffer = al_calloc(16, size); + if(!device->Dry.Buffer) { ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size); return ALC_INVALID_DEVICE; @@ -2130,17 +2131,17 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Hrtf || device->Uhj_Encoder) { - device->VirtOut.Buffer = device->DryBuffer; - device->VirtOut.NumChannels = device->NumChannels; - device->RealOut.Buffer = device->DryBuffer + device->NumChannels; + device->VirtOut.Buffer = device->Dry.Buffer; + device->VirtOut.NumChannels = device->Dry.NumChannels; + device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; device->RealOut.NumChannels = 2; } else { device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; - device->RealOut.Buffer = device->DryBuffer; - device->RealOut.NumChannels = device->NumChannels; + device->RealOut.Buffer = device->Dry.Buffer; + device->RealOut.NumChannels = device->Dry.NumChannels; } SetMixerFPUMode(&oldMode); @@ -2278,8 +2279,9 @@ static ALCvoid FreeDevice(ALCdevice *device) AL_STRING_DEINIT(device->DeviceName); - al_free(device->DryBuffer); - device->DryBuffer = NULL; + al_free(device->Dry.Buffer); + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; device->RealOut.Buffer = NULL; @@ -3383,7 +3385,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) AL_STRING_INIT(device->Hrtf_Name); device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); - device->DryBuffer = NULL; + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; device->RealOut.Buffer = NULL; @@ -3642,7 +3645,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL_STRING_INIT(device->Hrtf_Name); AL_STRING_INIT(device->DeviceName); - device->DryBuffer = NULL; + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; device->RealOut.Buffer = NULL; @@ -3836,7 +3840,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Uhj_Encoder = NULL; device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); - device->DryBuffer = NULL; + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; device->VirtOut.Buffer = NULL; device->VirtOut.NumChannels = 0; device->RealOut.Buffer = NULL; diff --git a/Alc/ALu.c b/Alc/ALu.c index 599ba3c2..9ca5dd02 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -394,8 +394,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A Relative = ALSource->HeadRelative; DirectChannels = ALSource->DirectChannels; - voice->Direct.OutBuffer = Device->DryBuffer; - voice->Direct.OutChannels = Device->NumChannels; + voice->Direct.OutBuffer = Device->Dry.Buffer; + voice->Direct.OutChannels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ALSource->Send[i].Slot; @@ -526,7 +526,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Build a rotate + conversion matrix (B-Format -> N3D), and include * scaling for first-order content on second- or third-order output. */ - scale = Device->AmbiScale * 1.732050808f; + scale = Device->Dry.AmbiScale * 1.732050808f; aluMatrixfSet(&matrix, 1.414213562f, 0.0f, 0.0f, 0.0f, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, @@ -535,8 +535,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ); for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain, - voice->Direct.Gains[c].Target); + ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, matrix.m[c], + DryGain, voice->Direct.Gains[c].Target); /* Rebuild the matrix, without the second- or third-order output * scaling (effects take first-order content, and will do the scaling @@ -722,8 +722,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, - voice->Direct.Gains[c].Target); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + DryGain, voice->Direct.Gains[c].Target); } for(i = 0;i < NumSends;i++) @@ -859,8 +859,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte WetGainHFAuto = ALSource->WetGainHFAuto; RoomRolloffBase = ALSource->RoomRolloffFactor; - voice->Direct.OutBuffer = Device->DryBuffer; - voice->Direct.OutChannels = Device->NumChannels; + voice->Direct.OutBuffer = Device->Dry.Buffer; + voice->Direct.OutChannels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ALSource->Send[i].Slot; @@ -1223,8 +1223,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, - voice->Direct.Gains[0].Target); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + DryGain, voice->Direct.Gains[0].Target); } for(i = 0;i < NumSends;i++) @@ -1452,8 +1452,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i); ALeffectState *state = slot->EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer, - device->NumChannels); + V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer, + device->Dry.NumChannels); } ctx = ctx->next; @@ -1463,8 +1463,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { const ALeffectslot *slot = device->DefaultSlot; ALeffectState *state = slot->EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer, - device->NumChannels); + V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer, + device->Dry.NumChannels); } /* Increment the clock time. Every second's worth of samples is diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 09aecf15..20ae26e4 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -75,7 +75,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *devi state->PeakGain = slot->EffectProps.Autowah.PeakGain; state->Resonance = slot->EffectProps.Autowah.Resonance; - ComputeAmbientGains(device->AmbiCoeffs, device->NumChannels, slot->Gain, state->Gain); + ComputeAmbientGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, slot->Gain, state->Gain); } static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 1c9efd47..e212cd75 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -113,9 +113,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Slot->Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index e835a5aa..ae859793 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -63,7 +63,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice state->Enabled = slot->EffectProps.Compressor.OnOff; - scale = device->AmbiScale; + scale = device->Dry.AmbiScale; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, @@ -71,7 +71,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice 0.0f, 0.0f, 0.0f, scale ); for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->AmbiCoeffs, device->NumChannels, + ComputeFirstOrderGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, matrix.m[i], slot->Gain, state->Gain[i]); } diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 06aad17c..2706a672 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -71,7 +71,8 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * { ALfloat coeffs[MAX_AMBI_COEFFS]; CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); - ComputePanningGains(device->AmbiCoeffs, device->NumChannels, coeffs, Gain, state->gains); + ComputePanningGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, + coeffs, Gain, state->gains); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 697758f0..92eb1a6d 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -83,7 +83,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Slot->Gain, state->Gain); + ComputeAmbientGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, Slot->Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index ebb6cf12..1f5925ef 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -104,11 +104,13 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co /* First tap panning */ CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + gain, state->Gain[0]); /* Second tap panning */ CalcXYZCoeffs( lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + gain, state->Gain[1]); } static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 051e8c7f..479a8536 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -103,7 +103,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * aluMatrixf matrix; ALuint i; - gain = device->AmbiScale; + gain = device->Dry.AmbiScale; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, gain, 0.0f, 0.0f, @@ -111,7 +111,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * 0.0f, 0.0f, 0.0f, gain ); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->AmbiCoeffs, device->NumChannels, + ComputeFirstOrderGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, matrix.m[i], slot->Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 21536f04..d29e0f25 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -113,9 +113,11 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + Slot->Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Flanger.Phase; rate = Slot->EffectProps.Flanger.Rate; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index cd6ccb22..4183b908 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -122,7 +122,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter[i].process = ALfilterState_processC; } - scale = Device->AmbiScale; + scale = Device->Dry.AmbiScale; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, @@ -130,7 +130,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * 0.0f, 0.0f, 0.0f, scale ); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, + ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, matrix.m[i], Slot->Gain, state->Gain[i]); } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a92fbd5b..a1b27876 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -681,7 +681,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect if(!(length > FLT_EPSILON)) { for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain; + State->Early.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * EarlyGain; } else { @@ -697,11 +697,11 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->VirtOut.NumChannels;i++) + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Early.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * EarlyGain * (1.0f-length); + State->Early.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * EarlyGain * (1.0f-length); } memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); @@ -709,7 +709,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect if(!(length > FLT_EPSILON)) { for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain; + State->Late.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * LateGain; } else { @@ -721,11 +721,11 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->VirtOut.NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->VirtOut.NumChannels;i++) + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain, DirGains); + for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Late.PanGain[i&3][Device->VirtOut.NumChannels+i] = Gain * LateGain * (1.0f-length); + State->Late.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * LateGain * (1.0f-length); } } @@ -738,13 +738,14 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec ALuint i; /* Apply a boost of about 3dB to better match the expected stereo output volume. */ - ComputeAmbientGains(Device->AmbiCoeffs, Device->NumChannels, Gain*1.414213562f, AmbientGains); + ComputeAmbientGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Gain*1.414213562f, AmbientGains); memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < Device->NumChannels;i++) + for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[i&3][i] = AmbientGains[i] * EarlyGain; } else @@ -761,8 +762,9 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + Gain, DirGains); + for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; } @@ -770,7 +772,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); if(!(length > FLT_EPSILON)) { - for(i = 0;i < Device->NumChannels;i++) + for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[i&3][i] = AmbientGains[i] * LateGain; } else @@ -783,8 +785,9 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, Gain, DirGains); - for(i = 0;i < Device->NumChannels;i++) + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, + Gain, DirGains); + for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; } } @@ -833,7 +836,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain*EarlyGain*gain[i], State->Early.PanGain[i]); } @@ -864,7 +867,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain*LateGain*gain[i], State->Late.PanGain[i]); } } diff --git a/Alc/panning.c b/Alc/panning.c index b17df007..8ac1d4d2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -426,9 +426,9 @@ static bool LoadChannelSetup(ALCdevice *device) for(j = 0;j < MAX_AMBI_COEFFS;++j) chanmap[i].Config[j] = coeffs[j]; } - SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, - &device->NumChannels, isfuma); - device->AmbiScale = ambiscale; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, isfuma); + device->Dry.AmbiScale = ambiscale; return true; } @@ -499,9 +499,9 @@ ALvoid aluInitPanning(ALCdevice *device) size_t count = 0; ALuint i; - device->AmbiScale = 1.0f; - memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs)); - device->NumChannels = 0; + device->Dry.AmbiScale = 1.0f; + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; if(device->Hrtf) { @@ -525,14 +525,14 @@ ALvoid aluInitPanning(ALCdevice *device) ambiscale = FIRST_ORDER_SCALE; for(i = 0;i < count;i++) - device->ChannelName[i] = chanmap[i].ChanName; + device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) - device->ChannelName[i] = InvalidChannel; - SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, - &device->NumChannels, AL_TRUE); - device->AmbiScale = ambiscale; + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + device->Dry.AmbiScale = ambiscale; - for(i = 0;i < device->NumChannels;i++) + for(i = 0;i < device->Dry.NumChannels;i++) { int chan = GetChannelIdxByName(device, CubeInfo[i].Channel); GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, @@ -547,12 +547,12 @@ ALvoid aluInitPanning(ALCdevice *device) ambiscale = FIRST_ORDER_SCALE; for(i = 0;i < count;i++) - device->ChannelName[i] = chanmap[i].ChanName; + device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) - device->ChannelName[i] = InvalidChannel; - SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, - &device->NumChannels, AL_TRUE); - device->AmbiScale = ambiscale; + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + device->Dry.AmbiScale = ambiscale; return; } @@ -611,9 +611,9 @@ ALvoid aluInitPanning(ALCdevice *device) break; } - SetChannelMap(device->ChannelName, device->AmbiCoeffs, chanmap, count, - &device->NumChannels, AL_TRUE); - device->AmbiScale = ambiscale; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + device->Dry.AmbiScale = ambiscale; } void aluInitEffectPanning(ALeffectslot *slot) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f79002fe..837b2be8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -431,25 +431,25 @@ struct ALCdevice_struct ALCboolean Connected; enum DeviceType Type; - ALuint Frequency; - ALuint UpdateSize; - ALuint NumUpdates; + ALuint Frequency; + ALuint UpdateSize; + ALuint NumUpdates; enum DevFmtChannels FmtChans; enum DevFmtType FmtType; - ALboolean IsHeadphones; + ALboolean IsHeadphones; al_string DeviceName; ATOMIC(ALCenum) LastError; // Maximum number of sources that can be created - ALuint MaxNoOfSources; + ALuint MaxNoOfSources; // Maximum number of slots that can be created - ALuint AuxiliaryEffectSlotMax; + ALuint AuxiliaryEffectSlotMax; - ALCuint NumMonoSources; - ALCuint NumStereoSources; - ALuint NumAuxSends; + ALCuint NumMonoSources; + ALCuint NumStereoSources; + ALuint NumAuxSends; // Map of Buffers for this device UIntMap BufferMap; @@ -481,11 +481,6 @@ struct ALCdevice_struct // Device flags ALuint Flags; - enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; - ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; - ALfloat AmbiScale; /* Scale for first-order XYZ inputs using AmbCoeffs. */ - ALuint NumChannels; - ALuint64 ClockBase; ALuint SamplesDone; @@ -494,8 +489,19 @@ struct ALCdevice_struct alignas(16) ALfloat ResampledData[BUFFERSIZE]; alignas(16) ALfloat FilteredData[BUFFERSIZE]; - /* Dry path buffer mix (will be aliased by the virtual or real output). */ - alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE]; + /* The "dry" path corresponds to the main output. */ + struct { + /* Channel names for the dry buffer mix. */ + enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; + /* Ambisonic coefficients for mixing to the dry buffer. */ + ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; + /* Scale for first-order XYZ inputs using AmbiCoeffs. */ + ALfloat AmbiScale; + + /* Dry buffer will be aliased by the virtual or real output. */ + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint NumChannels; + } Dry; /* Virtual output, to be post-processed to the real output. */ struct { @@ -680,15 +686,15 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST; /** * GetChannelIdxByName * - * Returns the device's channel index given a channel name (e.g. FrontCenter), - * or -1 if it doesn't exist. + * Returns the dry buffer's channel index for the given channel name (e.g. + * FrontCenter), or -1 if it doesn't exist. */ inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan) { ALint i = 0; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { - if(device->ChannelName[i] == chan) + if(device->Dry.ChannelName[i] == chan) return i; } return -1; -- cgit v1.2.3 From effb9d1e35ab3679daa6314ffecfc4d71dc4cdf7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Mar 2016 01:04:28 -0800 Subject: Keep track of the real output's channel names --- Alc/ALc.c | 108 +++++++++++++++++++++++----------------------- Alc/ALu.c | 35 ++++----------- Alc/panning.c | 3 ++ OpenAL32/Include/alMain.h | 2 + 4 files changed, 67 insertions(+), 81 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2d3af9d5..6074df4a 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1433,63 +1433,63 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) ALuint i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; + device->RealOut.ChannelName[i] = InvalidChannel; switch(device->FmtChans) { case DevFmtMono: - device->Dry.ChannelName[0] = FrontCenter; + device->RealOut.ChannelName[0] = FrontCenter; break; case DevFmtStereo: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; break; case DevFmtQuad: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = BackLeft; - device->Dry.ChannelName[3] = BackRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; break; case DevFmtX51: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = FrontCenter; - device->Dry.ChannelName[3] = LFE; - device->Dry.ChannelName[4] = SideLeft; - device->Dry.ChannelName[5] = SideRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = SideLeft; + device->RealOut.ChannelName[5] = SideRight; break; case DevFmtX51Rear: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = FrontCenter; - device->Dry.ChannelName[3] = LFE; - device->Dry.ChannelName[4] = BackLeft; - device->Dry.ChannelName[5] = BackRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackLeft; + device->RealOut.ChannelName[5] = BackRight; break; case DevFmtX61: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = FrontCenter; - device->Dry.ChannelName[3] = LFE; - device->Dry.ChannelName[4] = BackCenter; - device->Dry.ChannelName[5] = SideLeft; - device->Dry.ChannelName[6] = SideRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackCenter; + device->RealOut.ChannelName[5] = SideLeft; + device->RealOut.ChannelName[6] = SideRight; break; case DevFmtX71: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = FrontCenter; - device->Dry.ChannelName[3] = LFE; - device->Dry.ChannelName[4] = BackLeft; - device->Dry.ChannelName[5] = BackRight; - device->Dry.ChannelName[6] = SideLeft; - device->Dry.ChannelName[7] = SideRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = FrontCenter; + device->RealOut.ChannelName[3] = LFE; + device->RealOut.ChannelName[4] = BackLeft; + device->RealOut.ChannelName[5] = BackRight; + device->RealOut.ChannelName[6] = SideLeft; + device->RealOut.ChannelName[7] = SideRight; break; case DevFmtBFormat3D: - device->Dry.ChannelName[0] = BFormatW; - device->Dry.ChannelName[1] = BFormatX; - device->Dry.ChannelName[2] = BFormatY; - device->Dry.ChannelName[3] = BFormatZ; + device->RealOut.ChannelName[0] = BFormatW; + device->RealOut.ChannelName[1] = BFormatX; + device->RealOut.ChannelName[2] = BFormatY; + device->RealOut.ChannelName[3] = BFormatZ; break; } } @@ -1503,27 +1503,27 @@ void SetDefaultChannelOrder(ALCdevice *device) ALuint i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; + device->RealOut.ChannelName[i] = InvalidChannel; switch(device->FmtChans) { case DevFmtX51Rear: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = BackLeft; - device->Dry.ChannelName[3] = BackRight; - device->Dry.ChannelName[4] = FrontCenter; - device->Dry.ChannelName[5] = LFE; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; + device->RealOut.ChannelName[4] = FrontCenter; + device->RealOut.ChannelName[5] = LFE; return; case DevFmtX71: - device->Dry.ChannelName[0] = FrontLeft; - device->Dry.ChannelName[1] = FrontRight; - device->Dry.ChannelName[2] = BackLeft; - device->Dry.ChannelName[3] = BackRight; - device->Dry.ChannelName[4] = FrontCenter; - device->Dry.ChannelName[5] = LFE; - device->Dry.ChannelName[6] = SideLeft; - device->Dry.ChannelName[7] = SideRight; + device->RealOut.ChannelName[0] = FrontLeft; + device->RealOut.ChannelName[1] = FrontRight; + device->RealOut.ChannelName[2] = BackLeft; + device->RealOut.ChannelName[3] = BackRight; + device->RealOut.ChannelName[4] = FrontCenter; + device->RealOut.ChannelName[5] = LFE; + device->RealOut.ChannelName[6] = SideLeft; + device->RealOut.ChannelName[7] = SideRight; return; /* Same as WFX order */ diff --git a/Alc/ALu.c b/Alc/ALu.c index 9ca5dd02..8ea74669 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -101,28 +101,6 @@ extern inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33); -/* NOTE: HRTF and UHJ are set up a bit special in the device. Normally the - * device's DryBuffer, NumChannels, ChannelName, and Channel fields correspond - * to the output format, and the DryBuffer is then converted and written to the - * backend's audio buffer. - * - * With HRTF or UHJ, these fields correspond to a virtual format, and the - * actual output is stored in DryBuffer[NumChannels] for the left channel and - * DryBuffer[NumChannels+1] for the right. As a final output step, - * the virtual channels will have HRTF filters or UHJ encoding applied and - * written to the actual output. - * - * Sources that get mixed using HRTF directly (or that want to skip HRTF or UHJ - * completely) will need to offset the output buffer so that they skip the - * virtual output and write to the actual output channels. This is the reason - * you'll see - * - * voice->Direct.OutBuffer += voice->Direct.OutChannels; - * voice->Direct.OutChannels = 2; - * - * at various points in the code where HRTF is explicitly used or bypassed. - */ - static inline HrtfMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_SSE @@ -587,11 +565,14 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - - if(chans[c].channel == FrontLeft) - voice->Direct.Gains[c].Target[0] = DryGain; - else if(chans[c].channel == FrontRight) - voice->Direct.Gains[c].Target[1] = DryGain; + for(j = 0;j < Device->RealOut.NumChannels;j++) + { + if(chans[c].channel == Device->RealOut.ChannelName[j]) + { + voice->Direct.Gains[c].Target[j] = DryGain; + break; + } + } } } else for(c = 0;c < num_channels;c++) diff --git a/Alc/panning.c b/Alc/panning.c index 8ac1d4d2..beb928d9 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -557,6 +557,9 @@ ALvoid aluInitPanning(ALCdevice *device) return; } + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; + if(LoadChannelSetup(device)) return; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 837b2be8..fc55b93b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -510,6 +510,8 @@ struct ALCdevice_struct } VirtOut; /* "Real" output, which will be written to the device buffer. */ struct { + enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; + ALfloat (*Buffer)[BUFFERSIZE]; ALuint NumChannels; } RealOut; -- cgit v1.2.3 From da5f75615bf4dee38d456949b30b90921ad713c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Mar 2016 01:45:30 -0800 Subject: Allocate enough reverb panning gains --- Alc/effects/reverb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a1b27876..e68e6e19 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -87,7 +87,10 @@ typedef struct ALreverbState { ALuint Offset[4]; // The gain for each output channel based on 3D panning. - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; + // NOTE: With HRTF, we may be rendering to the dry buffer and the + // "real" buffer. The dry buffer may be using all 8 output channels, so + // we need two extra for the real stereo output. + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; } Early; // Decorrelator delay line. @@ -125,7 +128,8 @@ typedef struct ALreverbState { ALfloat LpSample[4]; // The gain for each output channel based on 3D panning. - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; + // NOTE: Add two in case of HRTF (see note about early pan). + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; } Late; struct { -- cgit v1.2.3 From d648486bcd431b34ad68b76db400ff7e963c72e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Mar 2016 14:29:44 -0800 Subject: Generalize GetChannelIdxByName --- Alc/ALc.c | 2 +- Alc/ALu.c | 15 +++++---------- Alc/effects/dedicated.c | 4 ++-- Alc/panning.c | 2 +- OpenAL32/Include/alMain.h | 12 ++++++------ 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 6074df4a..8ede026a 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1538,7 +1538,7 @@ void SetDefaultChannelOrder(ALCdevice *device) } } -extern inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan); +extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); /* ALCcontext_DeferUpdates diff --git a/Alc/ALu.c b/Alc/ALu.c index 8ea74669..eb7afd90 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -563,16 +563,11 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.OutChannels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { + int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - for(j = 0;j < Device->RealOut.NumChannels;j++) - { - if(chans[c].channel == Device->RealOut.ChannelName[j]) - { - voice->Direct.Gains[c].Target[j] = DryGain; - break; - } - } + if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) + voice->Direct.Gains[c].Target[idx] = DryGain; } } else for(c = 0;c < num_channels;c++) @@ -580,7 +575,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) + if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1) voice->Direct.Gains[c].Target[idx] = DryGain; } @@ -676,7 +671,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) + if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1) voice->Direct.Gains[c].Target[idx] = DryGain; for(i = 0;i < NumSends;i++) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 2706a672..447e6b95 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -57,7 +57,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; - if((idx=GetChannelIdxByName(device, LFE)) != -1) + if((idx=GetChannelIdxByName(device->Dry, LFE)) != -1) state->gains[idx] = Gain; } else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) @@ -65,7 +65,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * int idx; /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - if((idx=GetChannelIdxByName(device, FrontCenter)) != -1) + if((idx=GetChannelIdxByName(device->Dry, FrontCenter)) != -1) state->gains[idx] = Gain; else { diff --git a/Alc/panning.c b/Alc/panning.c index beb928d9..1765d1c8 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -534,7 +534,7 @@ ALvoid aluInitPanning(ALCdevice *device) for(i = 0;i < device->Dry.NumChannels;i++) { - int chan = GetChannelIdxByName(device, CubeInfo[i].Channel); + int chan = GetChannelIdxByName(device->Dry, CubeInfo[i].Channel); GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fc55b93b..aae19b05 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -688,20 +688,20 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST; /** * GetChannelIdxByName * - * Returns the dry buffer's channel index for the given channel name (e.g. - * FrontCenter), or -1 if it doesn't exist. + * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it + * doesn't exist. */ -inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan) +inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan) { - ALint i = 0; + ALint i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { - if(device->Dry.ChannelName[i] == chan) + if(names[i] == chan) return i; } return -1; } - +#define GetChannelIdxByName(x, c) GetChannelIndex((x).ChannelName, (c)) extern FILE *LogFile; -- cgit v1.2.3 From 859cc703e75c2699531f041ccd3e8169d44bea50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Mar 2016 22:56:44 -0800 Subject: Use the proper left and right channels for UHJ output --- Alc/ALu.c | 13 ++++++++++--- Alc/uhjfilter.c | 6 +++--- Alc/uhjfilter.h | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index eb7afd90..17c91e52 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1473,9 +1473,16 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { if(device->Uhj_Encoder) { - /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, device->RealOut.Buffer, - device->VirtOut.Buffer, SamplesToDo); + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + if(lidx != -1 && ridx != -1) + { + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, + device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->VirtOut.Buffer, SamplesToDo + ); + } } if(device->Bs2b) { diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index b410967a..4a71287f 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -36,7 +36,7 @@ static const ALfloat Filter2Coeff[4] = { * know which is the intended result. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { ALuint base, i, c; @@ -103,10 +103,10 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALf /* Left = (S + D)/2.0 */ for(i = 0;i < todo;i++) - OutBuffer[0][base + i] += (S[i] + D[i]) * 0.5f; + *(LeftOut++) += (S[i] + D[i]) * 0.5f; /* Right = (S - D)/2.0 */ for(i = 0;i < todo;i++) - OutBuffer[1][base + i] += (S[i] - D[i]) * 0.5f; + *(RightOut++) += (S[i] - D[i]) * 0.5f; base += todo; } diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index a5aa9275..14572bc3 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -43,6 +43,6 @@ typedef struct Uhj2Encoder { /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input * signal. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); #endif /* UHJFILTER_H */ -- cgit v1.2.3 From bb03fe227bff59ed5528b1b27e1206b72b9c7a80 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Mar 2016 19:59:14 -0800 Subject: Update the current HRTF delays if the stepping is not finished --- Alc/mixer_inc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index d69becc9..5c5c885d 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -61,6 +61,11 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, Delay[0] = hrtfparams->Target->Delay[0]; Delay[1] = hrtfparams->Target->Delay[1]; } + else + { + hrtfparams->Current->Delay[0] = Delay[0]; + hrtfparams->Current->Delay[1] = Delay[1]; + } } Delay[0] >>= HRTFDELAY_BITS; -- cgit v1.2.3 From 532897219326e5ee47eb08810734b2f2ed4409a3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Mar 2016 20:44:05 -0800 Subject: Separate writing to the output buffer from HRTF filtering --- Alc/mixer_inc.c | 89 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index 5c5c885d..a57a3ecb 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -9,6 +9,9 @@ #include "alu.h" +#define MAX_UPDATE_SAMPLES 128 + + static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint irSize, ALfloat (*restrict Coeffs)[2], @@ -26,15 +29,23 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, { ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; ALuint Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; + ALfloat out[MAX_UPDATE_SAMPLES][2]; ALfloat left, right; - ALuint pos; + ALuint minsize; + ALuint pos, i; pos = 0; - if(pos < Counter) + if(Counter == 0) + goto skip_stepping; + + minsize = minu(BufferSize, Counter); + while(pos < minsize) { - for(;pos < BufferSize && pos < Counter;pos++) + ALuint todo = minu(minsize-pos, MAX_UPDATE_SAMPLES); + + for(i = 0;i < todo;i++) { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos++]; left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); @@ -50,39 +61,55 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, Offset++; ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->Steps.Coeffs, left, right); - OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; - OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; - OutPos++; + out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]; + out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]; } - if(pos == Counter) - { - *hrtfparams->Current = *hrtfparams->Target; - Delay[0] = hrtfparams->Target->Delay[0]; - Delay[1] = hrtfparams->Target->Delay[1]; - } - else - { - hrtfparams->Current->Delay[0] = Delay[0]; - hrtfparams->Current->Delay[1] = Delay[1]; - } + for(i = 0;i < todo;i++) + OutBuffer[0][OutPos+i] += out[i][0]; + for(i = 0;i < todo;i++) + OutBuffer[1][OutPos+i] += out[i][1]; + OutPos += todo; + } + + if(pos == Counter) + { + *hrtfparams->Current = *hrtfparams->Target; + Delay[0] = hrtfparams->Target->Delay[0]; + Delay[1] = hrtfparams->Target->Delay[1]; + } + else + { + hrtfparams->Current->Delay[0] = Delay[0]; + hrtfparams->Current->Delay[1] = Delay[1]; } +skip_stepping: Delay[0] >>= HRTFDELAY_BITS; Delay[1] >>= HRTFDELAY_BITS; - for(;pos < BufferSize;pos++) + while(pos < BufferSize) { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; - - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; - OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; - OutPos++; + ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES); + + for(i = 0;i < todo;i++) + { + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos++]; + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; + + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]; + out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]; + } + + for(i = 0;i < todo;i++) + OutBuffer[0][OutPos+i] += out[i][0]; + for(i = 0;i < todo;i++) + OutBuffer[1][OutPos+i] += out[i][1]; + OutPos += todo; } } -- cgit v1.2.3 From 22abaa287d7c10fb1ae8ae34b32d5e0ebbbfad78 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Mar 2016 20:59:12 -0800 Subject: Use the real output's left and right channels with HRTF --- Alc/ALu.c | 29 +++++++++++++++++------------ Alc/mixer.c | 8 +++++++- Alc/mixer_defs.h | 24 ++++++++++++------------ Alc/mixer_inc.c | 15 ++++++++------- OpenAL32/Include/alu.h | 4 ++-- 5 files changed, 46 insertions(+), 34 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 17c91e52..d139cb7b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1454,20 +1454,25 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(device->Hrtf) { - HrtfMixerFunc HrtfMix = SelectHrtfMixer(); - ALuint irsize = GetHrtfIrSize(device->Hrtf); - MixHrtfParams hrtfparams; - memset(&hrtfparams, 0, sizeof(hrtfparams)); - for(c = 0;c < device->VirtOut.NumChannels;c++) + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + if(lidx != -1 && ridx != -1) { - hrtfparams.Current = &device->Hrtf_Params[c]; - hrtfparams.Target = &device->Hrtf_Params[c]; - HrtfMix(device->RealOut.Buffer, device->VirtOut.Buffer[c], 0, - device->Hrtf_Offset, 0, irsize, &hrtfparams, - &device->Hrtf_State[c], SamplesToDo - ); + HrtfMixerFunc HrtfMix = SelectHrtfMixer(); + ALuint irsize = GetHrtfIrSize(device->Hrtf); + MixHrtfParams hrtfparams; + memset(&hrtfparams, 0, sizeof(hrtfparams)); + for(c = 0;c < device->VirtOut.NumChannels;c++) + { + hrtfparams.Current = &device->Hrtf_Params[c]; + hrtfparams.Target = &device->Hrtf_Params[c]; + HrtfMix(device->RealOut.Buffer, lidx, ridx, + device->VirtOut.Buffer[c], 0, device->Hrtf_Offset, 0, + irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo + ); + } + device->Hrtf_Offset += SamplesToDo; } - device->Hrtf_Offset += SamplesToDo; } else { diff --git a/Alc/mixer.c b/Alc/mixer.c index 779d69e0..44495d72 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -603,6 +603,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam else { MixHrtfParams hrtfparams; + int lidx, ridx; + if(!Counter) { parms->Hrtf[chan].Current = parms->Hrtf[chan].Target; @@ -633,7 +635,11 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam hrtfparams.Target = &parms->Hrtf[chan].Target; hrtfparams.Current = &parms->Hrtf[chan].Current; - MixHrtfSamples(parms->OutBuffer, samples, Counter, voice->Offset, + lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(Device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + MixHrtfSamples(parms->OutBuffer, lidx, ridx, samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, &parms->Hrtf[chan].State, DstBufferSize); } diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 3fecab87..5db804b1 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -21,18 +21,18 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, A /* C mixers */ -void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, - ALuint BufferSize); +void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, + const ALuint IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); /* SSE mixers */ -void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, - ALuint BufferSize); +void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, + const ALuint IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); @@ -70,10 +70,10 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *sr ALfloat *restrict dst, ALuint numsamples); /* Neon mixers */ -void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, - ALuint BufferSize); +void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, + const ALuint IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index a57a3ecb..e9d81c2a 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -23,9 +23,10 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], ALfloat left, ALfloat right); -void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize) +void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, + const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + ALuint BufferSize) { ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; ALuint Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; @@ -66,9 +67,9 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, } for(i = 0;i < todo;i++) - OutBuffer[0][OutPos+i] += out[i][0]; + OutBuffer[lidx][OutPos+i] += out[i][0]; for(i = 0;i < todo;i++) - OutBuffer[1][OutPos+i] += out[i][1]; + OutBuffer[ridx][OutPos+i] += out[i][1]; OutPos += todo; } @@ -107,9 +108,9 @@ skip_stepping: } for(i = 0;i < todo;i++) - OutBuffer[0][OutPos+i] += out[i][0]; + OutBuffer[lidx][OutPos+i] += out[i][0]; for(i = 0;i < todo;i++) - OutBuffer[1][OutPos+i] += out[i][1]; + OutBuffer[ridx][OutPos+i] += out[i][1]; OutPos += todo; } } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index af2ea857..08f25204 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -193,8 +193,8 @@ typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, +typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize); -- cgit v1.2.3 From 0c4653085ceb9480fc20ec2087f653f0adff02b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Mar 2016 21:01:32 -0800 Subject: Don't request a specific HRTF when one isn't specified --- examples/alhrtf.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/alhrtf.c b/examples/alhrtf.c index b18a5115..2e6e7148 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -178,19 +178,22 @@ int main(int argc, char **argv) index = i; } + i = 0; + attr[i++] = ALC_HRTF_SOFT; + attr[i++] = ALC_TRUE; if(index == -1) { if(hrtfname) printf("HRTF \"%s\" not found\n", hrtfname); - index = 0; + printf("Using default HRTF...\n"); } - printf("Selecting HRTF %d...\n", index); - - attr[0] = ALC_HRTF_SOFT; - attr[1] = ALC_TRUE; - attr[2] = ALC_HRTF_ID_SOFT; - attr[3] = index; - attr[4] = 0; + else + { + printf("Selecting HRTF %d...\n", index); + attr[i++] = ALC_HRTF_ID_SOFT; + attr[i++] = index; + } + attr[i] = 0; if(!alcResetDeviceSOFT(device, attr)) printf("Failed to reset device: %s\n", alcGetString(device, alcGetError(device))); -- cgit v1.2.3 From 0220404a9152d2cb3024308655d4f0e6119167fa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Mar 2016 03:32:32 -0700 Subject: Use second-order coefficients for 5.1 Since the panning only drives 5 speakers, it shouldn't use more than 5 ambisonic channels (9 total in second order, minus 4 for unused height). --- Alc/panning.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 1765d1c8..49bc05b2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -444,22 +444,22 @@ ALvoid aluInitPanning(ALCdevice *device) { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, }, QuadCfg[4] = { - { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, - { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, }, X51SideCfg[5] = { - { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } }, - { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { SideLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } }, - { SideRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } }, + { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, + { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, + { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, + { SideLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, + { SideRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, }, X51RearCfg[5] = { - { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } }, - { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { BackLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } }, - { BackRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } }, + { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, + { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, + { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, + { BackLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, + { BackRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, }, X61Cfg[6] = { { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, @@ -586,13 +586,13 @@ ALvoid aluInitPanning(ALCdevice *device) case DevFmtX51: count = COUNTOF(X51SideCfg); chanmap = X51SideCfg; - ambiscale = THIRD_ORDER_SCALE; + ambiscale = SECOND_ORDER_SCALE; break; case DevFmtX51Rear: count = COUNTOF(X51RearCfg); chanmap = X51RearCfg; - ambiscale = THIRD_ORDER_SCALE; + ambiscale = SECOND_ORDER_SCALE; break; case DevFmtX61: -- cgit v1.2.3 From 919b35295e1b05293fd9f99a9a3f6d3f07a9c370 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 Mar 2016 09:04:03 -0700 Subject: Add a loader for ambdec files --- Alc/ambdec.c | 555 ++++++++++++++++++++++++++++++++++++++++++++++ Alc/ambdec.h | 46 ++++ CMakeLists.txt | 1 + OpenAL32/Include/alMain.h | 3 +- 4 files changed, 604 insertions(+), 1 deletion(-) create mode 100644 Alc/ambdec.c create mode 100644 Alc/ambdec.h diff --git a/Alc/ambdec.c b/Alc/ambdec.c new file mode 100644 index 00000000..9b467648 --- /dev/null +++ b/Alc/ambdec.c @@ -0,0 +1,555 @@ + +#include "config.h" + +#include "ambdec.h" + +#include +#include +#include + +#include "compat.h" + + +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 int readline(FILE *f, char **output, size_t *maxlen) +{ + size_t len = 0; + int c; + + while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) + ; + if(c == EOF) + return 0; + + do { + if(len+1 >= *maxlen) + { + void *temp = NULL; + size_t newmax; + + newmax = (*maxlen ? (*maxlen)<<1 : 32); + if(newmax > *maxlen) + temp = realloc(*output, newmax); + if(!temp) + { + ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen); + return 0; + } + + *output = temp; + *maxlen = newmax; + } + (*output)[len++] = c; + (*output)[len] = '\0'; + } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); + + return 1; +} + + +/* Custom strtok_r, since we can't rely on it existing. */ +static char *my_strtok_r(char *str, const char *delim, char **saveptr) +{ + /* Sanity check and update internal pointer. */ + if(!saveptr || !delim) return NULL; + if(str) *saveptr = str; + str = *saveptr; + + /* Nothing more to do with this string. */ + if(!str) return NULL; + + /* Find the first non-delimiter character. */ + while(*str != '\0' && strchr(delim, *str) != NULL) + str++; + if(*str == '\0') + { + /* End of string. */ + *saveptr = NULL; + return NULL; + } + + /* Find the next delimiter character. */ + *saveptr = strpbrk(str, delim); + if(*saveptr) *((*saveptr)++) = '\0'; + + return str; +} + +static char *read_uint(ALuint *num, const char *line, int base) +{ + char *end; + *num = strtoul(line, &end, base); + if(end && *end != '\0') + end = lstrip(end); + return end; +} + +static char *read_float(ALfloat *num, const char *line) +{ + char *end; +#ifdef HAVE_STRTOF + *num = strtof(line, &end); +#else + *num = strtod(line, &end); +#endif + if(end && *end != '\0') + end = lstrip(end); + return end; +} + + +char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen) +{ + while(readline(f, buffer, maxlen)) + { + char *line, *comment; + + line = lstrip(*buffer); + comment = strchr(line, '#'); + if(comment) *(comment++) = 0; + + line = rstrip(line); + if(line[0]) return line; + } + return NULL; +} + +static int load_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr) +{ + ALuint cur = 0; + while(cur < conf->NumSpeakers) + { + const char *cmd = my_strtok_r(NULL, " \t", saveptr); + if(!cmd) + { + char *line = read_clipped_line(f, buffer, maxlen); + if(!line) + { + ERR("Unexpected end of file\n"); + return 0; + } + cmd = my_strtok_r(line, " \t", saveptr); + } + + if(strcmp(cmd, "add_spkr") == 0) + { + const char *name = my_strtok_r(NULL, " \t", saveptr); + const char *dist = my_strtok_r(NULL, " \t", saveptr); + const char *az = my_strtok_r(NULL, " \t", saveptr); + const char *elev = my_strtok_r(NULL, " \t", saveptr); + const char *conn = my_strtok_r(NULL, " \t", saveptr); + + if(!name) ERR("Name not specified for speaker %u\n", cur+1); + else al_string_copy_cstr(&conf->Speakers[cur].Name, name); + if(!dist) ERR("Distance not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Distance, dist); + if(!az) ERR("Azimuth not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Azimuth, az); + if(!elev) ERR("Elevation not specified for speaker %u\n", cur+1); + else read_float(&conf->Speakers[cur].Elevation, elev); + if(!conn) ERR("Connection not specified for speaker %u\n", cur+1); + else al_string_copy_cstr(&conf->Speakers[cur].Connection, conn); + cur++; + } + else + { + ERR("Unexpected speakers command: %s\n", cmd); + return 0; + } + + cmd = my_strtok_r(NULL, " \t", saveptr); + if(cmd) + { + ERR("Unexpected junk on line: %s\n", cmd); + return 0; + } + } + + return 1; +} + +static int load_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALuint maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) +{ + int gotgains = 0; + ALuint cur = 0; + while(cur < maxrow) + { + const char *cmd = my_strtok_r(NULL, " \t", saveptr); + if(!cmd) + { + char *line = read_clipped_line(f, buffer, maxlen); + if(!line) + { + ERR("Unexpected end of file\n"); + return 0; + } + cmd = my_strtok_r(line, " \t", saveptr); + } + + if(strcmp(cmd, "order_gain") == 0) + { + ALuint curgain = 0; + char *line; + while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL) + { + ALfloat value; + line = read_float(&value, line); + if(line && *line != '\0') + { + ERR("Extra junk on gain %u: %s\n", curgain+1, line); + return 0; + } + if(curgain < MAX_AMBI_ORDER+1) + gains[curgain] = value; + curgain++; + } + while(curgain < MAX_AMBI_ORDER+1) + gains[curgain++] = 0.0f; + gotgains = 1; + } + else if(strcmp(cmd, "add_row") == 0) + { + ALuint curidx = 0; + char *line; + while((line=my_strtok_r(NULL, " \t", saveptr)) != NULL) + { + ALfloat value; + line = read_float(&value, line); + if(line && *line != '\0') + { + ERR("Extra junk on matrix element %ux%u: %s\n", cur, curidx, line); + return 0; + } + if(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx] = value; + curidx++; + } + while(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx++] = 0.0f; + cur++; + } + else + { + ERR("Unexpected speakers command: %s\n", cmd); + return 0; + } + + cmd = my_strtok_r(NULL, " \t", saveptr); + if(cmd) + { + ERR("Unexpected junk on line: %s\n", cmd); + return 0; + } + } + + if(!gotgains) + { + ERR("Matrix order_gain not specified\n"); + return 0; + } + + return 1; +} + +void ambdec_init(AmbDecConf *conf) +{ + ALuint i; + + memset(conf, 0, sizeof(*conf)); + AL_STRING_INIT(conf->Description); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + AL_STRING_INIT(conf->Speakers[i].Name); + AL_STRING_INIT(conf->Speakers[i].Connection); + } +} + +void ambdec_deinit(AmbDecConf *conf) +{ + ALuint i; + + al_string_deinit(&conf->Description); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + al_string_deinit(&conf->Speakers[i].Name); + al_string_deinit(&conf->Speakers[i].Connection); + } + memset(conf, 0, sizeof(*conf)); +} + +int ambdec_load(AmbDecConf *conf, const char *fname) +{ + char *buffer = NULL; + size_t maxlen = 0; + FILE *f; + + f = al_fopen(fname, "r"); + if(!f) + { + ERR("Failed to open: %s\n", fname); + return 0; + } + + while(read_clipped_line(f, &buffer, &maxlen)) + { + char *line, *saveptr; + char *command; + + command = my_strtok_r(buffer, "/ \t", &saveptr); + if(!command) + { + ERR("Malformed line: %s\n", line); + goto fail; + } + + if(strcmp(command, "description") == 0) + { + char *value = my_strtok_r(NULL, "", &saveptr); + al_string_copy_cstr(&conf->Description, lstrip(value)); + } + else if(strcmp(command, "version") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_uint(&conf->Version, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after version: %s\n", line); + goto fail; + } + if(conf->Version != 3) + { + ERR("Unsupported version: %u\n", conf->Version); + goto fail; + } + } + else if(strcmp(command, "dec") == 0) + { + const char *dec = my_strtok_r(NULL, "/ \t", &saveptr); + if(strcmp(dec, "chan_mask") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_uint(&conf->ChanMask, line, 16); + if(line && *line != '\0') + { + ERR("Extra junk after mask: %s\n", line); + goto fail; + } + } + else if(strcmp(dec, "freq_bands") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_uint(&conf->FreqBands, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after freq_bands: %s\n", line); + goto fail; + } + if(conf->FreqBands != 1 && conf->FreqBands != 2) + { + ERR("Invalid freq_bands value: %u\n", conf->FreqBands); + goto fail; + } + } + else if(strcmp(dec, "speakers") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_uint(&conf->NumSpeakers, line, 10); + if(line && *line != '\0') + { + ERR("Extra junk after speakers: %s\n", line); + goto fail; + } + if(conf->NumSpeakers > MAX_OUTPUT_CHANNELS) + { + ERR("Unsupported speaker count: %u\n", conf->NumSpeakers); + goto fail; + } + } + else if(strcmp(dec, "coeff_scale") == 0) + { + line = my_strtok_r(NULL, " \t", &saveptr); + if(strcmp(line, "n3d") == 0) + conf->CoeffScale = ADS_N3D; + else if(strcmp(line, "sn3d") == 0) + conf->CoeffScale = ADS_SN3D; + else if(strcmp(line, "fuma") == 0) + conf->CoeffScale = ADS_FuMa; + else + { + ERR("Unsupported coeff scale: %s\n", line); + goto fail; + } + } + else + { + ERR("Unexpected /dec option: %s\n", dec); + goto fail; + } + } + else if(strcmp(command, "opt") == 0) + { + const char *opt = my_strtok_r(NULL, "/ \t", &saveptr); + if(strcmp(opt, "xover_freq") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_float(&conf->XOverFreq, line); + if(line && *line != '\0') + { + ERR("Extra junk after xover_freq: %s\n", line); + goto fail; + } + } + else if(strcmp(opt, "xover_ratio") == 0) + { + line = my_strtok_r(NULL, "", &saveptr); + line = read_float(&conf->XOverRatio, line); + if(line && *line != '\0') + { + ERR("Extra junk after xover_ratio: %s\n", line); + goto fail; + } + } + else if(strcmp(opt, "input_scale") == 0 || strcmp(opt, "nfeff_comp") == 0 || + strcmp(opt, "delay_comp") == 0 || strcmp(opt, "level_comp") == 0) + { + /* Unused */ + my_strtok_r(NULL, " \t", &saveptr); + } + else + { + ERR("Unexpected /opt option: %s\n", opt); + goto fail; + } + } + else if(strcmp(command, "speakers") == 0) + { + const char *value = my_strtok_r(NULL, "/ \t", &saveptr); + if(strcmp(value, "{") != 0) + { + ERR("Expected { after speakers command, got %s\n", value); + goto fail; + } + if(!load_speakers(conf, f, &buffer, &maxlen, &saveptr)) + goto fail; + value = my_strtok_r(NULL, "/ \t", &saveptr); + if(!value) + { + line = read_clipped_line(f, &buffer, &maxlen); + if(!line) + { + ERR("Unexpected end of file\n"); + goto fail; + } + value = my_strtok_r(line, "/ \t", &saveptr); + } + if(strcmp(value, "}") != 0) + { + ERR("Expected } after speaker definitions, got %s\n", value); + goto fail; + } + } + else if(strcmp(command, "lfmatrix") == 0 || strcmp(command, "hfmatrix") == 0 || + strcmp(command, "matrix") == 0) + { + const char *value = my_strtok_r(NULL, "/ \t", &saveptr); + if(strcmp(value, "{") != 0) + { + ERR("Expected { after speakers command, got %s\n", value); + goto fail; + } + if(conf->FreqBands == 1) + { + if(strcmp(command, "matrix") != 0) + { + ERR("Unexpected \"%s\" type for a single-band decoder\n", command); + goto fail; + } + if(!load_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) + goto fail; + } + else + { + if(strcmp(command, "lfmatrix") == 0) + { + if(!load_matrix(conf->LFOrderGain, conf->LFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) + goto fail; + } + else if(strcmp(command, "hfmatrix") == 0) + { + if(!load_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) + goto fail; + } + else + { + ERR("Unexpected \"%s\" type for a dual-band decoder\n", command); + goto fail; + } + } + value = my_strtok_r(NULL, "/ \t", &saveptr); + if(!value) + { + line = read_clipped_line(f, &buffer, &maxlen); + if(!line) + { + ERR("Unexpected end of file\n"); + goto fail; + } + value = my_strtok_r(line, "/ \t", &saveptr); + } + if(strcmp(value, "}") != 0) + { + ERR("Expected } after matrix definitions, got %s\n", value); + goto fail; + } + } + else if(strcmp(command, "end") == 0) + { + line = my_strtok_r(NULL, "/ \t", &saveptr); + if(line) + { + ERR("Unexpected junk on end: %s\n", line); + goto fail; + } + + fclose(f); + free(buffer); + return 1; + } + else + { + ERR("Unexpected command: %s\n", command); + goto fail; + } + + line = my_strtok_r(NULL, "/ \t", &saveptr); + if(line) + { + ERR("Unexpected junk on line: %s\n", line); + goto fail; + } + } + ERR("Unexpected end of file\n"); + +fail: + fclose(f); + free(buffer); + return 0; +} diff --git a/Alc/ambdec.h b/Alc/ambdec.h new file mode 100644 index 00000000..8a3befc1 --- /dev/null +++ b/Alc/ambdec.h @@ -0,0 +1,46 @@ +#ifndef AMBDEC_H +#define AMBDEC_H + +#include "alstring.h" +#include "alMain.h" + +/* Helpers to read .ambdec configuration files. */ + +enum AmbDecScaleType { + ADS_N3D, + ADS_SN3D, + ADS_FuMa, +}; +typedef struct AmbDecConf { + al_string Description; + ALuint Version; /* Must be 3 */ + + ALuint ChanMask; + ALuint FreqBands; /* Must be 1 or 2 */ + ALuint NumSpeakers; + enum AmbDecScaleType CoeffScale; + + ALfloat XOverFreq; + ALfloat XOverRatio; + + struct { + al_string Name; + ALfloat Distance; + ALfloat Azimuth; + ALfloat Elevation; + al_string Connection; + } Speakers[MAX_OUTPUT_CHANNELS]; + + /* Unused when FreqBands == 1 */ + ALfloat LFOrderGain[MAX_AMBI_ORDER+1]; + ALfloat LFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + + ALfloat HFOrderGain[MAX_AMBI_ORDER+1]; + ALfloat HFMatrix[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; +} AmbDecConf; + +void ambdec_init(AmbDecConf *conf); +void ambdec_deinit(AmbDecConf *conf); +int ambdec_load(AmbDecConf *conf, const char *fname); + +#endif /* AMBDEC_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 33eb180e..d815c2aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -644,6 +644,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/bsinc.c Alc/hrtf.c Alc/uhjfilter.c + Alc/ambdec.c Alc/panning.c Alc/mixer.c Alc/mixer_c.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index aae19b05..86311761 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -397,7 +397,8 @@ enum RenderMode { /* The maximum number of Ambisonics coefficients. For a given order (o), the * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, * second-order has 9, and third-order has 16. */ -#define MAX_AMBI_COEFFS 16 +#define MAX_AMBI_ORDER 3 +#define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; -- cgit v1.2.3 From 066df88a2cbac15caed8b57926cce113d2182ed7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 Mar 2016 20:25:36 -0700 Subject: Always mix to the real output for DirectChannels --- Alc/ALu.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d139cb7b..d7f68c03 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -553,29 +553,17 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A if(DirectChannels) { - if(Device->Hrtf || Device->Uhj_Encoder) - { - /* DirectChannels with HRTF or UHJ enabled. Skip the virtual - * channels and write FrontLeft and FrontRight inputs to the - * first and second outputs. - */ - voice->Direct.OutBuffer = Device->RealOut.Buffer; - voice->Direct.OutChannels = Device->RealOut.NumChannels; - for(c = 0;c < num_channels;c++) - { - int idx; - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Gains[c].Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Gains[c].Target[idx] = DryGain; - } - } - else for(c = 0;c < num_channels;c++) + /* Skip the virtual channels and write FrontLeft and FrontRight + * inputs to the real output. + */ + voice->Direct.OutBuffer = Device->RealOut.Buffer; + voice->Direct.OutChannels = Device->RealOut.NumChannels; + for(c = 0;c < num_channels;c++) { int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1) + if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) voice->Direct.Gains[c].Target[idx] = DryGain; } -- cgit v1.2.3 From 64cb21cb9ff08d222d00eedc38fbc0970543bac3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Mar 2016 04:02:25 -0700 Subject: Downgrade some ERRs to WARNs or TRACEs --- Alc/ambdec.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Alc/ambdec.c b/Alc/ambdec.c index 9b467648..a1e3e396 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -154,15 +154,15 @@ static int load_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxle const char *elev = my_strtok_r(NULL, " \t", saveptr); const char *conn = my_strtok_r(NULL, " \t", saveptr); - if(!name) ERR("Name not specified for speaker %u\n", cur+1); + if(!name) WARN("Name not specified for speaker %u\n", cur+1); else al_string_copy_cstr(&conf->Speakers[cur].Name, name); - if(!dist) ERR("Distance not specified for speaker %u\n", cur+1); + if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); else read_float(&conf->Speakers[cur].Distance, dist); - if(!az) ERR("Azimuth not specified for speaker %u\n", cur+1); + if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); else read_float(&conf->Speakers[cur].Azimuth, az); - if(!elev) ERR("Elevation not specified for speaker %u\n", cur+1); + if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); else read_float(&conf->Speakers[cur].Elevation, elev); - if(!conn) ERR("Connection not specified for speaker %u\n", cur+1); + if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); else al_string_copy_cstr(&conf->Speakers[cur].Connection, conn); cur++; } @@ -296,6 +296,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) { char *buffer = NULL; size_t maxlen = 0; + char *line; FILE *f; f = al_fopen(fname, "r"); @@ -305,12 +306,12 @@ int ambdec_load(AmbDecConf *conf, const char *fname) return 0; } - while(read_clipped_line(f, &buffer, &maxlen)) + while((line=read_clipped_line(f, &buffer, &maxlen)) != NULL) { - char *line, *saveptr; + char *saveptr; char *command; - command = my_strtok_r(buffer, "/ \t", &saveptr); + command = my_strtok_r(line, "/ \t", &saveptr); if(!command) { ERR("Malformed line: %s\n", line); -- cgit v1.2.3 From 53fadf54977a3312db66e7e086c9b01d9162ae29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Mar 2016 05:08:05 -0700 Subject: Add a dual-band ambisonic decoder This uses a virtual B-Format buffer for mixing, and then uses a dual-band decoder for improved positional quality. This currently only works with first- order output since first-order input (from the AL_EXT_BFROMAT extension) would not sound correct when fed through a second- or third-order decoder. This also does not currently implement near-field compensation since near-field rendering effects are not implemented. --- Alc/ALc.c | 17 ++- Alc/ALu.c | 8 ++ Alc/bformatdec.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++ Alc/bformatdec.h | 14 +++ Alc/effects/reverb.c | 20 ++-- Alc/panning.c | 131 ++++++++++++++++++++- CMakeLists.txt | 1 + OpenAL32/Include/alMain.h | 3 + OpenAL32/Include/alu.h | 3 +- 9 files changed, 467 insertions(+), 16 deletions(-) create mode 100644 Alc/bformatdec.c create mode 100644 Alc/bformatdec.h diff --git a/Alc/ALc.c b/Alc/ALc.c index 8ede026a..f51757e8 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -37,6 +37,8 @@ #include "alError.h" #include "bs2b.h" #include "uhjfilter.h" +#include "bformatdec.h" +#include "ambdec.h" #include "alu.h" #include "compat.h" @@ -2116,12 +2118,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - aluInitPanning(device); + aluInitPanning(device, NULL); - /* With HRTF, allocate two extra channels for the post-filter output. */ + /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); - if(device->Hrtf || device->Uhj_Encoder) - size += 2 * sizeof(device->Dry.Buffer[0]); + if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) + size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) { @@ -2129,12 +2131,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if(device->Hrtf || device->Uhj_Encoder) + if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) { device->VirtOut.Buffer = device->Dry.Buffer; device->VirtOut.NumChannels = device->Dry.NumChannels; device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - device->RealOut.NumChannels = 2; + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); } else { @@ -2277,6 +2279,9 @@ static ALCvoid FreeDevice(ALCdevice *device) al_free(device->Uhj_Encoder); device->Uhj_Encoder = NULL; + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + AL_STRING_DEINIT(device->DeviceName); al_free(device->Dry.Buffer); diff --git a/Alc/ALu.c b/Alc/ALu.c index d7f68c03..5064a588 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -35,6 +35,7 @@ #include "bs2b.h" #include "hrtf.h" #include "uhjfilter.h" +#include "bformatdec.h" #include "static_assert.h" #include "mixer_defs.h" @@ -1462,6 +1463,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->Hrtf_Offset += SamplesToDo; } } + else if(device->AmbiDecoder) + { + bformatdec_process(device->AmbiDecoder, + device->RealOut.Buffer, device->RealOut.NumChannels, + device->VirtOut.Buffer, SamplesToDo + ); + } else { if(device->Uhj_Encoder) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c new file mode 100644 index 00000000..d917f803 --- /dev/null +++ b/Alc/bformatdec.c @@ -0,0 +1,286 @@ + +#include "config.h" + +#include "bformatdec.h" +#include "ambdec.h" +#include "alu.h" + + +typedef struct BandSplitter { + ALfloat coeff; + ALfloat lp_z1; + ALfloat lp_z2; + ALfloat hp_z1; +} BandSplitter; + +static void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult) +{ + ALfloat w = freq_mult * F_TAU; + ALfloat cw = cosf(w); + if(cw > FLT_EPSILON) + splitter->coeff = (sinf(w) - 1.0f) / cw; + else + splitter->coeff = cw * -0.5f; + + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +static void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, + const ALfloat *input, ALuint count) +{ + ALfloat coeff, d, x; + ALuint i; + + coeff = splitter->coeff*0.5f + 0.5f; + for(i = 0;i < count;i++) + { + x = input[i]; + + d = (x - splitter->lp_z1) * coeff; + x = splitter->lp_z1 + d; + splitter->lp_z1 = x + d; + + d = (x - splitter->lp_z2) * coeff; + x = splitter->lp_z2 + d; + splitter->lp_z2 = x + d; + + lpout[i] = x; + } + + coeff = splitter->coeff; + for(i = 0;i < count;i++) + { + x = input[i]; + + d = x - coeff*splitter->hp_z1; + x = splitter->hp_z1 + coeff*d; + splitter->hp_z1 = d; + + hpout[i] = x - lpout[i]; + } +} + + +static const ALfloat UnitScale[MAX_AMBI_COEFFS] = { + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f +}; +static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { + 1.000000000f, /* ACN 0 (W), sqrt(1) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 2.236067978f, /* ACN 4 (V), sqrt(5) */ + 2.236067978f, /* ACN 5 (T), sqrt(5) */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 2.236067978f, /* ACN 7 (S), sqrt(5) */ + 2.236067978f, /* ACN 8 (U), sqrt(5) */ + 2.645751311f, /* ACN 9 (Q), sqrt(7) */ + 2.645751311f, /* ACN 10 (O), sqrt(7) */ + 2.645751311f, /* ACN 11 (M), sqrt(7) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.645751311f, /* ACN 13 (L), sqrt(7) */ + 2.645751311f, /* ACN 14 (N), sqrt(7) */ + 2.645751311f, /* ACN 15 (P), sqrt(7) */ +}; +static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ +}; + + +/* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with + * single-band decoding + */ +typedef struct BFormatDec { + alignas(16) ALfloat MatrixHF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + alignas(16) ALfloat MatrixLF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + + BandSplitter XOver[MAX_AMBI_COEFFS]; + + ALfloat (*Samples)[BUFFERSIZE]; + /* These two alias into Samples */ + ALfloat (*SamplesHF)[BUFFERSIZE]; + ALfloat (*SamplesLF)[BUFFERSIZE]; + + ALuint NumChannels; + ALboolean DualBand; +} BFormatDec; + +BFormatDec *bformatdec_alloc() +{ + return al_calloc(16, sizeof(BFormatDec)); +} + +void bformatdec_free(BFormatDec *dec) +{ + if(dec) + { + al_free(dec->Samples); + dec->Samples = NULL; + dec->SamplesHF = NULL; + dec->SamplesLF = NULL; + + memset(dec, 0, sizeof(*dec)); + al_free(dec); + } +} + +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]) +{ + const ALfloat *coeff_scale = UnitScale; + ALfloat ratio; + ALuint i; + + al_free(dec->Samples); + dec->Samples = NULL; + dec->SamplesHF = NULL; + dec->SamplesLF = NULL; + + dec->NumChannels = chancount; + dec->Samples = al_calloc(16, dec->NumChannels * conf->FreqBands * + sizeof(dec->Samples[0])); + dec->SamplesHF = dec->Samples; + dec->SamplesLF = dec->SamplesHF + dec->NumChannels; + + if(conf->CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf->CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; + + if(conf->FreqBands == 1) + { + dec->DualBand = AL_FALSE; + ratio = 1.0f; + } + else + { + dec->DualBand = AL_TRUE; + + ratio = conf->XOverFreq / (ALfloat)srate; + for(i = 0;i < MAX_AMBI_COEFFS;i++) + bandsplit_init(&dec->XOver[i], ratio); + + ratio = powf(10.0f, conf->XOverRatio / 40.0f); + memset(dec->MatrixLF, 0, sizeof(dec->MatrixLF)); + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = chanmap[i]; + ALuint j, k = 0; + + for(j = 0;j < 1;j++) + { + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + conf->LFOrderGain[0] / ratio; + } + for(;j < 4;j++) + { + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + conf->LFOrderGain[1] / ratio; + } + for(;j < 9;j++) + { + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + conf->LFOrderGain[2] / ratio; + } + for(;j < 16;j++) + { + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + conf->LFOrderGain[3] / ratio; + } + } + } + + memset(dec->MatrixHF, 0, sizeof(dec->MatrixHF)); + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = chanmap[i]; + ALuint j, k = 0; + + for(j = 0;j < 1;j++) + { + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + conf->HFOrderGain[0] * ratio; + } + for(;j < 4;j++) + { + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + conf->HFOrderGain[1] * ratio; + } + for(;j < 9;j++) + { + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + conf->HFOrderGain[2] * ratio; + } + for(;j < 16;j++) + { + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + conf->HFOrderGain[3] * ratio; + } + } +} + + +static void apply_row(ALfloat *out, const ALfloat *mtx, ALfloat (*restrict in)[BUFFERSIZE], ALuint inchans, ALuint todo) +{ + ALuint c, i; + + for(c = 0;c < inchans;c++) + { + ALfloat gain = mtx[c]; + if(!(gain > GAIN_SILENCE_THRESHOLD)) + continue; + for(i = 0;i < todo;i++) + out[i] += in[c][i] * gain; + } +} + +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +{ + ALuint chan, i; + + if(dec->DualBand) + { + for(i = 0;i < dec->NumChannels;i++) + bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], + InSamples[i], SamplesToDo); + + for(chan = 0;chan < OutChannels;chan++) + { + apply_row(OutBuffer[chan], dec->MatrixHF[chan], dec->SamplesHF, + dec->NumChannels, SamplesToDo); + apply_row(OutBuffer[chan], dec->MatrixLF[chan], dec->SamplesLF, + dec->NumChannels, SamplesToDo); + } + } + else + { + for(chan = 0;chan < OutChannels;chan++) + apply_row(OutBuffer[chan], dec->MatrixHF[chan], InSamples, + dec->NumChannels, SamplesToDo); + } +} diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h new file mode 100644 index 00000000..a322f41d --- /dev/null +++ b/Alc/bformatdec.h @@ -0,0 +1,14 @@ +#ifndef BFORMATDEC_H +#define BFORMATDEC_H + +#include "alMain.h" + +struct AmbDecConf; +struct BFormatDec; + +struct BFormatDec *bformatdec_alloc(); +void bformatdec_free(struct BFormatDec *dec); +void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]); +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); + +#endif /* BFORMATDEC_H */ diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index e68e6e19..cf31ba62 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -87,10 +87,11 @@ typedef struct ALreverbState { ALuint Offset[4]; // The gain for each output channel based on 3D panning. - // NOTE: With HRTF, we may be rendering to the dry buffer and the - // "real" buffer. The dry buffer may be using all 8 output channels, so - // we need two extra for the real stereo output. - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; + // NOTE: With certain output modes, we may be rendering to the dry + // buffer and the "real" buffer. The two combined may be using more + // than 8 output channels, so we need some extra for the real output + // too. + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+4]; } Early; // Decorrelator delay line. @@ -128,8 +129,8 @@ typedef struct ALreverbState { ALfloat LpSample[4]; // The gain for each output channel based on 3D panning. - // NOTE: Add two in case of HRTF (see note about early pan). - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; + // NOTE: Add some extra in case (see note about early pan). + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+4]; } Late; struct { @@ -371,7 +372,10 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev /* WARNING: This assumes the real output follows the virtual output in the * device's DryBuffer. */ - State->ExtraChannels = (Device->Hrtf || Device->Uhj_Encoder) ? 2 : 0; + if(Device->Hrtf || Device->Uhj_Encoder || Device->AmbiDecoder) + State->ExtraChannels = ChannelsFromDevFmt(Device->FmtChans); + else + State->ExtraChannels = 0; // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the @@ -938,7 +942,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf || Device->Uhj_Encoder) + if(Device->Hrtf || Device->Uhj_Encoder || Device->AmbiDecoder) UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, diff --git a/Alc/panning.c b/Alc/panning.c index 49bc05b2..df504292 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -30,6 +30,8 @@ #include "alAuxEffectSlot.h" #include "alu.h" #include "bool.h" +#include "ambdec.h" +#include "bformatdec.h" extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]); @@ -252,6 +254,88 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff *outcount = i; } +static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS]) +{ + ALuint i; + + for(i = 0;i < conf->NumSpeakers;i++) + { + int c = -1; + + /* NOTE: AmbDec does not define any standard speaker names, however + * for this to work we have to by able to find the output channel + * the speaker definition corresponds to. Therefore, OpenAL Soft + * requires these channel labels to be recognized: + * + * LF = Front left + * RF = Front right + * LS = Side left + * RS = Side right + * LB = Back left + * RB = Back right + * CE = Front center + * CB = Back center + * + * Additionally, surround51 will acknowledge back speakers for side + * channels, and surround51rear will acknowledge side speakers for + * back channels, to avoid issues with an ambdec expecting 5.1 to + * use the side channels when the device is configured for back, + * and vice-versa. + */ + if(al_string_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) + c = GetChannelIdxByName(device->RealOut, FrontLeft); + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) + c = GetChannelIdxByName(device->RealOut, FrontRight); + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) + c = GetChannelIdxByName(device->RealOut, FrontCenter); + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) + { + if(device->FmtChans == DevFmtX51Rear) + c = GetChannelIdxByName(device->RealOut, BackLeft); + else + c = GetChannelIdxByName(device->RealOut, SideLeft); + } + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) + { + if(device->FmtChans == DevFmtX51Rear) + c = GetChannelIdxByName(device->RealOut, BackRight); + else + c = GetChannelIdxByName(device->RealOut, SideRight); + } + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) + { + if(device->FmtChans == DevFmtX51) + c = GetChannelIdxByName(device->RealOut, SideLeft); + else + c = GetChannelIdxByName(device->RealOut, BackLeft); + } + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) + { + if(device->FmtChans == DevFmtX51) + c = GetChannelIdxByName(device->RealOut, SideRight); + else + c = GetChannelIdxByName(device->RealOut, BackRight); + } + else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) + c = GetChannelIdxByName(device->RealOut, BackCenter); + else + { + ERR("AmbDec speaker label \"%s\" not recognized\n", + al_string_get_cstr(conf->Speakers[i].Name)); + return false; + } + if(c == -1) + { + ERR("Failed to lookup AmbDec speaker label %s\n", + al_string_get_cstr(conf->Speakers[i].Name)); + return false; + } + speakermap[i] = c; + } + + return true; +} + static bool LoadChannelSetup(ALCdevice *device) { static const enum Channel mono_chans[1] = { @@ -432,7 +516,7 @@ static bool LoadChannelSetup(ALCdevice *device) return true; } -ALvoid aluInitPanning(ALCdevice *device) +ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) { /* NOTE: These decoder coefficients are using FuMa channel ordering and * normalization, since that's what was produced by the Ambisonic Decoder @@ -556,6 +640,51 @@ ALvoid aluInitPanning(ALCdevice *device) return; } + if(device->AmbiDecoder) + { + /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ + static const ChannelMap Ambi3D[4] = { + { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } }, + }; + ALuint speakermap[MAX_OUTPUT_CHANNELS]; + + if(conf->ChanMask > 0xffff) + { + ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf->ChanMask); + goto ambi_fail; + } + if(conf->ChanMask > 0xf) + { + ERR("Only first-order is supported for HQ decoding (mask 0x%04x, max 0xf)\n", + conf->ChanMask); + goto ambi_fail; + } + + if(!MakeSpeakerMap(device, conf, speakermap)) + goto ambi_fail; + bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); + + count = COUNTOF(Ambi3D); + chanmap = Ambi3D; + ambiscale = FIRST_ORDER_SCALE; + + for(i = 0;i < count;i++) + device->Dry.ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_FALSE); + device->Dry.AmbiScale = ambiscale; + + return; + + ambi_fail: + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + } for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; diff --git a/CMakeLists.txt b/CMakeLists.txt index d815c2aa..c3e17967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -645,6 +645,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/hrtf.c Alc/uhjfilter.c Alc/ambdec.c + Alc/bformatdec.c Alc/panning.c Alc/mixer.c Alc/mixer_c.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 86311761..3ce95801 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -476,6 +476,9 @@ struct ALCdevice_struct // Stereo-to-binaural filter struct bs2b *Bs2b; + /* High quality Ambisonic decoder */ + struct BFormatDec *AmbiDecoder; + /* Rendering mode. */ enum RenderMode Render_Mode; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 08f25204..dfc9284f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -33,6 +33,7 @@ extern "C" { #endif +struct AmbDecConf; struct ALsource; struct ALvoice; struct ALeffectslot; @@ -280,7 +281,7 @@ inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat v void aluInitMixer(void); -ALvoid aluInitPanning(ALCdevice *Device); +ALvoid aluInitPanning(ALCdevice *Device, const struct AmbDecConf *conf); void aluInitEffectPanning(struct ALeffectslot *slot); -- cgit v1.2.3 From 23bce59c663ad9227767d53325a33977675896d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Mar 2016 07:07:09 -0700 Subject: Rename a couple functions for more informative logging --- Alc/ambdec.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Alc/ambdec.c b/Alc/ambdec.c index a1e3e396..6920d705 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -129,7 +129,7 @@ char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen) return NULL; } -static int load_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr) +static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr) { ALuint cur = 0; while(cur < conf->NumSpeakers) @@ -164,6 +164,7 @@ static int load_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxle else read_float(&conf->Speakers[cur].Elevation, elev); if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); else al_string_copy_cstr(&conf->Speakers[cur].Connection, conn); + cur++; } else @@ -183,7 +184,7 @@ static int load_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxle return 1; } -static int load_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALuint maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) +static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALuint maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) { int gotgains = 0; ALuint cur = 0; @@ -445,7 +446,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) ERR("Expected { after speakers command, got %s\n", value); goto fail; } - if(!load_speakers(conf, f, &buffer, &maxlen, &saveptr)) + if(!load_ambdec_speakers(conf, f, &buffer, &maxlen, &saveptr)) goto fail; value = my_strtok_r(NULL, "/ \t", &saveptr); if(!value) @@ -480,22 +481,22 @@ int ambdec_load(AmbDecConf *conf, const char *fname) ERR("Unexpected \"%s\" type for a single-band decoder\n", command); goto fail; } - if(!load_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) + if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) goto fail; } else { if(strcmp(command, "lfmatrix") == 0) { - if(!load_matrix(conf->LFOrderGain, conf->LFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) + if(!load_ambdec_matrix(conf->LFOrderGain, conf->LFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) goto fail; } else if(strcmp(command, "hfmatrix") == 0) { - if(!load_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, - f, &buffer, &maxlen, &saveptr)) + if(!load_ambdec_matrix(conf->HFOrderGain, conf->HFMatrix, conf->NumSpeakers, + f, &buffer, &maxlen, &saveptr)) goto fail; } else -- cgit v1.2.3 From 3a26d853ba02d970b3e31db85c8b4b32c14417b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Mar 2016 08:00:03 -0700 Subject: Replace the custom layout options with an ambdec loader The ambisonic layout options were never very good for clarity or flexibility. Hopefully using ambdec files will prove to be better. --- Alc/panning.c | 216 +++++++++++++++++++++++----------------------------------- 1 file changed, 87 insertions(+), 129 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index df504292..e090461e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -62,10 +62,31 @@ static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = { 9, /* Q */ }; -/* NOTE: These are scale factors as applied to Ambisonics content. FuMa - * decoder coefficients should be divided by these values to get N3D decoder - * coefficients. +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper N3D scalings. */ +static const ALfloat UnitScale[MAX_AMBI_COEFFS] = { + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f +}; +static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { + 1.000000000f, /* ACN 0 (W), sqrt(1) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 2.236067978f, /* ACN 4 (V), sqrt(5) */ + 2.236067978f, /* ACN 5 (T), sqrt(5) */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 2.236067978f, /* ACN 7 (S), sqrt(5) */ + 2.236067978f, /* ACN 8 (U), sqrt(5) */ + 2.645751311f, /* ACN 9 (Q), sqrt(7) */ + 2.645751311f, /* ACN 10 (O), sqrt(7) */ + 2.645751311f, /* ACN 11 (M), sqrt(7) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.645751311f, /* ACN 13 (L), sqrt(7) */ + 2.645751311f, /* ACN 14 (N), sqrt(7) */ + 2.645751311f, /* ACN 15 (P), sqrt(7) */ +}; static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { 1.414213562f, /* ACN 0 (W), sqrt(2) */ 1.732050808f, /* ACN 1 (Y), sqrt(3) */ @@ -338,73 +359,37 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe static bool LoadChannelSetup(ALCdevice *device) { - static const enum Channel mono_chans[1] = { - FrontCenter - }, stereo_chans[2] = { - FrontLeft, FrontRight - }, quad_chans[4] = { - FrontLeft, FrontRight, - BackLeft, BackRight - }, surround51_chans[5] = { - FrontLeft, FrontRight, FrontCenter, - SideLeft, SideRight - }, surround51rear_chans[5] = { - FrontLeft, FrontRight, FrontCenter, - BackLeft, BackRight - }, surround61_chans[6] = { - FrontLeft, FrontRight, - FrontCenter, BackCenter, - SideLeft, SideRight - }, surround71_chans[7] = { - FrontLeft, FrontRight, FrontCenter, - BackLeft, BackRight, - SideLeft, SideRight - }; ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; - const enum Channel *channels = NULL; + ALuint speakermap[MAX_OUTPUT_CHANNELS]; + const ALfloat *coeff_scale = UnitScale; const char *layout = NULL; ALfloat ambiscale = 1.0f; - size_t count = 0; - int isfuma; - int order; + const char *fname; + AmbDecConf conf; size_t i; switch(device->FmtChans) { case DevFmtMono: layout = "mono"; - channels = mono_chans; - count = COUNTOF(mono_chans); break; case DevFmtStereo: layout = "stereo"; - channels = stereo_chans; - count = COUNTOF(stereo_chans); break; case DevFmtQuad: layout = "quad"; - channels = quad_chans; - count = COUNTOF(quad_chans); break; case DevFmtX51: layout = "surround51"; - channels = surround51_chans; - count = COUNTOF(surround51_chans); break; case DevFmtX51Rear: layout = "surround51rear"; - channels = surround51rear_chans; - count = COUNTOF(surround51rear_chans); break; case DevFmtX61: layout = "surround61"; - channels = surround61_chans; - count = COUNTOF(surround61_chans); break; case DevFmtX71: layout = "surround71"; - channels = surround71_chans; - count = COUNTOF(surround71_chans); break; case DevFmtBFormat3D: break; @@ -412,108 +397,81 @@ static bool LoadChannelSetup(ALCdevice *device) if(!layout) return false; - else + + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", layout, &fname)) + return false; + + ambdec_init(&conf); + if(!ambdec_load(&conf, fname)) { - char name[32] = {0}; - const char *type; - char eol; + ERR("Failed to load layout file %s\n", fname); + goto fail; + } - snprintf(name, sizeof(name), "%s/type", layout); - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type)) - return false; + if(conf.FreqBands != 1) + { + ERR("AmbDec layout file must be single-band (freq_bands = %u)\n", conf.FreqBands); + goto fail; + } - if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2) - { - ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout); - return false; - } + if(!MakeSpeakerMap(device, &conf, speakermap)) + goto fail; - if(strcasecmp(name, "fuma") == 0) - isfuma = 1; - else if(strcasecmp(name, "n3d") == 0) - isfuma = 0; - else - { - ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout); - return false; - } + if(conf.ChanMask > 0x1ff) + ambiscale = THIRD_ORDER_SCALE; + else if(conf.ChanMask > 0xf) + ambiscale = SECOND_ORDER_SCALE; + else if(conf.ChanMask > 0x1) + ambiscale = FIRST_ORDER_SCALE; + else + ambiscale = 0.0f; - if(order == 3) - ambiscale = THIRD_ORDER_SCALE; - else if(order == 2) - ambiscale = SECOND_ORDER_SCALE; - else if(order == 1) - ambiscale = FIRST_ORDER_SCALE; - else if(order == 0) - ambiscale = ZERO_ORDER_SCALE; - else - { - ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout); - return false; - } - } + if(conf.CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf.CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; - for(i = 0;i < count;i++) + for(i = 0;i < conf.NumSpeakers;i++) { - float coeffs[MAX_AMBI_COEFFS] = {0.0f}; - const char *channame; - char chanlayout[32]; - const char *value; - int props = 0; - char eol = 0; - int j; - - chanmap[i].ChanName = channels[i]; - channame = GetLabelFromChannel(channels[i]); - - snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame); - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value)) + ALuint chan = speakermap[i]; + ALuint j, k = 0; + + for(j = 0;j < MAX_AMBI_COEFFS;j++) + chanmap[i].Config[j] = 0.0f; + + chanmap[i].ChanName = device->RealOut.ChannelName[chan]; + for(j = 0;j < 1;j++) { - ERR("Missing channel %s\n", channame); - return false; + if((conf.ChanMask&(1< (order+1)*(order+1)) + for(;j < 9;j++) { - ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1)); - return false; + if((conf.ChanMask&(1<Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, isfuma); + + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, conf.NumSpeakers, + &device->Dry.NumChannels, AL_FALSE); device->Dry.AmbiScale = ambiscale; + + ambdec_deinit(&conf); return true; + +fail: + ambdec_deinit(&conf); + return false; } ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) -- cgit v1.2.3 From 8ff4a5435614c85e43a3514157537dab80ecb3e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Mar 2016 09:07:03 -0700 Subject: Properly handle negative matrix values and fix decoder initialization --- Alc/bformatdec.c | 2 +- Alc/panning.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index d917f803..fff693bc 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -252,7 +252,7 @@ static void apply_row(ALfloat *out, const ALfloat *mtx, ALfloat (*restrict in)[B for(c = 0;c < inchans;c++) { ALfloat gain = mtx[c]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(i = 0;i < todo;i++) out[i] += in[c][i] * gain; diff --git a/Alc/panning.c b/Alc/panning.c index e090461e..c28ca4d6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -623,7 +623,6 @@ ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) if(!MakeSpeakerMap(device, conf, speakermap)) goto ambi_fail; - bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); count = COUNTOF(Ambi3D); chanmap = Ambi3D; @@ -637,6 +636,7 @@ ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) &device->Dry.NumChannels, AL_FALSE); device->Dry.AmbiScale = ambiscale; + bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); return; ambi_fail: -- cgit v1.2.3 From a3863d5834d5d21edf2e2aa9c42a3bdb44c25b51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Mar 2016 01:36:57 -0700 Subject: Add config options to enable the hq ambisonic decoder --- Alc/ALc.c | 13 +++++++- Alc/panning.c | 82 ++++++++++++++++++++++++++++---------------------- OpenAL32/Include/alu.h | 3 +- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f51757e8..ffb20442 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2118,7 +2118,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - aluInitPanning(device, NULL); + if(!device->Hrtf && !device->Uhj_Encoder && + GetConfigValueBool(al_string_get_cstr(device->DeviceName), "ambisonics", "hq-mode", 1)) + { + if(!device->AmbiDecoder) + device->AmbiDecoder = bformatdec_alloc(); + } + else + { + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + } + aluInitPanning(device); /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); diff --git a/Alc/panning.c b/Alc/panning.c index c28ca4d6..d9a1da9d 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -227,6 +227,23 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) } +DECL_CONST static const char *GetChannelLayoutName(enum DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return "mono"; + case DevFmtStereo: return "stereo"; + case DevFmtQuad: return "quad"; + case DevFmtX51: return "surround51"; + case DevFmtX51Rear: return "surround51rear"; + case DevFmtX61: return "surround61"; + case DevFmtX71: return "surround71"; + case DevFmtBFormat3D: + break; + } + return NULL; +} + typedef struct ChannelMap { enum Channel ChanName; ChannelConfig Config; @@ -368,35 +385,8 @@ static bool LoadChannelSetup(ALCdevice *device) AmbDecConf conf; size_t i; - switch(device->FmtChans) - { - case DevFmtMono: - layout = "mono"; - break; - case DevFmtStereo: - layout = "stereo"; - break; - case DevFmtQuad: - layout = "quad"; - break; - case DevFmtX51: - layout = "surround51"; - break; - case DevFmtX51Rear: - layout = "surround51rear"; - break; - case DevFmtX61: - layout = "surround61"; - break; - case DevFmtX71: - layout = "surround71"; - break; - case DevFmtBFormat3D: - break; - } - - if(!layout) - return false; + layout = GetChannelLayoutName(device->FmtChans); + if(!layout) return false; if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", layout, &fname)) return false; @@ -474,7 +464,7 @@ fail: return false; } -ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) +ALvoid aluInitPanning(ALCdevice *device) { /* NOTE: These decoder coefficients are using FuMa channel ordering and * normalization, since that's what was produced by the Ambisonic Decoder @@ -608,20 +598,37 @@ ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; ALuint speakermap[MAX_OUTPUT_CHANNELS]; + const char *fname = ""; + const char *layout; + AmbDecConf conf; + + ambdec_init(&conf); + + layout = GetChannelLayoutName(device->FmtChans); + if(!layout) goto ambi_fail; + + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "ambisonics", layout, &fname)) + goto ambi_fail; + + if(!ambdec_load(&conf, fname)) + { + ERR("Failed to load %s\n", fname); + goto ambi_fail; + } - if(conf->ChanMask > 0xffff) + if(conf.ChanMask > 0xffff) { - ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf->ChanMask); + ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); goto ambi_fail; } - if(conf->ChanMask > 0xf) + if(conf.ChanMask > 0xf) { ERR("Only first-order is supported for HQ decoding (mask 0x%04x, max 0xf)\n", - conf->ChanMask); + conf.ChanMask); goto ambi_fail; } - if(!MakeSpeakerMap(device, conf, speakermap)) + if(!MakeSpeakerMap(device, &conf, speakermap)) goto ambi_fail; count = COUNTOF(Ambi3D); @@ -636,10 +643,13 @@ ALvoid aluInitPanning(ALCdevice *device, const AmbDecConf *conf) &device->Dry.NumChannels, AL_FALSE); device->Dry.AmbiScale = ambiscale; - bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); + TRACE("Enabling %s-band ambisonic decoder\n", (conf.FreqBands==1)?"single":"dual"); + bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); + ambdec_deinit(&conf); return; ambi_fail: + ambdec_deinit(&conf); bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index dfc9284f..08f25204 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -33,7 +33,6 @@ extern "C" { #endif -struct AmbDecConf; struct ALsource; struct ALvoice; struct ALeffectslot; @@ -281,7 +280,7 @@ inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat v void aluInitMixer(void); -ALvoid aluInitPanning(ALCdevice *Device, const struct AmbDecConf *conf); +ALvoid aluInitPanning(ALCdevice *Device); void aluInitEffectPanning(struct ALeffectslot *slot); -- cgit v1.2.3 From 55ff0c143e67ceccd46f3d2ca24e9f6fd4d4884c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Mar 2016 06:49:35 -0700 Subject: Rename the BFormat channels to Aux --- Alc/ALc.c | 8 ++++---- Alc/panning.c | 40 ++++++++++++++++++++-------------------- OpenAL32/Include/alMain.h | 8 ++++---- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ffb20442..f22cb7c1 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1488,10 +1488,10 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) device->RealOut.ChannelName[7] = SideRight; break; case DevFmtBFormat3D: - device->RealOut.ChannelName[0] = BFormatW; - device->RealOut.ChannelName[1] = BFormatX; - device->RealOut.ChannelName[2] = BFormatY; - device->RealOut.ChannelName[3] = BFormatZ; + device->RealOut.ChannelName[0] = Aux0; + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; break; } } diff --git a/Alc/panning.c b/Alc/panning.c index d9a1da9d..16c84b6d 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -216,10 +216,10 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) case LowerBackLeft: return "lower-back-left"; case LowerBackRight: return "lower-back-right"; - case BFormatW: return "bformat-w"; - case BFormatX: return "bformat-x"; - case BFormatY: return "bformat-y"; - case BFormatZ: return "bformat-z"; + case Aux0: return "aux-0"; + case Aux1: return "aux-1"; + case Aux2: return "aux-2"; + case Aux3: return "aux-3"; case InvalidChannel: break; } @@ -517,14 +517,14 @@ ALvoid aluInitPanning(ALCdevice *device) { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, }, BFormat2D[3] = { - { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, }, BFormat3D[4] = { - { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } }, + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; const ChannelMap *chanmap = NULL; ALfloat ambiscale = 1.0f; @@ -592,10 +592,10 @@ ALvoid aluInitPanning(ALCdevice *device) { /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ static const ChannelMap Ambi3D[4] = { - { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } }, + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *fname = ""; @@ -719,13 +719,13 @@ ALvoid aluInitPanning(ALCdevice *device) void aluInitEffectPanning(ALeffectslot *slot) { static const ChannelMap FirstOrderN3D[4] = { - { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } }, + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; static const enum Channel AmbiChannels[MAX_OUTPUT_CHANNELS] = { - BFormatW, BFormatY, BFormatZ, BFormatX, InvalidChannel + Aux0, Aux1, Aux2, Aux3, InvalidChannel }; memset(slot->AmbiCoeffs, 0, sizeof(slot->AmbiCoeffs)); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3ce95801..c71e844f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -326,10 +326,10 @@ enum Channel { LowerBackLeft, LowerBackRight, - BFormatW, - BFormatX, - BFormatY, - BFormatZ, + Aux0, + Aux1, + Aux2, + Aux3, InvalidChannel }; -- cgit v1.2.3 From 606402fff05b115bc8b4728f9444fa46ef7e5e35 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Mar 2016 08:50:13 -0700 Subject: Make sure enough reverb panning gains are defined --- Alc/effects/reverb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index cf31ba62..504e35b7 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -89,9 +89,9 @@ typedef struct ALreverbState { // The gain for each output channel based on 3D panning. // NOTE: With certain output modes, we may be rendering to the dry // buffer and the "real" buffer. The two combined may be using more - // than 8 output channels, so we need some extra for the real output - // too. - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+4]; + // than the max output channels, so we need some extra for the real + // output too. + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2]; } Early; // Decorrelator delay line. @@ -130,7 +130,7 @@ typedef struct ALreverbState { // The gain for each output channel based on 3D panning. // NOTE: Add some extra in case (see note about early pan). - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+4]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2]; } Late; struct { -- cgit v1.2.3 From ce575718ef495c3c146d7a1b443ce556014e057f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Mar 2016 10:10:26 -0700 Subject: Store the effect's output buffer in the effect state --- Alc/ALc.c | 7 ++++++- Alc/ALu.c | 10 +++++----- OpenAL32/Include/alAuxEffectSlot.h | 3 +++ OpenAL32/alAuxEffectSlot.c | 2 ++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f22cb7c1..091a5473 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2170,6 +2170,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALeffectslot *slot = context->EffectSlotMap.array[pos].value; + slot->EffectState->OutBuffer = device->Dry.Buffer; + slot->EffectState->OutChannels = device->Dry.NumChannels; if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); @@ -2217,8 +2219,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->DefaultSlot) { ALeffectslot *slot = device->DefaultSlot; + ALeffectState *state = slot->EffectState; - if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE) + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + if(V(state,deviceUpdate)(device) == AL_FALSE) { V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); diff --git a/Alc/ALu.c b/Alc/ALu.c index 5064a588..55ed84dc 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1417,8 +1417,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i); ALeffectState *state = slot->EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer, - device->Dry.NumChannels); + V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, + state->OutChannels); } ctx = ctx->next; @@ -1428,8 +1428,8 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { const ALeffectslot *slot = device->DefaultSlot; ALeffectState *state = slot->EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer, - device->Dry.NumChannels); + V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, + state->OutChannels); } /* Increment the clock time. Every second's worth of samples is @@ -1503,7 +1503,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(buffer) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; - ALuint OutChannels = device->RealOut.NumChannels;; + ALuint OutChannels = device->RealOut.NumChannels; #define WRITE(T, a, b, c, d) do { \ Write_##T((a), (b), (c), (d)); \ diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 3f677fd1..2c9a83e5 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -15,6 +15,9 @@ struct ALeffectslot; typedef struct ALeffectState { const struct ALeffectStateVtable *vtbl; + + ALfloat (*OutBuffer)[BUFFERSIZE]; + ALuint OutChannels; } ALeffectState; struct ALeffectStateVtable { diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index b0dba25d..c80bab22 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -464,6 +464,8 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e SetMixerFPUMode(&oldMode); ALCdevice_Lock(Device); + State->OutBuffer = Device->Dry.Buffer; + State->OutChannels = Device->Dry.NumChannels; if(V(State,deviceUpdate)(Device) == AL_FALSE) { ALCdevice_Unlock(Device); -- cgit v1.2.3 From 3877545d8c18df7b04771e790e5faf751eb51495 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Mar 2016 14:05:45 -0700 Subject: Add a workaround for a buggy modff --- Alc/effects/reverb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 504e35b7..5ec5f6cf 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -241,6 +241,21 @@ static const ALfloat LATE_LINE_LENGTH[4] = static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; +#if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM) +/* HACK: Workaround for a modff bug in 32-bit Windows, which attempts to write + * a 64-bit double to the 32-bit float parameter. + */ +static inline float hack_modff(float x, float *y) +{ + double di; + double df = modf((double)x, &di); + *y = (float)di; + return (float)df; +} +#define modff hack_modff +#endif + + /************************************** * Device Update * **************************************/ -- cgit v1.2.3 From 0a03596af11570f5dba473c93c67c59d285d7bc2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Mar 2016 14:42:53 -0700 Subject: Simplify setting the matrix coeffs --- Alc/bformatdec.c | 56 ++++++++++++++------------------------------------------ 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index fff693bc..f5a8e8c4 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -183,30 +183,16 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, { ALuint chan = chanmap[i]; ALuint j, k = 0; + ALfloat gain; - for(j = 0;j < 1;j++) + for(j = 0;j < MAX_AMBI_COEFFS;j++) { + if(j == 0) gain = conf->LFOrderGain[0] / ratio; + else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + else if(j == 4) gain = conf->LFOrderGain[2] / ratio; + else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * - conf->LFOrderGain[0] / ratio; - } - for(;j < 4;j++) - { - if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * - conf->LFOrderGain[1] / ratio; - } - for(;j < 9;j++) - { - if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * - conf->LFOrderGain[2] / ratio; - } - for(;j < 16;j++) - { - if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * - conf->LFOrderGain[3] / ratio; + dec->MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * gain; } } } @@ -216,30 +202,16 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, { ALuint chan = chanmap[i]; ALuint j, k = 0; + ALfloat gain; - for(j = 0;j < 1;j++) - { - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - conf->HFOrderGain[0] * ratio; - } - for(;j < 4;j++) - { - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - conf->HFOrderGain[1] * ratio; - } - for(;j < 9;j++) - { - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - conf->HFOrderGain[2] * ratio; - } - for(;j < 16;j++) + for(j = 0;j < MAX_AMBI_COEFFS;j++) { + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 4) gain = conf->HFOrderGain[2] * ratio; + else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - conf->HFOrderGain[3] * ratio; + dec->MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; } } } -- cgit v1.2.3 From 713ac9e6790ac5bb9491a893c9b2ee0a693878b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Mar 2016 17:52:20 -0700 Subject: Add a specific output for first-order sources --- Alc/ALc.c | 20 +++++++++++++++++++- Alc/ALu.c | 4 +++- Alc/bformatdec.c | 8 ++++++++ Alc/bformatdec.h | 1 + Alc/effects/compressor.c | 5 ++++- Alc/effects/equalizer.c | 5 ++++- Alc/effects/modulator.c | 5 ++++- Alc/panning.c | 10 ++++++++++ OpenAL32/Include/alMain.h | 9 +++++++++ 9 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 091a5473..8ca33592 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2133,7 +2133,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); - if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) + if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) + size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); + else if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) @@ -2157,6 +2159,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->RealOut.NumChannels = device->Dry.NumChannels; } + if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) + { + /* Higher-order high quality decoding requires upsampling first-order + * content, so make sure to mix it separately. + */ + device->FOAOut.Buffer = device->RealOut.Buffer + device->RealOut.NumChannels; + device->FOAOut.NumChannels = 4; + } + else + { + device->FOAOut.Buffer = device->Dry.Buffer; + device->FOAOut.NumChannels = device->Dry.NumChannels; + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); + } + SetMixerFPUMode(&oldMode); V0(device->Backend,lock)(); context = ATOMIC_LOAD(&device->ContextList); diff --git a/Alc/ALu.c b/Alc/ALu.c index 55ed84dc..b5b7de9c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -513,8 +513,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale ); + voice->Direct.OutBuffer = Device->FOAOut.Buffer; + voice->Direct.OutChannels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, matrix.m[c], + ComputeFirstOrderGains(Device->FOAOut.AmbiCoeffs, Device->FOAOut.NumChannels, matrix.m[c], DryGain, voice->Direct.Gains[c].Target); /* Rebuild the matrix, without the second- or third-order output diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index f5a8e8c4..37be67e4 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -142,6 +142,14 @@ void bformatdec_free(BFormatDec *dec) } } +int bformatdec_getOrder(const struct BFormatDec *dec) +{ + if(dec->NumChannels > 9) return 3; + if(dec->NumChannels > 4) return 2; + if(dec->NumChannels > 1) return 1; + return 0; +} + void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]) { const ALfloat *coeff_scale = UnitScale; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index a322f41d..5f17d711 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -8,6 +8,7 @@ struct BFormatDec; struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); +int bformatdec_getOrder(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]); void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index ae859793..6358f672 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -70,8 +70,11 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, scale ); + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, + ComputeFirstOrderGains(device->FOAOut.AmbiCoeffs, device->FOAOut.NumChannels, matrix.m[i], slot->Gain, state->Gain[i]); } diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 479a8536..ffc9830f 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -110,8 +110,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * 0.0f, 0.0f, gain, 0.0f, 0.0f, 0.0f, 0.0f, gain ); + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, + ComputeFirstOrderGains(device->FOAOut.AmbiCoeffs, device->FOAOut.NumChannels, matrix.m[i], slot->Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 4183b908..c283d4b0 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -129,8 +129,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, scale ); + + STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + ComputeFirstOrderGains(Device->FOAOut.AmbiCoeffs, Device->FOAOut.NumChannels, matrix.m[i], Slot->Gain, state->Gain[i]); } diff --git a/Alc/panning.c b/Alc/panning.c index 16c84b6d..401d29d6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -646,6 +646,16 @@ ALvoid aluInitPanning(ALCdevice *device) TRACE("Enabling %s-band ambisonic decoder\n", (conf.FreqBands==1)?"single":"dual"); bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); ambdec_deinit(&conf); + + if(bformatdec_getOrder(device->AmbiDecoder) >= 2) + { + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + device->FOAOut.AmbiCoeffs[0][0] = 1.0f; + device->FOAOut.AmbiCoeffs[1][1] = 1.0f; + device->FOAOut.AmbiCoeffs[2][2] = 1.0f; + device->FOAOut.AmbiCoeffs[3][3] = 1.0f; + } + return; ambi_fail: diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c71e844f..b870059b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -507,6 +507,15 @@ struct ALCdevice_struct ALuint NumChannels; } Dry; + /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ + struct { + /* Ambisonic coefficients for mixing. */ + ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint NumChannels; + } FOAOut; + /* Virtual output, to be post-processed to the real output. */ struct { ALfloat (*Buffer)[BUFFERSIZE]; -- cgit v1.2.3 From 0dc35784dbaa37857e988582f41482ef9b59d8a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Mar 2016 10:39:14 -0700 Subject: Allow second-order HQ decoding Could really do with some optimizations to the mixing gain calculations. For ambisonic targets, the coefficients will only have 1 non-0 entry for each output, so the double loop in unnecessarily wasteful. Similarly, most uses won't need a full height encoding either, so a horizontal-only or mixed-order target could reduce the number of channels. --- Alc/panning.c | 30 +++++++++++++++++++++--------- OpenAL32/Include/alMain.h | 7 ++++++- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 401d29d6..031b518d 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -220,6 +220,11 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) case Aux1: return "aux-1"; case Aux2: return "aux-2"; case Aux3: return "aux-3"; + case Aux4: return "aux-4"; + case Aux5: return "aux-5"; + case Aux6: return "aux-6"; + case Aux7: return "aux-7"; + case Aux8: return "aux-8"; case InvalidChannel: break; } @@ -591,11 +596,16 @@ ALvoid aluInitPanning(ALCdevice *device) if(device->AmbiDecoder) { /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ - static const ChannelMap Ambi3D[4] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, + static const ChannelMap Ambi3D[9] = { + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, }; ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *fname = ""; @@ -621,9 +631,9 @@ ALvoid aluInitPanning(ALCdevice *device) ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); goto ambi_fail; } - if(conf.ChanMask > 0xf) + if(conf.ChanMask > 0x1ff) { - ERR("Only first-order is supported for HQ decoding (mask 0x%04x, max 0xf)\n", + ERR("Only first- and second-order is supported for HQ decoding (mask 0x%04x, max 0x1ff)\n", conf.ChanMask); goto ambi_fail; } @@ -631,9 +641,11 @@ ALvoid aluInitPanning(ALCdevice *device) if(!MakeSpeakerMap(device, &conf, speakermap)) goto ambi_fail; - count = COUNTOF(Ambi3D); + if(conf.ChanMask > 0xf) + ERR("Second-order HQ decoding does not currently handle first-order sources\n"); + count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4; chanmap = Ambi3D; - ambiscale = FIRST_ORDER_SCALE; + ambiscale = 1.0f; for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b870059b..71620c3f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -330,6 +330,11 @@ enum Channel { Aux1, Aux2, Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, InvalidChannel }; @@ -362,7 +367,7 @@ enum DevFmtChannels { DevFmtChannelsDefault = DevFmtStereo }; -#define MAX_OUTPUT_CHANNELS (8) +#define MAX_OUTPUT_CHANNELS (9) ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST; ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST; -- cgit v1.2.3 From 147274f165b5cf8f1f004567c777e0e274c9e228 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Mar 2016 12:53:36 -0700 Subject: Up-sample first-order content when using a higher order HQ decoder --- Alc/ALu.c | 8 ++++++ Alc/bformatdec.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/bformatdec.h | 5 ++++ Alc/panning.c | 2 -- 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index b5b7de9c..206aceda 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1367,6 +1367,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); for(c = 0;c < device->RealOut.NumChannels;c++) memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Dry.Buffer != device->FOAOut.Buffer) + for(c = 0;c < device->FOAOut.NumChannels;c++) + memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); V0(device->Backend,lock)(); @@ -1467,6 +1470,11 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } else if(device->AmbiDecoder) { + if(device->VirtOut.Buffer != device->FOAOut.Buffer) + bformatdec_upSample(device->AmbiDecoder, + device->VirtOut.Buffer, device->FOAOut.Buffer, + device->FOAOut.NumChannels, SamplesToDo + ); bformatdec_process(device->AmbiDecoder, device->RealOut.Buffer, device->RealOut.NumChannels, device->VirtOut.Buffer, SamplesToDo diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 37be67e4..ab148d1b 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -5,6 +5,8 @@ #include "ambdec.h" #include "alu.h" +#include "threads.h" + typedef struct BandSplitter { ALfloat coeff; @@ -105,6 +107,46 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; +static const ALfloat SquareMatrixHF[4][MAX_AMBI_COEFFS] = { + { 0.353553f, 0.204094f, 0.0f, 0.204094f }, + { 0.353553f, -0.204094f, 0.0f, 0.204094f }, + { 0.353553f, 0.204094f, 0.0f, -0.204094f }, + { 0.353553f, -0.204094f, 0.0f, -0.204094f }, +}; +static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS]; + +static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = { + { 0.25f, 0.14425f, 0.14425f, 0.14425f }, + { 0.25f, -0.14425f, 0.14425f, 0.14425f }, + { 0.25f, 0.14425f, 0.14425f, -0.14425f }, + { 0.25f, -0.14425f, 0.14425f, -0.14425f }, + { 0.25f, 0.14425f, -0.14425f, 0.14425f }, + { 0.25f, -0.14425f, -0.14425f, 0.14425f }, + { 0.25f, 0.14425f, -0.14425f, -0.14425f }, + { 0.25f, -0.14425f, -0.14425f, -0.14425f }, +}; +static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; + +static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT; + +static void init_encoder(void) +{ + CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[0]); + CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[1]); + CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[2]); + CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[3]); + CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[4]); + CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[5]); + CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[6]); + CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[7]); + + CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, SquareEncoder[0]); + CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, SquareEncoder[1]); + CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, SquareEncoder[2]); + CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, SquareEncoder[3]); +} + + /* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with * single-band decoding */ @@ -119,12 +161,19 @@ typedef struct BFormatDec { ALfloat (*SamplesHF)[BUFFERSIZE]; ALfloat (*SamplesLF)[BUFFERSIZE]; + struct { + const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS]; + const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; + ALuint NumChannels; + } UpSampler; + ALuint NumChannels; ALboolean DualBand; } BFormatDec; BFormatDec *bformatdec_alloc() { + alcall_once(&encoder_inited, init_encoder); return al_calloc(16, sizeof(BFormatDec)); } @@ -172,6 +221,19 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(conf->CoeffScale == ADS_FuMa) coeff_scale = FuMa2N3DScale; + if((conf->ChanMask & ~0x831b)) + { + dec->UpSampler.MatrixHF = CubeMatrixHF; + dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder; + dec->UpSampler.NumChannels = 8; + } + else + { + dec->UpSampler.MatrixHF = SquareMatrixHF; + dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder; + dec->UpSampler.NumChannels = 4; + } + if(conf->FreqBands == 1) { dec->DualBand = AL_FALSE; @@ -264,3 +326,29 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU dec->NumChannels, SamplesToDo); } } + + +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) +{ + ALuint i, j, k; + + /* This up-sampler is very simplistic. It essentially decodes the first- + * order content to a square channel array (or cube if height is desired), + * then encodes those points onto the higher order soundfield. + */ + for(k = 0;k < dec->UpSampler.NumChannels;k++) + { + memset(dec->Samples[0], 0, SamplesToDo*sizeof(ALfloat)); + apply_row(dec->Samples[0], dec->UpSampler.MatrixHF[k], InSamples, + InChannels, SamplesToDo); + + for(j = 0;j < dec->NumChannels;j++) + { + ALfloat gain = dec->UpSampler.Encoder[k][j]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(i = 0;i < SamplesToDo;i++) + OutBuffer[j][i] += dec->Samples[0][i] * gain; + } + } +} diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 5f17d711..623e7b09 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -10,6 +10,11 @@ struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]); + +/* Decodes the ambisonic input to the given output channels. */ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +/* Up-samples a first-order input to the decoder's configuration. */ +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); + #endif /* BFORMATDEC_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 031b518d..9c504b04 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -641,8 +641,6 @@ ALvoid aluInitPanning(ALCdevice *device) if(!MakeSpeakerMap(device, &conf, speakermap)) goto ambi_fail; - if(conf.ChanMask > 0xf) - ERR("Second-order HQ decoding does not currently handle first-order sources\n"); count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4; chanmap = Ambi3D; ambiscale = 1.0f; -- cgit v1.2.3 From 2847590d454f4fa51ec2561d47d2872bf01997d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Mar 2016 15:11:33 -0700 Subject: Simplify setting a custom channel map configuration --- Alc/panning.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 9c504b04..8d66df04 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -430,30 +430,20 @@ static bool LoadChannelSetup(ALCdevice *device) { ALuint chan = speakermap[i]; ALuint j, k = 0; + ALfloat gain; for(j = 0;j < MAX_AMBI_COEFFS;j++) chanmap[i].Config[j] = 0.0f; chanmap[i].ChanName = device->RealOut.ChannelName[chan]; - for(j = 0;j < 1;j++) - { - if((conf.ChanMask&(1< Date: Wed, 23 Mar 2016 16:00:07 -0700 Subject: Trace the HQ decoder order --- Alc/panning.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 8d66df04..2bbdbaed 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -643,7 +643,10 @@ ALvoid aluInitPanning(ALCdevice *device) &device->Dry.NumChannels, AL_FALSE); device->Dry.AmbiScale = ambiscale; - TRACE("Enabling %s-band ambisonic decoder\n", (conf.FreqBands==1)?"single":"dual"); + TRACE("Enabling %s-band %s-order ambisonic decoder\n", + (conf.FreqBands == 1) ? "single" : "dual", + (conf.ChanMask > 0x1ff) ? "third" : (conf.ChanMask > 0xf) ? "second" : "first" + ); bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); ambdec_deinit(&conf); -- cgit v1.2.3 From b0acfa17634281bf95f423d903aac5dfc23f3697 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Mar 2016 11:11:17 -0700 Subject: Add a cast and a couple float type fixes --- Alc/ALu.c | 4 ++-- Alc/ambdec.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 206aceda..cdb75e6a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -678,7 +678,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); - coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5; + coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f; voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain; voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain; for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) @@ -1179,7 +1179,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte if(Device->Render_Mode == StereoPair) { /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ - coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5; + coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5f; voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain; voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain; for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) diff --git a/Alc/ambdec.c b/Alc/ambdec.c index 6920d705..29bd4afa 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -105,7 +105,7 @@ static char *read_float(ALfloat *num, const char *line) #ifdef HAVE_STRTOF *num = strtof(line, &end); #else - *num = strtod(line, &end); + *num = (ALfloat)strtod(line, &end); #endif if(end && *end != '\0') end = lstrip(end); -- cgit v1.2.3 From 19b130c45d0760f44b453cec6be33ae5cef48851 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Mar 2016 13:55:23 -0700 Subject: Use the "decoder" config section instead of "ambisonics" --- Alc/ALc.c | 2 +- Alc/panning.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8ca33592..7c3afa0c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2119,7 +2119,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(!device->Hrtf && !device->Uhj_Encoder && - GetConfigValueBool(al_string_get_cstr(device->DeviceName), "ambisonics", "hq-mode", 1)) + GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 1)) { if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); diff --git a/Alc/panning.c b/Alc/panning.c index 2bbdbaed..6f6db3df 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -607,7 +607,7 @@ ALvoid aluInitPanning(ALCdevice *device) layout = GetChannelLayoutName(device->FmtChans); if(!layout) goto ambi_fail; - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "ambisonics", layout, &fname)) + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "decoder", layout, &fname)) goto ambi_fail; if(!ambdec_load(&conf, fname)) -- cgit v1.2.3 From 31489861847dcb15a2f21ffb70d98f9da6051c8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Mar 2016 14:40:44 -0700 Subject: Implement AL_EXT_STEREO_ANGLES support --- Alc/ALc.c | 10 ++++++---- Alc/ALu.c | 11 ++++++++--- OpenAL32/Include/alSource.h | 5 +++++ OpenAL32/alSource.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7c3afa0c..e6c37546 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -523,6 +523,8 @@ static const ALCenums enumeration[] = { DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), + DECL(AL_STEREO_ANGLES), + DECL(AL_UNUSED), DECL(AL_PENDING), DECL(AL_PROCESSED), @@ -712,10 +714,10 @@ static const ALchar alExtList[] = "AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE " "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS " "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " - "AL_EXT_source_distance_model AL_LOKI_quadriphonic AL_SOFT_block_alignment " - "AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels AL_SOFT_loop_points AL_SOFT_MSADPCM " - "AL_SOFT_source_latency AL_SOFT_source_length"; + "AL_EXT_source_distance_model AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic " + "AL_SOFT_block_alignment AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data " + "AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points " + "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/Alc/ALu.c b/Alc/ALu.c index cdb75e6a..b5791f53 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -303,9 +303,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } - }, StereoMap[2] = { - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } }, RearMap[2] = { { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } @@ -352,6 +349,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALuint NumSends, Frequency; ALboolean Relative; const struct ChanMap *chans = NULL; + struct ChanMap StereoMap[2] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } + }; ALuint num_channels = 0; ALboolean DirectChannels; ALboolean isbformat = AL_FALSE; @@ -373,6 +374,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A Relative = ALSource->HeadRelative; DirectChannels = ALSource->DirectChannels; + /* Convert counter-clockwise to clockwise. */ + StereoMap[0].angle = -ALSource->StereoPan[0]; + StereoMap[1].angle = -ALSource->StereoPan[1]; + voice->Direct.OutBuffer = Device->Dry.Buffer; voice->Direct.OutChannels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index bf589e8d..b7c08fcd 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -76,6 +76,11 @@ typedef struct ALsource { volatile ALfloat RoomRolloffFactor; volatile ALfloat DopplerFactor; + /* NOTE: Stereo pan angles are specified in radians, counter-clockwise + * rather than clockwise. + */ + volatile ALfloat StereoPan[2]; + volatile ALfloat Radius; /** diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 250c9d1e..d7b68185 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -104,6 +104,9 @@ typedef enum SourceProp { srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, + /* AL_EXT_STEREO_ANGLES */ + srcAngles = AL_STEREO_ANGLES, + /* AL_EXT_BFORMAT */ srcOrientation = AL_ORIENTATION, } SourceProp; @@ -157,6 +160,7 @@ static ALint FloatValsByProp(ALenum prop) case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_RW_OFFSETS_SOFT: + case AL_STEREO_ANGLES: return 2; case AL_POSITION: @@ -221,6 +225,7 @@ static ALint DoubleValsByProp(ALenum prop) case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_RW_OFFSETS_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_STEREO_ANGLES: return 2; case AL_POSITION: @@ -299,6 +304,8 @@ static ALint IntValsByProp(ALenum prop) break; /* i64 only */ case AL_SEC_OFFSET_LATENCY_SOFT: break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ } return 0; } @@ -359,6 +366,8 @@ static ALint Int64ValsByProp(ALenum prop) case AL_SEC_OFFSET_LATENCY_SOFT: break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ } return 0; } @@ -507,6 +516,17 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; + case AL_STEREO_ANGLES: + CHECKVAL(isfinite(values[0]) && isfinite(values[1])); + + LockContext(Context); + Source->StereoPan[0] = values[0]; + Source->StereoPan[1] = values[1]; + UnlockContext(Context); + ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + return AL_TRUE; + + case AL_POSITION: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); @@ -830,6 +850,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_STEREO_ANGLES: break; } @@ -931,6 +952,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp return SetSourcefv(Source, Context, (int)prop, fvals); case AL_SEC_OFFSET_LATENCY_SOFT: + case AL_STEREO_ANGLES: break; } @@ -1054,6 +1076,13 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p UnlockContext(Context); return AL_TRUE; + case AL_STEREO_ANGLES: + LockContext(Context); + values[0] = Source->StereoPan[0]; + values[1] = Source->StereoPan[1]; + UnlockContext(Context); + return AL_TRUE; + case AL_POSITION: LockContext(Context); values[0] = Source->Position.v[0]; @@ -1325,6 +1354,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p break; /* i64 only */ case AL_SEC_OFFSET_LATENCY_SOFT: break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ case AL_DIRECT_FILTER: case AL_AUXILIARY_SEND_FILTER: @@ -1446,6 +1477,8 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SEC_OFFSET_LATENCY_SOFT: break; /* Double only */ + case AL_STEREO_ANGLES: + break; /* Float/double only */ } ERR("Unexpected property: 0x%04x\n", prop); @@ -2530,6 +2563,9 @@ static ALvoid InitSourceParams(ALsource *Source) Source->DopplerFactor = 1.0f; Source->DirectChannels = AL_FALSE; + Source->StereoPan[0] = DEG2RAD( 30.0f); + Source->StereoPan[1] = DEG2RAD(-30.0f); + Source->Radius = 0.0f; Source->DistanceModel = DefaultDistanceModel; -- cgit v1.2.3 From 05dace65257ed8828a2e3a5cc3add0016b1ac72e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Mar 2016 14:47:30 -0700 Subject: Mix Dedicated effects to the real output if possible --- Alc/effects/dedicated.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 447e6b95..893f3abc 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -57,22 +57,37 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; - if((idx=GetChannelIdxByName(device->Dry, LFE)) != -1) + if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) + { state->gains[idx] = Gain; + STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + } } else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) { int idx; /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - if((idx=GetChannelIdxByName(device->Dry, FrontCenter)) != -1) + if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1) + { state->gains[idx] = Gain; + STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + } else { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); - ComputePanningGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, - coeffs, Gain, state->gains); + if((idx=GetChannelIdxByName(device->Dry, FrontCenter)) != -1) + state->gains[idx] = Gain; + else + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); + ComputePanningGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, + coeffs, Gain, state->gains); + } + STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; } } } -- cgit v1.2.3 From e23da7a1dea9997f61d23af50ed915ebee98f2e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Mar 2016 19:57:25 -0700 Subject: Skip height-related ambisonic channels for 2D rendering --- Alc/bformatdec.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++---------- Alc/panning.c | 18 +++++++++-- 2 files changed, 94 insertions(+), 19 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index ab148d1b..3a07ac36 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -131,6 +131,8 @@ static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT; static void init_encoder(void) { + ALuint i, j; + CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[0]); CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[1]); CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[2]); @@ -144,6 +146,18 @@ static void init_encoder(void) CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, SquareEncoder[1]); CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, SquareEncoder[2]); CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, SquareEncoder[3]); + + for(i = 0;i < 4;i++) + { + /* Remove the skipped height-related coefficients for 2D rendering. */ + SquareEncoder[i][2] = SquareEncoder[i][3]; + SquareEncoder[i][3] = SquareEncoder[i][4]; + SquareEncoder[i][4] = SquareEncoder[i][8]; + SquareEncoder[i][5] = SquareEncoder[i][9]; + SquareEncoder[i][6] = SquareEncoder[i][15]; + for(j = 7;j < MAX_AMBI_COEFFS;j++) + SquareEncoder[i][j] = 0.0f; + } } @@ -169,6 +183,7 @@ typedef struct BFormatDec { ALuint NumChannels; ALboolean DualBand; + ALboolean Periphonic; } BFormatDec; BFormatDec *bformatdec_alloc() @@ -193,14 +208,26 @@ void bformatdec_free(BFormatDec *dec) int bformatdec_getOrder(const struct BFormatDec *dec) { - if(dec->NumChannels > 9) return 3; - if(dec->NumChannels > 4) return 2; - if(dec->NumChannels > 1) return 1; + if(dec->Periphonic) + { + if(dec->NumChannels > 9) return 3; + if(dec->NumChannels > 4) return 2; + if(dec->NumChannels > 1) return 1; + } + else + { + if(dec->NumChannels > 5) return 3; + if(dec->NumChannels > 3) return 2; + if(dec->NumChannels > 1) return 1; + } return 0; } void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]) { + static const ALuint map2DTo3D[7] = { + 0, 1, 3, 4, 8, 9, 15 + }; const ALfloat *coeff_scale = UnitScale; ALfloat ratio; ALuint i; @@ -226,12 +253,14 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, dec->UpSampler.MatrixHF = CubeMatrixHF; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder; dec->UpSampler.NumChannels = 8; + dec->Periphonic = AL_TRUE; } else { dec->UpSampler.MatrixHF = SquareMatrixHF; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder; dec->UpSampler.NumChannels = 4; + dec->Periphonic = AL_FALSE; } if(conf->FreqBands == 1) @@ -255,14 +284,30 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint j, k = 0; ALfloat gain; - for(j = 0;j < MAX_AMBI_COEFFS;j++) + if(!dec->Periphonic) { - if(j == 0) gain = conf->LFOrderGain[0] / ratio; - else if(j == 1) gain = conf->LFOrderGain[1] / ratio; - else if(j == 4) gain = conf->LFOrderGain[2] / ratio; - else if(j == 9) gain = conf->LFOrderGain[3] / ratio; - if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * gain; + for(j = 0;j < 7;j++) + { + ALuint l = map2DTo3D[j]; + if(j == 0) gain = conf->LFOrderGain[0] / ratio; + else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + else if(j == 3) gain = conf->LFOrderGain[2] / ratio; + else if(j == 5) gain = conf->LFOrderGain[3] / ratio; + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[l] * gain; + } + } + else + { + for(j = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->LFOrderGain[0] / ratio; + else if(j == 1) gain = conf->LFOrderGain[1] / ratio; + else if(j == 4) gain = conf->LFOrderGain[2] / ratio; + else if(j == 9) gain = conf->LFOrderGain[3] / ratio; + if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * gain; + } } } } @@ -274,14 +319,30 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint j, k = 0; ALfloat gain; - for(j = 0;j < MAX_AMBI_COEFFS;j++) + if(!dec->Periphonic) + { + for(j = 0;j < 7;j++) + { + ALuint l = map2DTo3D[j]; + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 3) gain = conf->HFOrderGain[2] * ratio; + else if(j == 5) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain; + } + } + else { - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 4) gain = conf->HFOrderGain[2] * ratio; - else if(j == 9) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; + for(j = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 4) gain = conf->HFOrderGain[2] * ratio; + else if(j == 9) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; + } } } } diff --git a/Alc/panning.c b/Alc/panning.c index 6f6db3df..676896d8 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -596,6 +596,12 @@ ALvoid aluInitPanning(ALCdevice *device) { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, + }, Ambi2D[5] = { + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, }; ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *fname = ""; @@ -631,8 +637,16 @@ ALvoid aluInitPanning(ALCdevice *device) if(!MakeSpeakerMap(device, &conf, speakermap)) goto ambi_fail; - count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4; - chanmap = Ambi3D; + if((conf.ChanMask & ~0x831b)) + { + count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4; + chanmap = Ambi3D; + } + else + { + count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi2D) : 3; + chanmap = Ambi2D; + } ambiscale = 1.0f; for(i = 0;i < count;i++) -- cgit v1.2.3 From e0466766d7f9e3017c3bb8fc39a132ee05a357d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Mar 2016 23:25:13 -0700 Subject: Include any first-order scaling in the FOAOut coefficients --- Alc/ALc.c | 2 -- Alc/ALu.c | 14 ++------------ Alc/effects/compressor.c | 10 ++++------ Alc/effects/equalizer.c | 7 +++---- Alc/effects/modulator.c | 11 +++++------ Alc/panning.c | 47 ++++++++++++++++++++++++++++++++--------------- OpenAL32/Include/alMain.h | 2 -- 7 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e6c37546..6389270c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2173,8 +2173,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->FOAOut.Buffer = device->Dry.Buffer; device->FOAOut.NumChannels = device->Dry.NumChannels; - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); } SetMixerFPUMode(&oldMode); diff --git a/Alc/ALu.c b/Alc/ALu.c index b5791f53..c83efce8 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -507,10 +507,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A aluCrossproduct(N, V, U); aluNormalize(U); - /* Build a rotate + conversion matrix (B-Format -> N3D), and include - * scaling for first-order content on second- or third-order output. - */ - scale = Device->Dry.AmbiScale * 1.732050808f; + /* Build a rotate + conversion matrix (B-Format -> N3D). */ + scale = 1.732050808f; aluMatrixfSet(&matrix, 1.414213562f, 0.0f, 0.0f, 0.0f, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, @@ -524,14 +522,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ComputeFirstOrderGains(Device->FOAOut.AmbiCoeffs, Device->FOAOut.NumChannels, matrix.m[c], DryGain, voice->Direct.Gains[c].Target); - /* Rebuild the matrix, without the second- or third-order output - * scaling (effects take first-order content, and will do the scaling - * themselves when mixing to the output). - */ - scale = 1.732050808f; - aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale); - aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale); - aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale); for(i = 0;i < NumSends;i++) { if(!SendSlots[i]) diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 6358f672..4e1d55f1 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -58,17 +58,15 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot) { aluMatrixf matrix; - ALfloat scale; ALuint i; state->Enabled = slot->EffectProps.Compressor.OnOff; - scale = device->Dry.AmbiScale; aluMatrixfSet(&matrix, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, scale, 0.0f, 0.0f, - 0.0f, 0.0f, scale, 0.0f, - 0.0f, 0.0f, 0.0f, scale + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index ffc9830f..f3383bd2 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -103,12 +103,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * aluMatrixf matrix; ALuint i; - gain = device->Dry.AmbiScale; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, gain, 0.0f, 0.0f, - 0.0f, 0.0f, gain, 0.0f, - 0.0f, 0.0f, 0.0f, gain + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index c283d4b0..03e0d458 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -93,8 +93,8 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot) { - ALfloat scale, cw, a; aluMatrixf matrix; + ALfloat cw, a; ALuint i; if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) @@ -122,12 +122,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter[i].process = ALfilterState_processC; } - scale = Device->Dry.AmbiScale; aluMatrixfSet(&matrix, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, scale, 0.0f, 0.0f, - 0.0f, 0.0f, scale, 0.0f, - 0.0f, 0.0f, 0.0f, scale + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; diff --git a/Alc/panning.c b/Alc/panning.c index 676896d8..7fb62c5b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -388,7 +388,7 @@ static bool LoadChannelSetup(ALCdevice *device) ALfloat ambiscale = 1.0f; const char *fname; AmbDecConf conf; - size_t i; + ALuint i, j; layout = GetChannelLayoutName(device->FmtChans); if(!layout) return false; @@ -429,8 +429,8 @@ static bool LoadChannelSetup(ALCdevice *device) for(i = 0;i < conf.NumSpeakers;i++) { ALuint chan = speakermap[i]; - ALuint j, k = 0; ALfloat gain; + ALuint k = 0; for(j = 0;j < MAX_AMBI_COEFFS;j++) chanmap[i].Config[j] = 0.0f; @@ -449,7 +449,14 @@ static bool LoadChannelSetup(ALCdevice *device) SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, conf.NumSpeakers, &device->Dry.NumChannels, AL_FALSE); - device->Dry.AmbiScale = ambiscale; + + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; + for(j = 1;j < 4;j++) + device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + } ambdec_deinit(&conf); return true; @@ -522,11 +529,10 @@ ALvoid aluInitPanning(ALCdevice *device) { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; const ChannelMap *chanmap = NULL; - ALfloat ambiscale = 1.0f; + ALfloat ambiscale; size_t count = 0; - ALuint i; + ALuint i, j; - device->Dry.AmbiScale = 1.0f; memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); device->Dry.NumChannels = 0; @@ -549,7 +555,6 @@ ALvoid aluInitPanning(ALCdevice *device) count = COUNTOF(Cube8Cfg); chanmap = Cube8Cfg; - ambiscale = FIRST_ORDER_SCALE; for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; @@ -557,7 +562,9 @@ ALvoid aluInitPanning(ALCdevice *device) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); - device->Dry.AmbiScale = ambiscale; + + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); for(i = 0;i < device->Dry.NumChannels;i++) { @@ -571,7 +578,6 @@ ALvoid aluInitPanning(ALCdevice *device) { count = COUNTOF(BFormat2D); chanmap = BFormat2D; - ambiscale = FIRST_ORDER_SCALE; for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; @@ -579,7 +585,9 @@ ALvoid aluInitPanning(ALCdevice *device) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); - device->Dry.AmbiScale = ambiscale; + + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); return; } @@ -647,7 +655,6 @@ ALvoid aluInitPanning(ALCdevice *device) count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi2D) : 3; chanmap = Ambi2D; } - ambiscale = 1.0f; for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; @@ -655,7 +662,6 @@ ALvoid aluInitPanning(ALCdevice *device) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_FALSE); - device->Dry.AmbiScale = ambiscale; TRACE("Enabling %s-band %s-order ambisonic decoder\n", (conf.FreqBands == 1) ? "single" : "dual", @@ -664,7 +670,10 @@ ALvoid aluInitPanning(ALCdevice *device) bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); ambdec_deinit(&conf); - if(bformatdec_getOrder(device->AmbiDecoder) >= 2) + if(bformatdec_getOrder(device->AmbiDecoder) < 2) + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); + else { memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); device->FOAOut.AmbiCoeffs[0][0] = 1.0f; @@ -687,6 +696,7 @@ ALvoid aluInitPanning(ALCdevice *device) if(LoadChannelSetup(device)) return; + ambiscale = 1.0f; switch(device->FmtChans) { case DevFmtMono: @@ -734,13 +744,20 @@ ALvoid aluInitPanning(ALCdevice *device) case DevFmtBFormat3D: count = COUNTOF(BFormat3D); chanmap = BFormat3D; - ambiscale = 1.0f; + ambiscale = FIRST_ORDER_SCALE; break; } SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); - device->Dry.AmbiScale = ambiscale; + + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; + for(j = 1;j < 4;j++) + device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + } } void aluInitEffectPanning(ALeffectslot *slot) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 71620c3f..4c737f02 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -504,8 +504,6 @@ struct ALCdevice_struct enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; /* Ambisonic coefficients for mixing to the dry buffer. */ ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; - /* Scale for first-order XYZ inputs using AmbiCoeffs. */ - ALfloat AmbiScale; /* Dry buffer will be aliased by the virtual or real output. */ ALfloat (*Buffer)[BUFFERSIZE]; -- cgit v1.2.3 From 7f4bd13f60836da8c112cef6badf5a5fe464d51f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 01:50:19 -0700 Subject: Allow up to third-order for horizontal-only rendering --- Alc/panning.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 7fb62c5b..1ac79449 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -595,21 +595,30 @@ ALvoid aluInitPanning(ALCdevice *device) { /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ static const ChannelMap Ambi3D[9] = { + /* Zeroth order */ { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* First order */ { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Second order */ { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f } }, { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, - }, Ambi2D[5] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, + }, Ambi2D[7] = { + /* Zeroth order */ + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* First order */ + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Second order */ + { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Third order */ + { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, }; ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *fname = ""; @@ -635,24 +644,24 @@ ALvoid aluInitPanning(ALCdevice *device) ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); goto ambi_fail; } - if(conf.ChanMask > 0x1ff) - { - ERR("Only first- and second-order is supported for HQ decoding (mask 0x%04x, max 0x1ff)\n", - conf.ChanMask); - goto ambi_fail; - } if(!MakeSpeakerMap(device, &conf, speakermap)) goto ambi_fail; if((conf.ChanMask & ~0x831b)) { - count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi3D) : 4; + if(conf.ChanMask > 0x1ff) + { + ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", + conf.ChanMask); + goto ambi_fail; + } + count = (conf.ChanMask > 0xf) ? 9 : 4; chanmap = Ambi3D; } else { - count = (conf.ChanMask > 0xf) ? COUNTOF(Ambi2D) : 3; + count = (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? 7 : 5 : 3; chanmap = Ambi2D; } @@ -663,9 +672,10 @@ ALvoid aluInitPanning(ALCdevice *device) SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_FALSE); - TRACE("Enabling %s-band %s-order ambisonic decoder\n", + TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf.FreqBands == 1) ? "single" : "dual", - (conf.ChanMask > 0x1ff) ? "third" : (conf.ChanMask > 0xf) ? "second" : "first" + (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? "third" : "second" : "first", + (conf.ChanMask & ~0x831b) ? " periphonic" : "" ); bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); ambdec_deinit(&conf); -- cgit v1.2.3 From 67db77452fcff2db20294c2e062ffb3684a0b710 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 17:33:49 -0700 Subject: Add distance compensation to the HQ decoder This only compensates for timing and gain differences caused by differences in the physical speaker distances. It's not near-field compensation. This also relies on having proper distance values defined in the ambdec definition file. --- Alc/bformatdec.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 3a07ac36..7c202228 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -161,6 +161,8 @@ static void init_encoder(void) } +#define MAX_DELAY_LENGTH 128 + /* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with * single-band decoding */ @@ -181,6 +183,14 @@ typedef struct BFormatDec { ALuint NumChannels; } UpSampler; + struct { + alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; + ALfloat Gain; + ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ + } Delay[MAX_OUTPUT_CHANNELS]; + + ALfloat ChannelMix[BUFFERSIZE]; + ALuint NumChannels; ALboolean DualBand; ALboolean Periphonic; @@ -229,7 +239,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; - ALfloat ratio; + ALfloat maxdist, ratio; ALuint i; al_free(dec->Samples); @@ -345,6 +355,45 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, } } } + + + maxdist = 0.0f; + for(i = 0;i < conf->NumSpeakers;i++) + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + + memset(dec->Delay, 0, sizeof(dec->Delay)); + if(maxdist > 0.0f) + { + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = chanmap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + (ALfloat)srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)); + dec->Delay[chan].Gain = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan, + al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, + dec->Delay[chan].Gain + ); + } + } + else + { + for(i = 0;i < conf->NumSpeakers;i++) + dec->Delay[chanmap[i]].Gain = 1.0f; + } } @@ -374,17 +423,71 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU for(chan = 0;chan < OutChannels;chan++) { - apply_row(OutBuffer[chan], dec->MatrixHF[chan], dec->SamplesHF, + memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + apply_row(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF, dec->NumChannels, SamplesToDo); - apply_row(OutBuffer[chan], dec->MatrixLF[chan], dec->SamplesLF, + apply_row(dec->ChannelMix, dec->MatrixLF[chan], dec->SamplesLF, dec->NumChannels, SamplesToDo); + + if(dec->Delay[chan].Length > 0) + { + const ALuint base = dec->Delay[chan].Length; + if(SamplesToDo >= base) + { + for(i = 0;i < base;i++) + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + for(;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i-base] * dec->Delay[chan].Gain; + memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], + base*sizeof(ALfloat)); + } + else + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, + base - SamplesToDo); + memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, + SamplesToDo*sizeof(ALfloat)); + } + } + else for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i] * dec->Delay[chan].Gain; } } else { for(chan = 0;chan < OutChannels;chan++) - apply_row(OutBuffer[chan], dec->MatrixHF[chan], InSamples, + { + memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + apply_row(dec->ChannelMix, dec->MatrixHF[chan], InSamples, dec->NumChannels, SamplesToDo); + + if(dec->Delay[chan].Length > 0) + { + const ALuint base = dec->Delay[chan].Length; + if(SamplesToDo >= base) + { + for(i = 0;i < base;i++) + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + for(;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i-base] * dec->Delay[chan].Gain; + memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], + base*sizeof(ALfloat)); + } + else + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, + base - SamplesToDo); + memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, + SamplesToDo*sizeof(ALfloat)); + } + } + else for(i = 0;i < SamplesToDo;i++) + OutBuffer[chan][i] += dec->ChannelMix[i] * dec->Delay[chan].Gain; + } } } -- cgit v1.2.3 From 1dcb04157c158fc22390dd99a89469a523dd0109 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 17:52:42 -0700 Subject: Add a config option for distance compensation --- Alc/bformatdec.c | 4 ++-- Alc/bformatdec.h | 6 +++++- Alc/panning.c | 10 ++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 7c202228..463a1969 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -233,7 +233,7 @@ int bformatdec_getOrder(const struct BFormatDec *dec) return 0; } -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]) +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags) { static const ALuint map2DTo3D[7] = { 0, 1, 3, 4, 8, 9, 15 @@ -362,7 +362,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, maxdist = maxf(maxdist, conf->Speakers[i].Distance); memset(dec->Delay, 0, sizeof(dec->Delay)); - if(maxdist > 0.0f) + if((flags&BFDF_DistanceComp) && maxdist > 0.0f) { for(i = 0;i < conf->NumSpeakers;i++) { diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 623e7b09..3ad06373 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -6,10 +6,14 @@ struct AmbDecConf; struct BFormatDec; +enum BFormatDecFlags { + BFDF_DistanceComp = 1<<0 +}; + struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); -void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS]); +void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags); /* Decodes the ambisonic input to the given output channels. */ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); diff --git a/Alc/panning.c b/Alc/panning.c index 1ac79449..90122550 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -620,9 +620,11 @@ ALvoid aluInitPanning(ALCdevice *device) { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, }; + const char *devname = al_string_get_cstr(device->DeviceName); ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *fname = ""; const char *layout; + int decflags = 0; AmbDecConf conf; ambdec_init(&conf); @@ -630,9 +632,12 @@ ALvoid aluInitPanning(ALCdevice *device) layout = GetChannelLayoutName(device->FmtChans); if(!layout) goto ambi_fail; - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "decoder", layout, &fname)) + if(!ConfigValueStr(devname, "decoder", layout, &fname)) goto ambi_fail; + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) + decflags |= BFDF_DistanceComp; + if(!ambdec_load(&conf, fname)) { ERR("Failed to load %s\n", fname); @@ -677,7 +682,8 @@ ALvoid aluInitPanning(ALCdevice *device) (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? "third" : "second" : "first", (conf.ChanMask & ~0x831b) ? " periphonic" : "" ); - bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap); + bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, + speakermap, decflags); ambdec_deinit(&conf); if(bformatdec_getOrder(device->AmbiDecoder) < 2) -- cgit v1.2.3 From b4a1ba9d3f7a87568059192dab4136a64ff13eb3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 18:06:36 -0700 Subject: Include the distance gain compensation in the decoder matrix --- Alc/bformatdec.c | 112 +++++++++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 463a1969..d873984a 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -185,7 +185,6 @@ typedef struct BFormatDec { struct { alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; - ALfloat Gain; ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ } Delay[MAX_OUTPUT_CHANNELS]; @@ -239,6 +238,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; + ALfloat distgain[MAX_OUTPUT_CHANNELS]; ALfloat maxdist, ratio; ALuint i; @@ -273,6 +273,41 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, dec->Periphonic = AL_FALSE; } + maxdist = 0.0f; + for(i = 0;i < conf->NumSpeakers;i++) + { + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + distgain[i] = 1.0f; + } + + memset(dec->Delay, 0, sizeof(dec->Delay)); + if((flags&BFDF_DistanceComp) && maxdist > 0.0f) + { + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = chanmap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + (ALfloat)srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)); + distgain[i] = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan, + al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i] + ); + } + } + if(conf->FreqBands == 1) { dec->DualBand = AL_FALSE; @@ -304,7 +339,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(j == 3) gain = conf->LFOrderGain[2] / ratio; else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[l] * gain; + dec->MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[l] * + gain * distgain[i]; } } else @@ -316,7 +352,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(j == 4) gain = conf->LFOrderGain[2] / ratio; else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * gain; + dec->MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * + gain * distgain[i]; } } } @@ -339,7 +376,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(j == 3) gain = conf->HFOrderGain[2] * ratio; else if(j == 5) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain; + dec->MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * + gain * distgain[i]; } } else @@ -351,49 +389,11 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(j == 4) gain = conf->HFOrderGain[2] * ratio; else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain; + dec->MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + gain * distgain[i]; } } } - - - maxdist = 0.0f; - for(i = 0;i < conf->NumSpeakers;i++) - maxdist = maxf(maxdist, conf->Speakers[i].Distance); - - memset(dec->Delay, 0, sizeof(dec->Delay)); - if((flags&BFDF_DistanceComp) && maxdist > 0.0f) - { - for(i = 0;i < conf->NumSpeakers;i++) - { - ALuint chan = chanmap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - (ALfloat)srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); - - dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)); - dec->Delay[chan].Gain = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan, - al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, - dec->Delay[chan].Gain - ); - } - } - else - { - for(i = 0;i < conf->NumSpeakers;i++) - dec->Delay[chanmap[i]].Gain = 1.0f; - } } @@ -435,24 +435,24 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU if(SamplesToDo >= base) { for(i = 0;i < base;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; for(;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i-base] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->ChannelMix[i-base]; memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], - base*sizeof(ALfloat)); + base*sizeof(ALfloat)); } else { for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, base - SamplesToDo); memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, - SamplesToDo*sizeof(ALfloat)); + SamplesToDo*sizeof(ALfloat)); } } else for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->ChannelMix[i]; } } else @@ -469,24 +469,24 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU if(SamplesToDo >= base) { for(i = 0;i < base;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; for(;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i-base] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->ChannelMix[i-base]; memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], - base*sizeof(ALfloat)); + base*sizeof(ALfloat)); } else { for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, base - SamplesToDo); memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, - SamplesToDo*sizeof(ALfloat)); + SamplesToDo*sizeof(ALfloat)); } } else for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i] * dec->Delay[chan].Gain; + OutBuffer[chan][i] += dec->ChannelMix[i]; } } } -- cgit v1.2.3 From ad7ad48bd126191e4936d386e55945832b9574d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 20:23:20 -0700 Subject: Don't use custom decoder configurations with mono or stereo By default, stereo outputs using UHJ, which renders to a B-Format buffer that gets run through a UHJ encoder for output. It may also output using pair-wise panning, which pans between -30 and +30 degrees with the speakers at the two ends. In both cases, the stereo coefficients are ignored. Mono, having only one output channel, can realistically only attenuate its channel. Turning the volume up and down accomplishes the same result. --- Alc/panning.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Alc/panning.c b/Alc/panning.c index 90122550..c3145cd7 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -390,6 +390,13 @@ static bool LoadChannelSetup(ALCdevice *device) AmbDecConf conf; ALuint i, j; + /* Don't use custom decoders with mono or stereo output (stereo is using + * UHJ or pair-wise panning, thus ignores the custom coefficients anyway, + * and mono would realistically only specify attenuation on the output). + */ + if(device->FmtChans == DevFmtMono || device->FmtChans == DevFmtStereo) + return false; + layout = GetChannelLayoutName(device->FmtChans); if(!layout) return false; @@ -629,6 +636,12 @@ ALvoid aluInitPanning(ALCdevice *device) ambdec_init(&conf); + /* Don't do HQ ambisonic decoding with mono or stereo output. Same + * reasons as in LoadChannelSetup. + */ + if(device->FmtChans == DevFmtMono || device->FmtChans == DevFmtStereo) + goto ambi_fail; + layout = GetChannelLayoutName(device->FmtChans); if(!layout) goto ambi_fail; -- cgit v1.2.3 From 6aaa11df300f6a9582dc6815407e59902ae6674b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 21:02:10 -0700 Subject: Use the same option for decoder configs --- Alc/panning.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index c3145cd7..b8ff3482 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -400,7 +400,7 @@ static bool LoadChannelSetup(ALCdevice *device) layout = GetChannelLayoutName(device->FmtChans); if(!layout) return false; - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", layout, &fname)) + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "decoder", layout, &fname)) return false; ambdec_init(&conf); @@ -410,6 +410,10 @@ static bool LoadChannelSetup(ALCdevice *device) goto fail; } + /* TODO: Perhaps just use the high-frequency matrix, even if both are + * present? The recommendation seems to be to use an energy decode (rE, + * aka high-frequency) if frequency-dependent processing is not available. + */ if(conf.FreqBands != 1) { ERR("AmbDec layout file must be single-band (freq_bands = %u)\n", conf.FreqBands); -- cgit v1.2.3 From 764d5801001b7d680da91075890160ea6dae597f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Mar 2016 21:39:12 -0700 Subject: Document the ambisonic decoder options --- alsoftrc.sample | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/alsoftrc.sample b/alsoftrc.sample index 255f82d0..353b5573 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -202,6 +202,52 @@ # of a context error. On Windows, a breakpoint exception is generated. #trap-al-error = false +## +## Ambisonic decoder stuff +## +[decoder] + +## hq-mode: +# Enables a high-quality ambisonic decoder. This mode is capable of frequency- +# dependent processing, creating a better reproduction of 3D sound rendering +# over surround sound speakers. Enabling this also requires specifying decoder +# configuration files for the appropriate speaker configuration you intend to +# use (see the quad, surround51, etc options below). Currently, periphonic +# (with height) configurations support up to second-order, and horizontal +# configurations support up to third-order. +hq-mode = false + +## distance-comp: +# Enables compensation for the speakers' relative distances to the listener. +# This applies the necessary delays and attenuation to make the speakers +# behave as though they are all equidistant, which is important for proper +# playback of 3D sound rendering. Requires the high-quality ambisonic decoder, +# as well as the proper distances to be specified in the decoder configuration +# file. +distance-comp = true + +## quad: +# Decoder configuration file for Quadrophonic channel output. +quad = + +## surround51: +# Decoder configuration file for 5.1 Surround (Side) channel output. +surround51 = + +## surround51rear: +# Decoder configuration file for 5.1 Surround (Rear) channel output. +surround51rear = + +## surround61: +# Decoder configuration file for 6.1 Surround channel output. +surround61 = + +## surround71: +# Decoder configuration file for 7.1 Surround channel output. Note: This can +# be used to enable 3D7.1 with the appropriate configuration file and speaker +# placement. +surround71 = + ## ## Reverb effect stuff (includes EAX reverb) ## -- cgit v1.2.3 From 91d53560d6f7e22be00ef6243f5dc1ea3211ceed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Mar 2016 01:57:28 -0700 Subject: Add a text file describing AmbDec config file support. --- alsoft_ambdec.txt | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ alsoftrc.sample | 17 +++-- 2 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 alsoft_ambdec.txt diff --git a/alsoft_ambdec.txt b/alsoft_ambdec.txt new file mode 100644 index 00000000..65965f3b --- /dev/null +++ b/alsoft_ambdec.txt @@ -0,0 +1,182 @@ +AmbDec Configuration Files +========================== + +AmbDec configuration files were developed by Fons Adriaensen as part of the +AmbDec program . + +Starting with OpenAL Soft 1.18, version 3 of the file format is supported as a +means of specifying custom surround sound speaker layouts. These configuration +files are also used to enable the high-quality ambisonic decoder. + + +File Format +=========== + +As of this writing, there is no official documentation of the .ambdec file +format. However, the format as OpenAL Soft sees it is as follows: + +The file is plain text. Comments start with a hash/pound character (#). There +may be any amount of whitespace in between the option and parameter values. +Strings are *not* enclosed in quotation marks. + +/description +Specifies a text description of the configuration. Ingored by OpenAL Soft. + +/version +Declares the format version used by the configuration file. OpenAL Soft +currently only supports version 3. + +/dec/chan_mask +Specifies a hexadecimal mask value of ambisonic input channels used by this +decoder. Counting up from the least significant bit, bit 0 maps to Ambisonic +Channel Number (ACN) 0, bit 1 maps to ACN 1, etc. As an example, a value of 'b' +enables bits 0, 1, and 3 (1011 in binary), which correspond to ACN 0, 1, and 3 +(first-order horizontal). + +/dec/freq_bands +Specifies the number of frequency bands used by the decoder. This must be 1 for +single-band or 2 for dual-band. + +/dec/speakers +Specifies the number of output speakers to decode to. + +/dec/coeff_scale +Specifies the scaling used by the decoder coefficients. Currently recognized +types are fuma, sn3d, and n3d, for Furse-Malham (FuMa), semi-normalized (SN3D), +and fully normalized (N3D) scaling, respectively. + +/opt/input_scale +Specifies the scaling used by the ambisonic input data. As OpenAL Soft renders +the data itself and knows the scaling, this is ignored. + +/opt/nfeff_comp +Specifies whether near-field effect compensation is off (not applied at all), +applied on input (faster, less accurate with varying speaker distances) or +output (slower, more accurate with varying speaker distances). Ignored by +OpenAL Soft. + +/opt/delay_comp +Specifies whether delay compensation is applied for output. This is used to +correct for time variations caused by different speaker distances. As OpenAL +Soft has its own config option for this, this is ignored. + +/opt/level_comp +Specifies whether gain compensation is applied for output. This is used to +correct for volume variations caused by different speaker distances. As OpenAL +Soft has its own config option for this, this is ignored. + +/opt/xover_freq +Specifies the crossover frequency for dual-band decoders. Frequencies less than +this are fed to the low-frequency matrix, and frequencies greater than this are +fed to the high-freqyency matrix. Unused for single-band decoders. + +/opt/xover_ratio +Specifies the volume ratio between the frequency bands. Values greater than 0 +decrease the low-frequency output by half the specified value and increase the +high-frequency output by half the specified value, while values less than 0 +increase the low-frequency output and decrease the high-frequency output to +similar effect. Unused for single-band decoders. + +/speakers/{ +Begins the output speaker definitions. A speaker is defined using the add_spkr +command, and there must be a matching number of speaker definitions as the +specified speaker count. The definitions are ended with a "/}". + +add_spkr +Defines an output speaker. The ID is a string identifier for the output speaker +(see Speaker IDs below). The distance is in meters from the center-point of the +physical speaker array. The azimuth is the horizontal angle of the speaker, in +degrees, where 0 is directly front and positive values go left. The elevation +is the vertical angle of the speaker, in degrees, where 0 is directly front and +positive goes upward. The connection string is the JACK port name the speaker +should connect to. Currently, OpenAL Soft uses the ID and distance, and ignores +the rest. + +/lfmatrix/{ +Begins the low-frequency decoder matrix definition. The definition should +include an order_gain command to specify the base gain for the ambisonic +orders. Each matrix row is defined using the add_row command, and there must be +a matching number of rows as the number of speakers. Additionally the row +definitions are in the same order as the speaker definitions. The definitions +are ended with a "/}". Only valid for dual-band decoders. + +/hfmatrix/{ +Begins the high-frequency decoder matrix definition. The definition should +include an order_gain command to specify the base gain for the ambisonic +orders. Each matrix row is defined using the add_row command, and there must be +a matching number of rows as the number of speakers, Additionally the row +definitions are in the same order as the speaker definitions. The definitions +are ended with a "/}". Only valid for dual-band decoders. + +/matrix/{ +Begins the decoder matrix definition. The definition should include an +order_gain command to specify the base gain for the ambisonic orders. Each +matrix row is defined using the add_row command, and there must be a matching +number of rows as the number of speakers. Additionally the row definitions are +in the same order as the speaker definitions. The definitions are ended with a +"/}". Only valid for single-band decoders. + +order_gain +Specifies the base gain for the zeroth-, first-, second-, and third-order +coefficients in the given matrix, automatically scaling the related +coefficients. This should be specified at the beginning of the matrix +definition. + +add_row ... +Specifies a row of coefficients for the matrix. There should be one coefficient +for each enabled bit in the channel mask, and corresponds to the matching ACN +channel. + +/end +Marks the end of the configuration file. + + +Speaker IDs +=========== + +The AmbDec program uses the speaker ID as a label to display in its config +dialog, but does not otherwise use it for any particular purpose. However, +since OpenAL Soft needs to match a speaker definition to an output channel, the +speaker ID is used to identify what output channel it correspond to. Therefore, +OpenAL Soft requires these channel labels to be recognized: + +LF = Front left +RF = Front right +LS = Side left +RS = Side right +LB = Back left +RB = Back right +CE = Front center +CB = Back center + +Additionally, configuration files for surround51 will acknowledge back speakers +for side channels, and surround51rear will acknowledge side speakers for back +channels, to avoid issues with a configuration expecting 5.1 to use the side +channels when the device is configured for back, or vice-versa. + +Furthermore, OpenAL Soft does not require a speaker definition for each output +channel the configuration is used with. So for example a 5.1 configuration may +omit a front center speaker definition, in which case the front center output +channel will not contribute to the ambisonic decode (though OpenAL Soft will +still use it in certain scenarios, such as the AL_EFFECT_DEDICATED_DIALOGUE +effect). + + +Creating Configuration Files +============================ + +Configuration files can be created or modified by hand in a text editor. The +AmbDec program also has a GUI for creating and editing them. However, these +methods rely on you having the coefficients to fill in... they won't be +generated for you. + +Another option is to use the Ambisonic Decoder Toolbox +. This is a collection of +MATLAB and GNU Octave scripts that can generate AmbDec configuration files from +an array of speaker definitions (labels and positions). If you're familiar with +using MATLAB or GNU Octave, this may be a good option. + +There are plans for OpenAL Soft to include a utility to generate coefficients +and make configuration files. However, calculating proper coefficients for +anything other than regular or semi-regular speaker setups is somewhat of a +black art, so may take some time. diff --git a/alsoftrc.sample b/alsoftrc.sample index 353b5573..3a22914d 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -227,24 +227,29 @@ hq-mode = false distance-comp = true ## quad: -# Decoder configuration file for Quadrophonic channel output. +# Decoder configuration file for Quadrophonic channel output. See +# alsoft_ambdec.txt for a description of the file format. quad = ## surround51: -# Decoder configuration file for 5.1 Surround (Side) channel output. +# Decoder configuration file for 5.1 Surround (Side) channel output. See +# alsoft_ambdec.txt for a description of the file format. surround51 = ## surround51rear: -# Decoder configuration file for 5.1 Surround (Rear) channel output. +# Decoder configuration file for 5.1 Surround (Rear) channel output. See +# alsoft_ambdec.txt for a description of the file format. surround51rear = ## surround61: -# Decoder configuration file for 6.1 Surround channel output. +# Decoder configuration file for 6.1 Surround channel output. See +# alsoft_ambdec.txt for a description of the file format. surround61 = ## surround71: -# Decoder configuration file for 7.1 Surround channel output. Note: This can -# be used to enable 3D7.1 with the appropriate configuration file and speaker +# Decoder configuration file for 7.1 Surround channel output. See +# alsoft_ambdec.txt for a description of the file format. Note: This can be +# used to enable 3D7.1 with the appropriate configuration file and speaker # placement. surround71 = -- cgit v1.2.3 From 33cd3834ac9b01fb4c2ef9c5497fc9926e8b8d28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Mar 2016 13:23:37 -0700 Subject: Align the ChannelMix buffer and use it for up-sampling --- Alc/bformatdec.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index d873984a..ce489dc1 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -177,18 +177,18 @@ typedef struct BFormatDec { ALfloat (*SamplesHF)[BUFFERSIZE]; ALfloat (*SamplesLF)[BUFFERSIZE]; - struct { - const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS]; - const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; - ALuint NumChannels; - } UpSampler; + alignas(16) ALfloat ChannelMix[BUFFERSIZE]; struct { alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ } Delay[MAX_OUTPUT_CHANNELS]; - ALfloat ChannelMix[BUFFERSIZE]; + struct { + const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS]; + const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; + ALuint NumChannels; + } UpSampler; ALuint NumChannels; ALboolean DualBand; @@ -502,8 +502,8 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B */ for(k = 0;k < dec->UpSampler.NumChannels;k++) { - memset(dec->Samples[0], 0, SamplesToDo*sizeof(ALfloat)); - apply_row(dec->Samples[0], dec->UpSampler.MatrixHF[k], InSamples, + memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + apply_row(dec->ChannelMix, dec->UpSampler.MatrixHF[k], InSamples, InChannels, SamplesToDo); for(j = 0;j < dec->NumChannels;j++) @@ -512,7 +512,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(i = 0;i < SamplesToDo;i++) - OutBuffer[j][i] += dec->Samples[0][i] * gain; + OutBuffer[j][i] += dec->ChannelMix[i] * gain; } } } -- cgit v1.2.3 From 34539bc973fc6ee525a4ba21f5653820e62004ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Mar 2016 14:50:18 -0700 Subject: Skip unused output channels for the HQ decode --- Alc/bformatdec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index ce489dc1..6dd5ce9a 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -167,6 +167,8 @@ static void init_encoder(void) * single-band decoding */ typedef struct BFormatDec { + ALboolean Enabled[MAX_OUTPUT_CHANNELS]; + alignas(16) ALfloat MatrixHF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; alignas(16) ALfloat MatrixLF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; @@ -253,6 +255,11 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, dec->SamplesHF = dec->Samples; dec->SamplesLF = dec->SamplesHF + dec->NumChannels; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + dec->Enabled[i] = AL_FALSE; + for(i = 0;i < conf->NumSpeakers;i++) + dec->Enabled[chanmap[i]] = AL_TRUE; + if(conf->CoeffScale == ADS_SN3D) coeff_scale = SN3D2N3DScale; else if(conf->CoeffScale == ADS_FuMa) @@ -423,6 +430,9 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU for(chan = 0;chan < OutChannels;chan++) { + if(!dec->Enabled[chan]) + continue; + memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); apply_row(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF, dec->NumChannels, SamplesToDo); @@ -459,6 +469,9 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU { for(chan = 0;chan < OutChannels;chan++) { + if(!dec->Enabled[chan]) + continue; + memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); apply_row(dec->ChannelMix, dec->MatrixHF[chan], InSamples, dec->NumChannels, SamplesToDo); -- cgit v1.2.3 From ca309e685e88244c3b380acd5eabbc65364665b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Mar 2016 16:35:42 -0700 Subject: Add a config dialog tab for decoder options --- utils/alsoft-config/mainwindow.cpp | 67 ++++++++++ utils/alsoft-config/mainwindow.h | 10 ++ utils/alsoft-config/mainwindow.ui | 264 ++++++++++++++++++++++++++++++++++++- 3 files changed, 336 insertions(+), 5 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 5f57ce0f..53e2ffea 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -312,6 +312,19 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(toggleHqState(int))); + connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); + connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder51Button, SIGNAL(clicked()), this, SLOT(select51DecoderFile())); + connect(ui->decoder51RearLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder51RearButton, SIGNAL(clicked()), this, SLOT(select51RearDecoderFile())); + connect(ui->decoder61LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select71DecoderFile())); + connect(ui->decoder71LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder71Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); + connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); @@ -610,6 +623,18 @@ void MainWindow::loadConfig(const QString &fname) } } + bool hqmode = settings.value("decoder/hq-mode", false).toBool(); + ui->decoderHQModeCheckBox->setChecked(hqmode); + bool distcomp = settings.value("decoder/distance-comp", true).toBool(); + ui->decoderDistCompCheckBox->setChecked(distcomp); + ui->decoderDistCompCheckBox->setEnabled(hqmode); + + ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); + ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); + ui->decoder51RearLineEdit->setText(settings.value("decoder/surround51rear").toString()); + ui->decoder61LineEdit->setText(settings.value("decoder/surround61").toString()); + ui->decoder71LineEdit->setText(settings.value("decoder/surround71").toString()); + QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); if(disabledCpuExts.size() == 1) disabledCpuExts = disabledCpuExts[0].split(QChar(',')); @@ -826,6 +851,19 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("stereo-mode", getValueFromName(stereoModeList, ui->stereoModeCombo->currentText())); settings.setValue("stereo-panning", getValueFromName(stereoPanList, ui->stereoPanningComboBox->currentText())); + settings.setValue("decoder/hq-mode", + ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("decoder/distance-comp", + ui->decoderDistCompCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + + settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); + settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); + settings.setValue("decoder/surround51rear", ui->decoder51RearLineEdit->text()); + settings.setValue("decoder/surround61", ui->decoder61LineEdit->text()); + settings.setValue("decoder/surround71", ui->decoder71LineEdit->text()); + QStringList strlist; if(!ui->enableSSECheckBox->isChecked()) strlist.append("sse"); @@ -1035,6 +1073,35 @@ void MainWindow::updatePeriodCountSlider() } +void MainWindow::toggleHqState(int state) +{ + ui->decoderDistCompCheckBox->setEnabled(state); + enableApplyButton(); +} + +void MainWindow::selectQuadDecoderFile() +{ selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} +void MainWindow::select51DecoderFile() +{ selectDecoderFile(ui->decoder51LineEdit, "Select 5.1 Surround (Side) Decoder");} +void MainWindow::select51RearDecoderFile() +{ selectDecoderFile(ui->decoder51RearLineEdit, "Select 5.1 Surround (Rear) Decoder");} +void MainWindow::select61DecoderFile() +{ selectDecoderFile(ui->decoder61LineEdit, "Select 6.1 Surround Decoder");} +void MainWindow::select71DecoderFile() +{ selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} +void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) +{ + QString fname = QFileDialog::getOpenFileName(this, tr(caption), + line->text(), tr("AmbDec Files (*.ambdec);;All Files (*.*)") + ); + if(!fname.isEmpty()) + { + line->setText(fname); + enableApplyButton(); + } +} + + void MainWindow::updateJackBufferSizeEdit(int size) { ui->jackBufferSizeLine->clear(); diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 65e6e1b6..3bf2fb83 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -35,6 +35,14 @@ private slots: void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); + void toggleHqState(int state); + + void selectQuadDecoderFile(); + void select51DecoderFile(); + void select51RearDecoderFile(); + void select61DecoderFile(); + void select71DecoderFile(); + void updateJackBufferSizeEdit(int size); void updateJackBufferSizeSlider(); @@ -68,6 +76,8 @@ private: void closeEvent(QCloseEvent *event); + void selectDecoderFile(QLineEdit *line, const char *name); + QStringList collectHrtfs(); void loadConfig(const QString &fname); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 9ed7840a..cb1df954 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -537,6 +537,258 @@ Pair-Wise uses standard pair-wise panning between + + + Renderer + + + + + 10 + 20 + 181 + 21 + + + + Enables high-quality ambisonic rendering. This mode is +capable of frequency-dependent processing, creating a +better reproduction of 3D sound rendering over +surround sound speakers. Enabling this also requires +specifying decoder configuration files for the +appropriate speaker configuration you intend to use. + + + Qt::RightToLeft + + + High Quality Mode: + + + + + + 10 + 50 + 181 + 21 + + + + This applies the necessary delays and attenuation +to make the speakers behave as though they are +all equidistant, which is important for proper +playback of 3D sound rendering. Requires the high +quality ambisonic renderer, as well as the proper +distances to be specified in the decoder +configuration file. + + + Qt::RightToLeft + + + Distance Compensation: + + + true + + + + + + 140 + 100 + 281 + 21 + + + + + + + 11 + 100 + 121 + 21 + + + + Quadrophonic: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 140 + 130 + 281 + 21 + + + + + + + 140 + 160 + 281 + 21 + + + + + + + 140 + 190 + 281 + 21 + + + + + + + 140 + 220 + 281 + 21 + + + + + + + 10 + 130 + 121 + 21 + + + + 5.1 Surround (Side): + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 160 + 121 + 21 + + + + 5.1 Surround (Rear): + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 190 + 121 + 21 + + + + 6.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 220 + 121 + 21 + + + + 7.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 430 + 100 + 91 + 21 + + + + Browse... + + + + + + 430 + 130 + 91 + 21 + + + + Browse... + + + + + + 430 + 160 + 91 + 21 + + + + Browse... + + + + + + 430 + 190 + 91 + 21 + + + + Browse... + + + + + + 430 + 220 + 91 + 21 + + + + Browse... + + + HRTF @@ -1182,7 +1434,7 @@ during updates. 320 30 91 - 22 + 21 @@ -1195,7 +1447,7 @@ during updates. 320 60 91 - 22 + 21 @@ -1239,7 +1491,7 @@ during updates. 320 30 91 - 22 + 21 @@ -1293,7 +1545,7 @@ during updates. 320 30 91 - 22 + 21 @@ -1942,7 +2194,9 @@ added by the ALC_EXT_DEDICATED extension. Cancel - + + + -- cgit v1.2.3 From 2ccc1d1d8a6ecc5c025e99518038fcc7a001d949 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Mar 2016 00:44:58 -0700 Subject: Move the aligned malloc functions to the common lib --- Alc/ALc.c | 1 + Alc/alcRing.c | 1 + Alc/bformatdec.c | 1 + Alc/helpers.c | 50 ------------------------------------- CMakeLists.txt | 3 ++- OpenAL32/Include/alMain.h | 6 +---- OpenAL32/alAuxEffectSlot.c | 2 ++ OpenAL32/alSource.c | 1 + OpenAL32/alThunk.c | 2 ++ common/almalloc.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ include/almalloc.h | 18 ++++++++++++++ 11 files changed, 91 insertions(+), 56 deletions(-) create mode 100644 common/almalloc.c create mode 100644 include/almalloc.h diff --git a/Alc/ALc.c b/Alc/ALc.c index 6389270c..43ec7cf9 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -44,6 +44,7 @@ #include "compat.h" #include "threads.h" #include "alstring.h" +#include "almalloc.h" #include "backends/base.h" diff --git a/Alc/alcRing.c b/Alc/alcRing.c index e9a40a12..05db7bc3 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -25,6 +25,7 @@ #include "alMain.h" #include "threads.h" +#include "almalloc.h" #include "compat.h" diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 6dd5ce9a..e4c6da49 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -6,6 +6,7 @@ #include "alu.h" #include "threads.h" +#include "almalloc.h" typedef struct BandSplitter { diff --git a/Alc/helpers.c b/Alc/helpers.c index f596c0d9..c8983c11 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -243,56 +243,6 @@ void FillCPUCaps(ALuint capfilter) } -void *al_malloc(size_t alignment, size_t size) -{ -#if defined(HAVE_ALIGNED_ALLOC) - size = (size+(alignment-1))&~(alignment-1); - return aligned_alloc(alignment, size); -#elif defined(HAVE_POSIX_MEMALIGN) - void *ret; - if(posix_memalign(&ret, alignment, size) == 0) - return ret; - return NULL; -#elif defined(HAVE__ALIGNED_MALLOC) - return _aligned_malloc(size, alignment); -#else - char *ret = malloc(size+alignment); - if(ret != NULL) - { - *(ret++) = 0x00; - while(((ptrdiff_t)ret&(alignment-1)) != 0) - *(ret++) = 0x55; - } - return ret; -#endif -} - -void *al_calloc(size_t alignment, size_t size) -{ - void *ret = al_malloc(alignment, size); - if(ret) memset(ret, 0, size); - return ret; -} - -void al_free(void *ptr) -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) - free(ptr); -#elif defined(HAVE__ALIGNED_MALLOC) - _aligned_free(ptr); -#else - if(ptr != NULL) - { - char *finder = ptr; - do { - --finder; - } while(*finder == 0x55); - free(finder); - } -#endif -} - - void SetMixerFPUMode(FPUCtl *ctl) { #ifdef HAVE_FENV_H diff --git a/CMakeLists.txt b/CMakeLists.txt index c3e17967..8c89a0d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -607,7 +607,8 @@ IF(NOT HAVE_STDINT_H) ENDIF() -SET(COMMON_OBJS common/atomic.c +SET(COMMON_OBJS common/almalloc.c + common/atomic.c common/rwlock.c common/threads.c common/uintmap.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4c737f02..17edd7fc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -36,6 +36,7 @@ #include "uintmap.h" #include "vector.h" #include "alstring.h" +#include "almalloc.h" #include "hrtf.h" @@ -637,11 +638,6 @@ inline void UnlockContext(ALCcontext *context) { ALCdevice_Unlock(context->Device); } -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); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index c80bab22..0364c33c 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -31,6 +31,8 @@ #include "alError.h" #include "alSource.h" +#include "almalloc.h" + extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index d7b68185..03eae080 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -37,6 +37,7 @@ #include "backends/base.h" #include "threads.h" +#include "almalloc.h" extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c index 0cebad42..29da9bbd 100644 --- a/OpenAL32/alThunk.c +++ b/OpenAL32/alThunk.c @@ -25,6 +25,8 @@ #include "alMain.h" #include "alThunk.h" +#include "almalloc.h" + static ATOMIC(ALenum) *ThunkArray; static ALuint ThunkArraySize; diff --git a/common/almalloc.c b/common/almalloc.c new file mode 100644 index 00000000..8c1c5794 --- /dev/null +++ b/common/almalloc.c @@ -0,0 +1,62 @@ + +#include "config.h" + +#include "almalloc.h" + +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_WINDOWS_H +#include +#endif + +void *al_malloc(size_t alignment, size_t size) +{ +#if defined(HAVE_ALIGNED_ALLOC) + size = (size+(alignment-1))&~(alignment-1); + return aligned_alloc(alignment, size); +#elif defined(HAVE_POSIX_MEMALIGN) + void *ret; + if(posix_memalign(&ret, alignment, size) == 0) + return ret; + return NULL; +#elif defined(HAVE__ALIGNED_MALLOC) + return _aligned_malloc(size, alignment); +#else + char *ret = malloc(size+alignment); + if(ret != NULL) + { + *(ret++) = 0x00; + while(((ptrdiff_t)ret&(alignment-1)) != 0) + *(ret++) = 0x55; + } + return ret; +#endif +} + +void *al_calloc(size_t alignment, size_t size) +{ + void *ret = al_malloc(alignment, size); + if(ret) memset(ret, 0, size); + return ret; +} + +void al_free(void *ptr) +{ +#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) + free(ptr); +#elif defined(HAVE__ALIGNED_MALLOC) + _aligned_free(ptr); +#else + if(ptr != NULL) + { + char *finder = ptr; + do { + --finder; + } while(*finder == 0x55); + free(finder); + } +#endif +} diff --git a/include/almalloc.h b/include/almalloc.h new file mode 100644 index 00000000..355db795 --- /dev/null +++ b/include/almalloc.h @@ -0,0 +1,18 @@ +#ifndef AL_MALLOC_H +#define AL_MALLOC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *al_malloc(size_t alignment, size_t size); +void *al_calloc(size_t alignment, size_t size); +void al_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* AL_MALLOC_H */ -- cgit v1.2.3 From d6163fe570e09a6fa65ef1f11eba3d6bcbd3aa9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Mar 2016 23:48:36 -0700 Subject: Convert remaining ringbuffers to the lockless variant --- Alc/backends/alsa.c | 35 +++++++++++++++------------------ Alc/backends/coreaudio.c | 22 ++++++++++++--------- Alc/backends/dsound.c | 18 +++++++++-------- Alc/backends/oss.c | 51 ++++++++++++++++++++++++------------------------ Alc/backends/winmm.c | 18 ++++++++--------- 5 files changed, 74 insertions(+), 70 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index b5715e18..3a0ed205 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -915,7 +915,7 @@ typedef struct ALCcaptureAlsa { ALsizei size; ALboolean doCapture; - RingBuffer *ring; + ll_ringbuffer_t *ring; snd_pcm_sframes_t last_avail; } ALCcaptureAlsa; @@ -1047,21 +1047,15 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { - self->ring = CreateRingBuffer(FrameSizeFromDevFmt(device->FmtChans, device->FmtType), - device->UpdateSize*device->NumUpdates); + self->ring = ll_ringbuffer_create( + device->UpdateSize*device->NumUpdates + 1, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType) + ); if(!self->ring) { ERR("ring buffer create failed\n"); goto error2; } - - 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; - } } al_string_copy_cstr(&device->DeviceName, name); @@ -1075,7 +1069,7 @@ error: error2: free(self->buffer); self->buffer = NULL; - DestroyRingBuffer(self->ring); + ll_ringbuffer_free(self->ring); self->ring = NULL; snd_pcm_close(self->pcmHandle); @@ -1085,7 +1079,7 @@ error2: static void ALCcaptureAlsa_close(ALCcaptureAlsa *self) { snd_pcm_close(self->pcmHandle); - DestroyRingBuffer(self->ring); + ll_ringbuffer_free(self->ring); free(self->buffer); self->buffer = NULL; @@ -1143,7 +1137,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff if(self->ring) { - ReadRingBuffer(self->ring, buffer, samples); + ll_ringbuffer_read(self->ring, buffer, samples); return ALC_NO_ERROR; } @@ -1246,12 +1240,15 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) while(avail > 0) { + ll_ringbuffer_data_t vec[2]; snd_pcm_sframes_t amt; - amt = snd_pcm_bytes_to_frames(self->pcmHandle, self->size); - if(avail < amt) amt = avail; + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len == 0) break; - amt = snd_pcm_readi(self->pcmHandle, self->buffer, amt); + amt = (vec[0].len < (snd_pcm_uframes_t)avail) ? + vec[0].len : (snd_pcm_uframes_t)avail; + amt = snd_pcm_readi(self->pcmHandle, vec[0].buf, amt); if(amt < 0) { ERR("read error: %s\n", snd_strerror(amt)); @@ -1275,11 +1272,11 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) continue; } - WriteRingBuffer(self->ring, self->buffer, amt); + ll_ringbuffer_write_advance(self->ring, amt); avail -= amt; } - return RingBufferSize(self->ring); + return ll_ringbuffer_read_space(self->ring); } static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index d9264217..4907f362 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -45,7 +45,7 @@ typedef struct { AudioBufferList *bufferList; // Buffer for data coming from the input device ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling - RingBuffer *ring; + ll_ringbuffer_t *ring; } ca_data; static const ALCchar ca_device[] = "CoreAudio Default"; @@ -102,7 +102,7 @@ static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverte ca_data *data = (ca_data*)device->ExtraData; // Read from the ring buffer and store temporarily in a large buffer - ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets)); + ll_ringbuffer_read(data->ring, data->resampleBuffer, *ioNumberDataPackets); // Set the input data ioData->mNumberBuffers = 1; @@ -130,7 +130,7 @@ static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags * return err; } - WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); + ll_ringbuffer_write(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); return noErr; } @@ -586,16 +586,19 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) if(data->bufferList == NULL) goto error; - data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates); - if(data->ring == NULL) - goto error; + data->ring = ll_ringbuffer_create( + device->UpdateSize*data->sampleRateRatio*device->NumUpdates + 1, + data->frameSize + ); + if(!data->ring) goto error; al_string_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; error: - DestroyRingBuffer(data->ring); + ll_ringbuffer_free(data->ring); + data->ring = NULL; free(data->resampleBuffer); destroy_buffer_list(data->bufferList); @@ -614,7 +617,8 @@ static void ca_close_capture(ALCdevice *device) { ca_data *data = (ca_data*)device->ExtraData; - DestroyRingBuffer(data->ring); + ll_ringbuffer_free(data->ring); + data->ring = NULL; free(data->resampleBuffer); destroy_buffer_list(data->bufferList); @@ -676,7 +680,7 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa static ALCuint ca_available_samples(ALCdevice *device) { ca_data *data = device->ExtraData; - return RingBufferSize(data->ring) / data->sampleRateRatio; + return ll_ringbuffer_read_space(data->ring) / data->sampleRateRatio; } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index c01e42ae..68ac08f1 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -653,7 +653,8 @@ typedef struct ALCdsoundCapture { IDirectSoundCaptureBuffer *DSCbuffer; DWORD BufferBytes; DWORD Cursor; - RingBuffer *Ring; + + ll_ringbuffer_t *Ring; } ALCdsoundCapture; static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); @@ -823,7 +824,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi } if(SUCCEEDED(hr)) { - self->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates); + self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, + InputType.Format.nBlockAlign); if(self->Ring == NULL) hr = DSERR_OUTOFMEMORY; } @@ -832,7 +834,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi { ERR("Device init failed: 0x%08lx\n", hr); - DestroyRingBuffer(self->Ring); + ll_ringbuffer_free(self->Ring); self->Ring = NULL; if(self->DSCbuffer != NULL) IDirectSoundCaptureBuffer_Release(self->DSCbuffer); @@ -854,7 +856,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi static void ALCdsoundCapture_close(ALCdsoundCapture *self) { - DestroyRingBuffer(self->Ring); + ll_ringbuffer_free(self->Ring); self->Ring = NULL; if(self->DSCbuffer != NULL) @@ -897,7 +899,7 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self) static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - ReadRingBuffer(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring, buffer, samples); return ALC_NO_ERROR; } @@ -929,9 +931,9 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) } if(SUCCEEDED(hr)) { - WriteRingBuffer(self->Ring, ReadPtr1, ReadCnt1/FrameSize); + ll_ringbuffer_write(self->Ring, ReadPtr1, ReadCnt1/FrameSize); if(ReadPtr2 != NULL) - WriteRingBuffer(self->Ring, ReadPtr2, ReadCnt2/FrameSize); + ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize); hr = IDirectSoundCaptureBuffer_Unlock(self->DSCbuffer, ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); @@ -945,7 +947,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) } done: - return RingBufferSize(self->Ring); + return ll_ringbuffer_read_space(self->Ring); } diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 33d7750a..a61b4859 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -484,10 +484,7 @@ typedef struct ALCcaptureOSS { int fd; - ALubyte *read_data; - int data_size; - - RingBuffer *ring; + ll_ringbuffer_t *ring; int doCapture; volatile int killNow; @@ -517,7 +514,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) ALCcaptureOSS *self = (ALCcaptureOSS*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; int frameSize; - int amt; + ssize_t amt; SetRTPriority(); althrd_setname(althrd_current(), RECORD_THREAD_NAME); @@ -526,22 +523,31 @@ static int ALCcaptureOSS_recordProc(void *ptr) while(!self->killNow) { - amt = read(self->fd, self->read_data, self->data_size); - if(amt < 0) + ll_ringbuffer_data_t vec[2]; + + amt = 0; + if(self->doCapture) { - ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(self); - aluHandleDisconnect(device); - ALCcaptureOSS_unlock(self); - break; + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len > 0) + { + amt = read(self->fd, vec[0].buf, vec[0].len*frameSize); + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + ALCcaptureOSS_lock(self); + aluHandleDisconnect(device); + ALCcaptureOSS_unlock(self); + break; + } + ll_ringbuffer_write_advance(self->ring, amt/frameSize); + } } if(amt == 0) { al_nssleep(1000000); continue; } - if(self->doCapture) - WriteRingBuffer(self->ring, self->read_data, amt/frameSize); } return 0; @@ -657,7 +663,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize); if(!self->ring) { ERR("Ring buffer create failed\n"); @@ -666,13 +672,11 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - self->data_size = info.fragsize; - self->read_data = calloc(1, self->data_size); - self->killNow = 0; if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) { - device->ExtraData = NULL; + ll_ringbuffer_free(self->ring); + self->ring = NULL; close(self->fd); self->fd = -1; return ALC_OUT_OF_MEMORY; @@ -693,11 +697,8 @@ static void ALCcaptureOSS_close(ALCcaptureOSS *self) close(self->fd); self->fd = -1; - DestroyRingBuffer(self->ring); + ll_ringbuffer_free(self->ring); self->ring = NULL; - - free(self->read_data); - self->read_data = NULL; } static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) @@ -713,13 +714,13 @@ static void ALCcaptureOSS_stop(ALCcaptureOSS *self) static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) { - ReadRingBuffer(self->ring, buffer, samples); + ll_ringbuffer_read(self->ring, buffer, samples); return ALC_NO_ERROR; } static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self) { - return RingBufferSize(self->ring); + return ll_ringbuffer_read_space(self->ring); } diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 3508ec49..0085251d 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -430,7 +430,7 @@ typedef struct ALCwinmmCapture { HWAVEIN InHdl; - RingBuffer *Ring; + ll_ringbuffer_t *Ring; WAVEFORMATEX Format; @@ -514,8 +514,9 @@ static int ALCwinmmCapture_captureProc(void *arg) break; WaveHdr = ((WAVEHDR*)msg.lParam); - WriteRingBuffer(self->Ring, (ALubyte*)WaveHdr->lpData, - WaveHdr->dwBytesRecorded/self->Format.nBlockAlign); + ll_ringbuffer_write(self->Ring, WaveHdr->lpData, + WaveHdr->dwBytesRecorded / self->Format.nBlockAlign + ); // Send buffer back to capture more data waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); @@ -603,7 +604,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) CapturedDataSize = self->Format.nSamplesPerSec / 10; - self->Ring = CreateRingBuffer(self->Format.nBlockAlign, CapturedDataSize); + self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign); if(!self->Ring) goto failure; InitRef(&self->WaveBuffersCommitted, 0); @@ -644,8 +645,7 @@ failure: free(BufferData); } - if(self->Ring) - DestroyRingBuffer(self->Ring); + ll_ringbuffer_free(self->Ring); self->Ring = NULL; if(self->InHdl) @@ -678,7 +678,7 @@ static void ALCwinmmCapture_close(ALCwinmmCapture *self) } free(buffer); - DestroyRingBuffer(self->Ring); + ll_ringbuffer_free(self->Ring); self->Ring = NULL; // Close the Wave device @@ -699,13 +699,13 @@ static void ALCwinmmCapture_stop(ALCwinmmCapture *self) static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - ReadRingBuffer(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring, buffer, samples); return ALC_NO_ERROR; } static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - return RingBufferSize(self->Ring); + return ll_ringbuffer_read_space(self->Ring); } -- cgit v1.2.3 From b3e500be32bf65c3cdab5754e43a6ff955bed5b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Mar 2016 01:12:02 -0700 Subject: Remove the old ringbuffer implementation --- Alc/alcRing.c | 101 ---------------------------------------------- OpenAL32/Include/alMain.h | 7 ---- 2 files changed, 108 deletions(-) diff --git a/Alc/alcRing.c b/Alc/alcRing.c index 05db7bc3..5994f196 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -29,107 +29,6 @@ #include "compat.h" -struct RingBuffer { - ALubyte *mem; - - ALsizei frame_size; - ALsizei length; - ALint read_pos; - ALint write_pos; - - almtx_t mtx; -}; - - -RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length) -{ - RingBuffer *ring = calloc(1, sizeof(*ring) + ((length+1) * frame_size)); - if(ring) - { - ring->mem = (ALubyte*)(ring+1); - - ring->frame_size = frame_size; - ring->length = length+1; - ring->read_pos = 0; - ring->write_pos = 0; - - almtx_init(&ring->mtx, almtx_plain); - } - return ring; -} - -void DestroyRingBuffer(RingBuffer *ring) -{ - if(ring) - { - almtx_destroy(&ring->mtx); - free(ring); - } -} - -ALsizei RingBufferSize(RingBuffer *ring) -{ - ALsizei s; - - almtx_lock(&ring->mtx); - s = (ring->write_pos-ring->read_pos+ring->length) % ring->length; - almtx_unlock(&ring->mtx); - - return s; -} - -void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len) -{ - int remain; - - almtx_lock(&ring->mtx); - - remain = (ring->read_pos-ring->write_pos-1+ring->length) % ring->length; - if(remain < len) len = remain; - - if(len > 0) - { - remain = ring->length - ring->write_pos; - if(remain < len) - { - memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, - remain*ring->frame_size); - memcpy(ring->mem, data+(remain*ring->frame_size), - (len-remain)*ring->frame_size); - } - else - memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, - len*ring->frame_size); - - ring->write_pos += len; - ring->write_pos %= ring->length; - } - - almtx_unlock(&ring->mtx); -} - -void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len) -{ - int remain; - - almtx_lock(&ring->mtx); - - remain = ring->length - ring->read_pos; - if(remain < len) - { - memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size); - memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size); - } - else - memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size); - - ring->read_pos += len; - ring->read_pos %= ring->length; - - almtx_unlock(&ring->mtx); -} - - /* NOTE: This lockless ringbuffer implementation is copied from JACK, extended * to include an element size. Consequently, parameters and return values for a * size or count is in 'elements', not bytes. Additionally, it only supports diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 17edd7fc..60dc9fb1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -652,13 +652,6 @@ void SetMixerFPUMode(FPUCtl *ctl); void RestoreFPUMode(const FPUCtl *ctl); -typedef struct RingBuffer RingBuffer; -RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length); -void DestroyRingBuffer(RingBuffer *ring); -ALsizei RingBufferSize(RingBuffer *ring); -void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len); -void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len); - typedef struct ll_ringbuffer ll_ringbuffer_t; typedef struct ll_ringbuffer_data { char *buf; -- cgit v1.2.3 From df0d225dbffab6ee8793f8bfdeaaafea3bbf305c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Mar 2016 01:49:58 -0700 Subject: Properly make hq-mode default to off --- Alc/ALc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 43ec7cf9..f7749367 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2122,7 +2122,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(!device->Hrtf && !device->Uhj_Encoder && - GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 1)) + GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) { if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); -- cgit v1.2.3 From 2cd73a8d97da45eefbd4a0b7f0e82e2750519dca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Mar 2016 02:25:59 -0700 Subject: Allow dual-band decoders for basic rendering Since the basic renderer does not do frequency-dependent processing, the high- frequency matrix is used for panning. --- Alc/panning.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index b8ff3482..26c320ff 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -410,15 +410,9 @@ static bool LoadChannelSetup(ALCdevice *device) goto fail; } - /* TODO: Perhaps just use the high-frequency matrix, even if both are - * present? The recommendation seems to be to use an energy decode (rE, - * aka high-frequency) if frequency-dependent processing is not available. - */ if(conf.FreqBands != 1) - { - ERR("AmbDec layout file must be single-band (freq_bands = %u)\n", conf.FreqBands); - goto fail; - } + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf.XOverFreq); if(!MakeSpeakerMap(device, &conf, speakermap)) goto fail; -- cgit v1.2.3 From 93047e2a7a74030374c0a2f113c1a74f71f6fab4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 31 Mar 2016 02:14:13 -0700 Subject: Use the 3D panned output for reverb with HQ decoding This is less than ideal, but matching each reverb line to a speaker with surround sound output is way too loud without the ambient volume scaling offered by the "direct" panning. --- Alc/effects/reverb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 5ec5f6cf..2aea0763 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -387,7 +387,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev /* WARNING: This assumes the real output follows the virtual output in the * device's DryBuffer. */ - if(Device->Hrtf || Device->Uhj_Encoder || Device->AmbiDecoder) + if(Device->Hrtf || Device->Uhj_Encoder) State->ExtraChannels = ChannelsFromDevFmt(Device->FmtChans); else State->ExtraChannels = 0; @@ -957,12 +957,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf || Device->Uhj_Encoder || Device->AmbiDecoder) + if(Device->Hrtf || Device->Uhj_Encoder) UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, props->Reverb.LateReverbGain, State); - else if(Device->FmtChans == DevFmtBFormat3D) + else if(Device->FmtChans == DevFmtBFormat3D || Device->AmbiDecoder) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, -- cgit v1.2.3 From 8145a26d07fd1a99c8cf72b1d02650e0988232b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 31 Mar 2016 16:21:49 -0700 Subject: Add a hack to workaround erroneous prebuf values from pulse --- Alc/backends/pulseaudio.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 9ad04a71..ca8441aa 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1051,10 +1051,12 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) { /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ - device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency * - self->spec.rate + 0.5); + device->NumUpdates = (ALuint)clampd( + (ALdouble)device->NumUpdates/device->Frequency*self->spec.rate + 0.5, 2.0, 16.0 + ); + self->attr.minreq = device->UpdateSize * pa_frame_size(&self->spec); - self->attr.tlength = self->attr.minreq * clampu(device->NumUpdates, 2, 16); + self->attr.tlength = self->attr.minreq * device->NumUpdates; self->attr.maxlength = -1; self->attr.prebuf = 0; @@ -1069,10 +1071,31 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) ALCpulsePlayback_bufferAttrCallback(self->stream, self); len = self->attr.minreq / pa_frame_size(&self->spec); - device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5); - device->NumUpdates = clampu(device->NumUpdates, 2, 16); + device->NumUpdates = (ALuint)clampd( + (ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5, 2.0, 16.0 + ); device->UpdateSize = len; + /* HACK: prebuf should be 0 as that's what we set it to. However on some + * systems it comes back as non-0, so we have to make sure the device will + * write enough audio to start playback. The lack of manual start control + * may have unintended consequences, but it's better than not starting at + * all. + */ + if(self->attr.prebuf != 0) + { + len = self->attr.prebuf / pa_frame_size(&self->spec); + if(len <= device->UpdateSize*device->NumUpdates) + ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", + len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + else + { + ERR("Large prebuf, %u samples (%u bytes), increasing device from %u samples", + len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); + device->NumUpdates = (len+device->UpdateSize-1) / device->UpdateSize; + } + } + pa_threaded_mainloop_unlock(self->loop); return ALC_TRUE; } -- cgit v1.2.3 From 071f8a7b188a4e05b66a525e6f9d47f51b09223d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Apr 2016 19:35:03 -0700 Subject: Also disable ALSA's resampler when not requesting a sample rate --- Alc/backends/alsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 3a0ed205..805d66e3 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -773,11 +773,14 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0)) + if(!GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || + !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); } + else if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 1) < 0) + ERR("Failed to enable ALSA resampler\n"); CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL)); /* set buffer time (implicitly constrains period/buffer parameters) */ if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0) -- cgit v1.2.3 From e127072b41d64cd95f72572fe897fa8ec2f98ece Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Apr 2016 20:21:32 -0700 Subject: Use al_malloc/al_free for allocations --- Alc/backends/alsa.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 805d66e3..3b37f3ca 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -845,7 +845,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) self->size = snd_pcm_frames_to_bytes(self->pcmHandle, device->UpdateSize); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { - self->buffer = malloc(self->size); + self->buffer = al_malloc(16, self->size); if(!self->buffer) { ERR("buffer malloc failed\n"); @@ -867,7 +867,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) if(althrd_create(&self->thread, thread_func, self) != althrd_success) { ERR("Could not create playback thread\n"); - free(self->buffer); + al_free(self->buffer); self->buffer = NULL; return ALC_FALSE; } @@ -890,7 +890,7 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) self->killNow = 1; althrd_join(self->thread, &res); - free(self->buffer); + al_free(self->buffer); self->buffer = NULL; } @@ -1070,8 +1070,6 @@ error: if(hp) snd_pcm_hw_params_free(hp); error2: - free(self->buffer); - self->buffer = NULL; ll_ringbuffer_free(self->ring); self->ring = NULL; snd_pcm_close(self->pcmHandle); @@ -1084,7 +1082,7 @@ static void ALCcaptureAlsa_close(ALCcaptureAlsa *self) snd_pcm_close(self->pcmHandle); ll_ringbuffer_free(self->ring); - free(self->buffer); + al_free(self->buffer); self->buffer = NULL; } @@ -1119,11 +1117,11 @@ static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self) void *ptr; size = snd_pcm_frames_to_bytes(self->pcmHandle, avail); - ptr = malloc(size); + ptr = al_malloc(16, size); if(ptr) { ALCcaptureAlsa_captureSamples(self, ptr, avail); - free(self->buffer); + al_free(self->buffer); self->buffer = ptr; self->size = size; } @@ -1165,7 +1163,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff } else { - free(self->buffer); + al_free(self->buffer); self->buffer = NULL; self->size = 0; } -- cgit v1.2.3 From f7efa0aff74d50abd4329a110c452de292f1e1c8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Apr 2016 02:59:26 -0700 Subject: Avoid double slashes when constructing paths --- Alc/helpers.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index c8983c11..47851cf9 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -620,7 +620,8 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string AL_STRING_INIT(str); al_string_copy_cstr(&str, path); - al_string_append_char(&str, '/'); + if(VECTOR_BACK(str) != '/') + al_string_append_char(&str, '/'); al_string_append_cstr(&str, dirent->d_name); TRACE("Got result %s\n", al_string_get_cstr(str)); VECTOR_PUSH_BACK(*results, str); @@ -661,13 +662,19 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') { al_string_copy_cstr(&path, str); - al_string_append_char(&path, '/'); + if(VECTOR_BACK(path) != '/') + al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); DirectorySearch(al_string_get_cstr(path), ext, &results); } else if((str=getenv("HOME")) != NULL && str[0] != '\0') { al_string_copy_cstr(&path, str); + if(VECTOR_BACK(path) == '/') + { + VECTOR_POP_BACK(path); + *VECTOR_ITER_END(path) = 0; + } al_string_append_cstr(&path, "/.local/share/"); al_string_append_cstr(&path, subdir); DirectorySearch(al_string_get_cstr(path), ext, &results); @@ -690,7 +697,8 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) } if(!al_string_empty(path)) { - al_string_append_char(&path, '/'); + if(VECTOR_BACK(path) != '/') + al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); DirectorySearch(al_string_get_cstr(path), ext, &results); -- cgit v1.2.3 From a8101da95676f2f9541cb3fcdbcf66ddb16e913c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Apr 2016 00:52:08 -0700 Subject: Use the correct slot callback for the 6.1 and 7.1 decoder buttons --- utils/alsoft-config/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 53e2ffea..4d286367 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -321,9 +321,9 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoder51RearLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoder51RearButton, SIGNAL(clicked()), this, SLOT(select51RearDecoderFile())); connect(ui->decoder61LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select71DecoderFile())); + connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); connect(ui->decoder71LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder71Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); + connect(ui->decoder71Button, SIGNAL(clicked()), this, SLOT(select71DecoderFile())); connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); -- cgit v1.2.3 From 7bdd68ddbe896bc7d50a8a43ba093d66e1c0216e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Apr 2016 08:04:56 -0700 Subject: Use frequency-dependent processing for the ambisonic up-sampler --- Alc/bformatdec.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index e4c6da49..dd0561d0 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -114,6 +114,12 @@ static const ALfloat SquareMatrixHF[4][MAX_AMBI_COEFFS] = { { 0.353553f, 0.204094f, 0.0f, -0.204094f }, { 0.353553f, -0.204094f, 0.0f, -0.204094f }, }; +static const ALfloat SquareMatrixLF[4][MAX_AMBI_COEFFS] = { + { 0.25f, 0.204094f, 0.0f, 0.204094f }, + { 0.25f, -0.204094f, 0.0f, 0.204094f }, + { 0.25f, 0.204094f, 0.0f, -0.204094f }, + { 0.25f, -0.204094f, 0.0f, -0.204094f }, +}; static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS]; static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = { @@ -126,6 +132,16 @@ static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.25f, -0.14425f, -0.14425f, -0.14425f }, }; +static const ALfloat CubeMatrixLF[8][MAX_AMBI_COEFFS] = { + { 0.125f, 0.125f, 0.125f, 0.125f }, + { 0.125f, -0.125f, 0.125f, 0.125f }, + { 0.125f, 0.125f, 0.125f, -0.125f }, + { 0.125f, -0.125f, 0.125f, -0.125f }, + { 0.125f, 0.125f, -0.125f, 0.125f }, + { 0.125f, -0.125f, -0.125f, 0.125f }, + { 0.125f, 0.125f, -0.125f, -0.125f }, + { 0.125f, -0.125f, -0.125f, -0.125f }, +}; static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT; @@ -188,7 +204,10 @@ typedef struct BFormatDec { } Delay[MAX_OUTPUT_CHANNELS]; struct { + BandSplitter XOver[4]; + const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS]; + const ALfloat (*restrict MatrixLF)[MAX_AMBI_COEFFS]; const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; ALuint NumChannels; } UpSampler; @@ -251,8 +270,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, dec->SamplesLF = NULL; dec->NumChannels = chancount; - dec->Samples = al_calloc(16, dec->NumChannels * conf->FreqBands * - sizeof(dec->Samples[0])); + dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0])); dec->SamplesHF = dec->Samples; dec->SamplesLF = dec->SamplesHF + dec->NumChannels; @@ -266,9 +284,13 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(conf->CoeffScale == ADS_FuMa) coeff_scale = FuMa2N3DScale; + ratio = 400.0f / (ALfloat)srate; + for(i = 0;i < 4;i++) + bandsplit_init(&dec->UpSampler.XOver[i], ratio); if((conf->ChanMask & ~0x831b)) { dec->UpSampler.MatrixHF = CubeMatrixHF; + dec->UpSampler.MatrixLF = CubeMatrixLF; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder; dec->UpSampler.NumChannels = 8; dec->Periphonic = AL_TRUE; @@ -276,6 +298,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else { dec->UpSampler.MatrixHF = SquareMatrixHF; + dec->UpSampler.MatrixLF = SquareMatrixLF; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder; dec->UpSampler.NumChannels = 4; dec->Periphonic = AL_FALSE; @@ -510,6 +533,15 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B { ALuint i, j, k; + /* First, split the first-order components into low and high frequency + * bands. This assumes SamplesHF and SamplesLF have enough space for first- + * order content (to which, this up-sampler is only used with second-order + * or higher decoding, so it will). + */ + for(i = 0;i < InChannels;i++) + bandsplit_process(&dec->UpSampler.XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], + InSamples[i], SamplesToDo); + /* This up-sampler is very simplistic. It essentially decodes the first- * order content to a square channel array (or cube if height is desired), * then encodes those points onto the higher order soundfield. @@ -517,7 +549,9 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B for(k = 0;k < dec->UpSampler.NumChannels;k++) { memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - apply_row(dec->ChannelMix, dec->UpSampler.MatrixHF[k], InSamples, + apply_row(dec->ChannelMix, dec->UpSampler.MatrixHF[k], dec->SamplesHF, + InChannels, SamplesToDo); + apply_row(dec->ChannelMix, dec->UpSampler.MatrixLF[k], dec->SamplesLF, InChannels, SamplesToDo); for(j = 0;j < dec->NumChannels;j++) -- cgit v1.2.3 From 1faa7b536d46f9f085c697ddbbac1a3e4e8bb0df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Apr 2016 13:03:00 -0700 Subject: Fix xover_freq type in the ambdec doc --- alsoft_ambdec.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alsoft_ambdec.txt b/alsoft_ambdec.txt index 65965f3b..0afc5064 100644 --- a/alsoft_ambdec.txt +++ b/alsoft_ambdec.txt @@ -20,7 +20,7 @@ may be any amount of whitespace in between the option and parameter values. Strings are *not* enclosed in quotation marks. /description -Specifies a text description of the configuration. Ingored by OpenAL Soft. +Specifies a text description of the configuration. Ignored by OpenAL Soft. /version Declares the format version used by the configuration file. OpenAL Soft @@ -65,7 +65,7 @@ Specifies whether gain compensation is applied for output. This is used to correct for volume variations caused by different speaker distances. As OpenAL Soft has its own config option for this, this is ignored. -/opt/xover_freq +/opt/xover_freq Specifies the crossover frequency for dual-band decoders. Frequencies less than this are fed to the low-frequency matrix, and frequencies greater than this are fed to the high-freqyency matrix. Unused for single-band decoders. -- cgit v1.2.3 From 695cfa50b2729edea1d837ca3ce6540b9200487b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Apr 2016 13:06:36 -0700 Subject: Improve error trace for bad matrix definitions --- Alc/ambdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ambdec.c b/Alc/ambdec.c index 29bd4afa..255011d5 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -443,7 +443,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) const char *value = my_strtok_r(NULL, "/ \t", &saveptr); if(strcmp(value, "{") != 0) { - ERR("Expected { after speakers command, got %s\n", value); + ERR("Expected { after %s command, got %s\n", command, value); goto fail; } if(!load_ambdec_speakers(conf, f, &buffer, &maxlen, &saveptr)) @@ -471,7 +471,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) const char *value = my_strtok_r(NULL, "/ \t", &saveptr); if(strcmp(value, "{") != 0) { - ERR("Expected { after speakers command, got %s\n", value); + ERR("Expected { after %s command, got %s\n", command, value); goto fail; } if(conf->FreqBands == 1) -- cgit v1.2.3 From 38247e021a95ef7db368d385479090c6c98e2ba9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Apr 2016 13:48:26 -0700 Subject: Put the decoder options in a group box --- utils/alsoft-config/mainwindow.ui | 388 ++++++++++++++++++++------------------ 1 file changed, 202 insertions(+), 186 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index cb1df954..268b5ea9 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -593,200 +593,216 @@ configuration file. true - + - 140 - 100 - 281 - 21 - - - - - - - 11 + -10 100 - 121 - 21 - - - - Quadrophonic: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 140 - 130 - 281 - 21 - - - - - - - 140 - 160 - 281 - 21 - - - - - - - 140 - 190 - 281 - 21 - - - - - - - 140 - 220 - 281 - 21 - - - - - - - 10 - 130 - 121 - 21 - - - - 5.1 Surround (Side): - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 160 - 121 - 21 - - - - 5.1 Surround (Rear): - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 190 - 121 - 21 - - - - 6.1 Surround: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 220 - 121 - 21 + 551 + 191 - - 7.1 Surround: + + Decoder Configurations - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 430 - 100 - 91 - 21 - - - - Browse... - - - - - - 430 - 130 - 91 - 21 - - - - Browse... - - - - - - 430 - 160 - 91 - 21 - - - - Browse... - - - - - - 430 - 190 - 91 - 21 - - - - Browse... - - - - - - 430 - 220 - 91 - 21 - - - - Browse... + Qt::AlignCenter + + + + 150 + 30 + 281 + 21 + + + + + + + 20 + 30 + 121 + 21 + + + + Quadrophonic: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 440 + 30 + 91 + 21 + + + + Browse... + + + + + + 150 + 60 + 281 + 21 + + + + + + + 440 + 60 + 91 + 21 + + + + Browse... + + + + + + 20 + 60 + 121 + 21 + + + + 5.1 Surround (Side): + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 20 + 90 + 121 + 21 + + + + 5.1 Surround (Rear): + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 150 + 90 + 281 + 21 + + + + + + + 440 + 90 + 91 + 21 + + + + Browse... + + + + + + 20 + 120 + 121 + 21 + + + + 6.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 150 + 120 + 281 + 21 + + + + + + + 440 + 120 + 91 + 21 + + + + Browse... + + + + + + 440 + 150 + 91 + 21 + + + + Browse... + + + + + + 150 + 150 + 281 + 21 + + + + + + + 20 + 150 + 121 + 21 + + + + 7.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + -- cgit v1.2.3 From d924e3d6c4aa8cfbc29c5522e16b30f7adaed597 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Apr 2016 10:44:57 -0700 Subject: Split aluInitPanning into separate functions for HRTF or UHJ --- Alc/ALc.c | 7 +- Alc/ALu.c | 4 +- Alc/panning.c | 479 ++++++++++++++++++++++------------------------ OpenAL32/Include/alMain.h | 8 +- OpenAL32/Include/alu.h | 2 + 5 files changed, 248 insertions(+), 252 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f7749367..69bf1fd4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2132,7 +2132,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; } - aluInitPanning(device); + if(device->Hrtf) + aluInitHrtfPanning(device); + else if(device->Uhj_Encoder) + aluInitUhjPanning(device); + else + aluInitPanning(device); /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); diff --git a/Alc/ALu.c b/Alc/ALu.c index c83efce8..b679b3ca 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -551,9 +551,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A if(DirectChannels) { - /* Skip the virtual channels and write FrontLeft and FrontRight - * inputs to the real output. - */ + /* Skip the virtual channels and write inputs to the real output. */ voice->Direct.OutBuffer = Device->RealOut.Buffer; voice->Direct.OutChannels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) diff --git a/Alc/panning.c b/Alc/panning.c index 26c320ff..c037cafc 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -381,26 +381,18 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe static bool LoadChannelSetup(ALCdevice *device) { - ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; ALuint speakermap[MAX_OUTPUT_CHANNELS]; - const ALfloat *coeff_scale = UnitScale; - const char *layout = NULL; - ALfloat ambiscale = 1.0f; - const char *fname; + const char *fname = ""; + const char *devname; + const char *layout; AmbDecConf conf; ALuint i, j; - /* Don't use custom decoders with mono or stereo output (stereo is using - * UHJ or pair-wise panning, thus ignores the custom coefficients anyway, - * and mono would realistically only specify attenuation on the output). - */ - if(device->FmtChans == DevFmtMono || device->FmtChans == DevFmtStereo) - return false; - layout = GetChannelLayoutName(device->FmtChans); if(!layout) return false; - if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "decoder", layout, &fname)) + devname = al_string_get_cstr(device->DeviceName); + if(!ConfigValueStr(devname, "decoder", layout, &fname)) return false; ambdec_init(&conf); @@ -410,192 +402,23 @@ static bool LoadChannelSetup(ALCdevice *device) goto fail; } - if(conf.FreqBands != 1) - ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", - conf.XOverFreq); - - if(!MakeSpeakerMap(device, &conf, speakermap)) - goto fail; - - if(conf.ChanMask > 0x1ff) - ambiscale = THIRD_ORDER_SCALE; - else if(conf.ChanMask > 0xf) - ambiscale = SECOND_ORDER_SCALE; - else if(conf.ChanMask > 0x1) - ambiscale = FIRST_ORDER_SCALE; - else - ambiscale = 0.0f; - - if(conf.CoeffScale == ADS_SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf.CoeffScale == ADS_FuMa) - coeff_scale = FuMa2N3DScale; - - for(i = 0;i < conf.NumSpeakers;i++) + if(conf.ChanMask > 0xffff) { - ALuint chan = speakermap[i]; - ALfloat gain; - ALuint k = 0; - - for(j = 0;j < MAX_AMBI_COEFFS;j++) - chanmap[i].Config[j] = 0.0f; - - chanmap[i].ChanName = device->RealOut.ChannelName[chan]; - for(j = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf.HFOrderGain[0]; - else if(j == 1) gain = conf.HFOrderGain[1]; - else if(j == 4) gain = conf.HFOrderGain[2]; - else if(j == 9) gain = conf.HFOrderGain[3]; - if((conf.ChanMask&(1<Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, conf.NumSpeakers, - &device->Dry.NumChannels, AL_FALSE); - - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); - for(i = 0;i < device->Dry.NumChannels;i++) - { - device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; - for(j = 1;j < 4;j++) - device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); + goto fail; } - ambdec_deinit(&conf); - return true; - -fail: - ambdec_deinit(&conf); - return false; -} - -ALvoid aluInitPanning(ALCdevice *device) -{ - /* NOTE: These decoder coefficients are using FuMa channel ordering and - * normalization, since that's what was produced by the Ambisonic Decoder - * Toolbox. SetChannelMap will convert them to N3D. - */ - static const ChannelMap MonoCfg[1] = { - { FrontCenter, { 1.414213562f } }, - }, StereoCfg[2] = { - { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, - { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, - }, QuadCfg[4] = { - { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, - { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, - }, X51SideCfg[5] = { - { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, - { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, - { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, - { SideLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, - { SideRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, - }, X51RearCfg[5] = { - { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, - { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, - { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, - { BackLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, - { BackRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, - }, X61Cfg[6] = { - { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, - { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } }, - { SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } }, - { SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } }, - }, X71Cfg[7] = { - { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, - { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } }, - { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, - { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, - { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, - }, Cube8Cfg[8] = { - { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, - { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } }, - { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, - { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, - }, BFormat2D[3] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, - }, BFormat3D[4] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, - }; - const ChannelMap *chanmap = NULL; - ALfloat ambiscale; - size_t count = 0; - ALuint i, j; - - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; + if(!MakeSpeakerMap(device, &conf, speakermap)) + goto fail; - if(device->Hrtf) + if(device->AmbiDecoder && (conf.ChanMask & ~0x831b) && conf.ChanMask > 0x1ff) { - static const struct { - enum Channel Channel; - ALfloat Angle; - ALfloat Elevation; - } CubeInfo[8] = { - { UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) }, - { UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) }, - { UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) }, - { UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) }, - { LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) }, - { LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) }, - { LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) }, - { LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) }, - }; - - count = COUNTOF(Cube8Cfg); - chanmap = Cube8Cfg; - - for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); - - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); - - for(i = 0;i < device->Dry.NumChannels;i++) - { - int chan = GetChannelIdxByName(device->Dry, CubeInfo[i].Channel); - GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, - device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); - } - return; + ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", + conf.ChanMask); + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; } - if(device->Uhj_Encoder) - { - count = COUNTOF(BFormat2D); - chanmap = BFormat2D; - for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); - - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); - - return; - } if(device->AmbiDecoder) { /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ @@ -625,54 +448,14 @@ ALvoid aluInitPanning(ALCdevice *device) { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, }; - const char *devname = al_string_get_cstr(device->DeviceName); - ALuint speakermap[MAX_OUTPUT_CHANNELS]; - const char *fname = ""; - const char *layout; + const ChannelMap *chanmap = NULL; + const char *devname; int decflags = 0; - AmbDecConf conf; - - ambdec_init(&conf); - - /* Don't do HQ ambisonic decoding with mono or stereo output. Same - * reasons as in LoadChannelSetup. - */ - if(device->FmtChans == DevFmtMono || device->FmtChans == DevFmtStereo) - goto ambi_fail; - - layout = GetChannelLayoutName(device->FmtChans); - if(!layout) goto ambi_fail; - - if(!ConfigValueStr(devname, "decoder", layout, &fname)) - goto ambi_fail; - - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) - decflags |= BFDF_DistanceComp; - - if(!ambdec_load(&conf, fname)) - { - ERR("Failed to load %s\n", fname); - goto ambi_fail; - } - - if(conf.ChanMask > 0xffff) - { - ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); - goto ambi_fail; - } - - if(!MakeSpeakerMap(device, &conf, speakermap)) - goto ambi_fail; + size_t count; if((conf.ChanMask & ~0x831b)) { - if(conf.ChanMask > 0x1ff) - { - ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", - conf.ChanMask); - goto ambi_fail; - } - count = (conf.ChanMask > 0xf) ? 9 : 4; + count = (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? 16 : 9 : 4; chanmap = Ambi3D; } else @@ -681,6 +464,10 @@ ALvoid aluInitPanning(ALCdevice *device) chanmap = Ambi2D; } + devname = al_string_get_cstr(device->DeviceName); + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) + decflags |= BFDF_DistanceComp; + for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) @@ -695,7 +482,6 @@ ALvoid aluInitPanning(ALCdevice *device) ); bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, speakermap, decflags); - ambdec_deinit(&conf); if(bformatdec_getOrder(device->AmbiDecoder) < 2) memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, @@ -708,21 +494,163 @@ ALvoid aluInitPanning(ALCdevice *device) device->FOAOut.AmbiCoeffs[2][2] = 1.0f; device->FOAOut.AmbiCoeffs[3][3] = 1.0f; } + } + else + { + ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; + const ALfloat *coeff_scale = UnitScale; + ALfloat ambiscale = 1.0f; - return; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - ambi_fail: - ambdec_deinit(&conf); - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; + if(conf.FreqBands != 1) + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf.XOverFreq); + + if(conf.ChanMask > 0x1ff) + ambiscale = THIRD_ORDER_SCALE; + else if(conf.ChanMask > 0xf) + ambiscale = SECOND_ORDER_SCALE; + else if(conf.ChanMask > 0x1) + ambiscale = FIRST_ORDER_SCALE; + else + ambiscale = 0.0f; + + if(conf.CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf.CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; + + for(i = 0;i < conf.NumSpeakers;i++) + { + ALuint chan = speakermap[i]; + ALfloat gain; + ALuint k = 0; + + for(j = 0;j < MAX_AMBI_COEFFS;j++) + chanmap[i].Config[j] = 0.0f; + + chanmap[i].ChanName = device->RealOut.ChannelName[chan]; + for(j = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf.HFOrderGain[0]; + else if(j == 1) gain = conf.HFOrderGain[1]; + else if(j == 4) gain = conf.HFOrderGain[2]; + else if(j == 9) gain = conf.HFOrderGain[3]; + if((conf.ChanMask&(1<Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, + conf.NumSpeakers, &device->Dry.NumChannels, AL_FALSE); + + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; + for(j = 1;j < 4;j++) + device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + } + } + + ambdec_deinit(&conf); + return true; + +fail: + ambdec_deinit(&conf); + return false; +} + + +/* NOTE: These decoder coefficients are using FuMa channel ordering and + * normalization, since that's what was produced by the Ambisonic Decoder + * Toolbox. SetChannelMap will convert them to N3D. + */ +static const ChannelMap MonoCfg[1] = { + { FrontCenter, { 1.414213562f } }, +}, StereoCfg[2] = { + { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, + { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, +}, QuadCfg[4] = { + { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, +}, X51SideCfg[5] = { + { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, + { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, + { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, + { SideLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, + { SideRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, +}, X51RearCfg[5] = { + { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, + { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, + { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, + { BackLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, + { BackRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, +}, X61Cfg[6] = { + { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, + { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } }, + { SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } }, + { SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } }, +}, X71Cfg[7] = { + { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, + { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } }, + { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, + { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, + { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, +}, Cube8Cfg[8] = { + { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, + { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, + { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } }, + { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } }, + { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } }, + { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, + { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, + { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, +}, BFormat2D[3] = { + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, +}, BFormat3D[4] = { + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, +}; + +ALvoid aluInitPanning(ALCdevice *device) +{ + const ChannelMap *chanmap = NULL; + ALfloat ambiscale; + size_t count = 0; + ALuint i, j; + + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; + + /* Don't use custom decoders or HQ decoding with mono or stereo output. + * Mono only has one channel, and stereo doesn't have enough speakers to + * really be specified this way. + */ + if(device->FmtChans != DevFmtMono && device->FmtChans != DevFmtStereo) + { + if(LoadChannelSetup(device)) + return; } + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - if(LoadChannelSetup(device)) - return; - ambiscale = 1.0f; switch(device->FmtChans) { @@ -787,6 +715,67 @@ ALvoid aluInitPanning(ALCdevice *device) } } +ALvoid aluInitHrtfPanning(ALCdevice *device) +{ + static const struct { + enum Channel Channel; + ALfloat Angle; + ALfloat Elevation; + } CubeInfo[8] = { + { UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) }, + { UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) }, + { UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) }, + { UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) }, + { LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) }, + { LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) }, + { LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) }, + { LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) }, + }; + const ChannelMap *chanmap = Cube8Cfg; + size_t count = COUNTOF(Cube8Cfg); + ALuint i; + + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; + + for(i = 0;i < count;i++) + device->Dry.ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); + + for(i = 0;i < device->Dry.NumChannels;i++) + { + int chan = GetChannelIdxByName(device->Dry, CubeInfo[i].Channel); + GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, + device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); + } +} + +ALvoid aluInitUhjPanning(ALCdevice *device) +{ + const ChannelMap *chanmap = BFormat2D; + size_t count = COUNTOF(BFormat2D); + ALuint i; + + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; + + for(i = 0;i < count;i++) + device->Dry.ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); +} + void aluInitEffectPanning(ALeffectslot *slot) { static const ChannelMap FirstOrderN3D[4] = { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 60dc9fb1..909c42cd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -472,6 +472,8 @@ struct ALCdevice_struct al_string Hrtf_Name; const struct Hrtf *Hrtf; ALCenum Hrtf_Status; + + /* HRTF filter state for dry buffer content */ HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS]; HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS]; ALuint Hrtf_Offset; @@ -479,12 +481,12 @@ struct ALCdevice_struct /* UHJ encoder state */ struct Uhj2Encoder *Uhj_Encoder; - // Stereo-to-binaural filter - struct bs2b *Bs2b; - /* High quality Ambisonic decoder */ struct BFormatDec *AmbiDecoder; + // Stereo-to-binaural filter + struct bs2b *Bs2b; + /* Rendering mode. */ enum RenderMode Render_Mode; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 08f25204..a70daa46 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -281,6 +281,8 @@ inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat v void aluInitMixer(void); ALvoid aluInitPanning(ALCdevice *Device); +ALvoid aluInitHrtfPanning(ALCdevice *device); +ALvoid aluInitUhjPanning(ALCdevice *device); void aluInitEffectPanning(struct ALeffectslot *slot); -- cgit v1.2.3 From 221281688f29878eeacb6c87763d46d0ba27a1da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Apr 2016 14:24:52 -0700 Subject: Separate some long if-else blocks into a separate function --- Alc/ALc.c | 343 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 179 insertions(+), 164 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 69bf1fd4..b6e3aa9c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1654,6 +1654,173 @@ static inline void UpdateClockBase(ALCdevice *device) device->SamplesDone = 0; } +/* InitRenderer + * + * Set up the appropriate panning method and mixing method given the device + * properties. + */ +static void InitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) +{ + ALCenum hrtf_status; + const char *mode; + bool headphones; + int bs2blevel; + int usehrtf; + size_t i; + + device->Hrtf = NULL; + al_string_clear(&device->Hrtf_Name); + device->Render_Mode = NormalRender; + + if(device->FmtChans != DevFmtStereo) + { + if(hrtf_appreq == Hrtf_Enable) + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) + { + if(!device->AmbiDecoder) + device->AmbiDecoder = bformatdec_alloc(); + } + else + { + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + } + + aluInitPanning(device); + return; + } + + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + + hrtf_status = device->Hrtf_Status; + headphones = device->IsHeadphones; + + if(device->Type != Loopback) + { + const char *mode; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + { + if(strcasecmp(mode, "headphones") == 0) + headphones = true; + else if(strcasecmp(mode, "speakers") == 0) + headphones = false; + else if(strcasecmp(mode, "auto") != 0) + ERR("Unexpected stereo-mode: %s\n", mode); + } + } + + if(hrtf_userreq == Hrtf_Default) + { + usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(headphones && hrtf_appreq != Hrtf_Disable) + hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + else if(usehrtf) + hrtf_status = ALC_HRTF_ENABLED_SOFT; + } + else + { + usehrtf = (hrtf_userreq == Hrtf_Enable); + if(!usehrtf) + hrtf_status = ALC_HRTF_DENIED_SOFT; + else + hrtf_status = ALC_HRTF_REQUIRED_SOFT; + } + + if(!usehrtf) + { + device->Hrtf_Status = hrtf_status; + goto no_hrtf; + } + + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + if(VECTOR_SIZE(device->Hrtf_List) == 0) + { + VECTOR_DEINIT(device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + } + + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + } + } + + for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + } + } + + if(device->Hrtf) + { + device->Hrtf_Status = hrtf_status; + device->Render_Mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + { + if(strcasecmp(mode, "full") == 0) + device->Render_Mode = HrtfRender; + else if(strcasecmp(mode, "basic") == 0) + device->Render_Mode = NormalRender; + else + ERR("Unexpected hrtf-mode: %s\n", mode); + } + + TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); + aluInitHrtfPanning(device); + return; + } + +no_hrtf: + TRACE("HRTF disabled\n"); + + bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; + if(device->Type != Loopback) + ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + if(bs2blevel > 0 && bs2blevel <= 6) + { + device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); + bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + device->Render_Mode = StereoPair; + TRACE("BS2B enabled\n"); + aluInitPanning(device); + return; + } + + TRACE("BS2B disabled\n"); + + device->Render_Mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) + { + if(strcasecmp(mode, "paired") == 0) + device->Render_Mode = StereoPair; + else if(strcasecmp(mode, "uhj") != 0) + ERR("Unexpected stereo-panning: %s\n", mode); + } + if(device->Render_Mode == NormalRender) + { + device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + TRACE("UHJ enabled\n"); + aluInitUhjPanning(device); + return; + } + + TRACE("UHJ disabled\n"); + aluInitPanning(device); +} + /* UpdateDeviceParams * * Updates device parameters according to the attribute list (caller is @@ -1868,6 +2035,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); + /************************************************************************* + * Update device format request if HRTF is requested + */ device->Hrtf_Status = ALC_HRTF_DISABLED_SOFT; if(device->Type != Loopback) { @@ -1900,20 +2070,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } else { - hrtf_userreq = hrtf_appreq = Hrtf_Default; + hrtf_userreq = Hrtf_Default; + hrtf_appreq = Hrtf_Disable; device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } } else if(hrtf_appreq == Hrtf_Enable) { - size_t i; + size_t i = VECTOR_SIZE(device->Hrtf_List); /* Loopback device. We don't need to match to a specific HRTF entry * here. If the requested ID matches, we'll pick that later, if not, - * we'll try to auto-select one anyway. */ - if(device->FmtChans != DevFmtStereo) - i = VECTOR_SIZE(device->Hrtf_List); - else + * we'll try to auto-select one anyway. Just make sure one exists + * that'll work. + */ + if(device->FmtChans == DevFmtStereo) { if(VECTOR_SIZE(device->Hrtf_List) == 0) { @@ -1931,7 +2102,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ERR("Requested format not HRTF compatible: %s, %uhz\n", DevFmtChannelsString(device->FmtChans), device->Frequency); - hrtf_appreq = Hrtf_Default; + hrtf_appreq = Hrtf_Disable; device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } @@ -1981,163 +2152,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); } - device->Hrtf = NULL; - al_string_clear(&device->Hrtf_Name); - device->Render_Mode = NormalRender; - if(device->FmtChans != DevFmtStereo) - { - if(hrtf_appreq == Hrtf_Enable) - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - } - else - { - bool headphones = device->IsHeadphones; - enum RenderMode render_mode = HrtfRender; - ALCenum hrtf_status = device->Hrtf_Status; - const char *mode; - int bs2blevel; - int usehrtf; - - if(device->Type != Loopback) - { - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) - { - if(strcasecmp(mode, "headphones") == 0) - headphones = true; - else if(strcasecmp(mode, "speakers") == 0) - headphones = false; - else if(strcasecmp(mode, "auto") != 0) - ERR("Unexpected stereo-mode: %s\n", mode); - } - - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) - { - if(strcasecmp(mode, "full") == 0) - render_mode = HrtfRender; - else if(strcasecmp(mode, "basic") == 0) - render_mode = NormalRender; - else - ERR("Unexpected hrtf-mode: %s\n", mode); - } - } - - - if(hrtf_userreq == Hrtf_Default) - { - usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable); - if(headphones && hrtf_appreq != Hrtf_Disable) - hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; - else if(usehrtf) - hrtf_status = ALC_HRTF_ENABLED_SOFT; - } - else - { - usehrtf = (hrtf_userreq == Hrtf_Enable); - if(!usehrtf) - hrtf_status = ALC_HRTF_DENIED_SOFT; - else - hrtf_status = ALC_HRTF_REQUIRED_SOFT; - } - - if(!usehrtf) - device->Hrtf_Status = hrtf_status; - else - { - size_t i; - - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - if(VECTOR_SIZE(device->Hrtf_List) == 0) - { - VECTOR_DEINIT(device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); - } - - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) - { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) - { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); - } - } - if(!device->Hrtf) - { - for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++) - { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) - { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); - break; - } - } - } - } - if(device->Hrtf) - { - device->Hrtf_Status = hrtf_status; - device->Render_Mode = render_mode; - TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); - } - else - { - TRACE("HRTF disabled\n"); - - bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; - if(device->Type != Loopback) - ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); - if(bs2blevel > 0 && bs2blevel <= 6) - { - device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); - bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); - device->Render_Mode = StereoPair; - TRACE("BS2B enabled\n"); - } - else - { - TRACE("BS2B disabled\n"); - - render_mode = NormalRender; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) - { - if(strcasecmp(mode, "paired") == 0) - render_mode = StereoPair; - else if(strcasecmp(mode, "uhj") != 0) - ERR("Unexpected stereo-panning: %s\n", mode); - } - device->Render_Mode = render_mode; - if(render_mode == NormalRender) - { - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); - TRACE("UHJ enabled\n"); - } - else - TRACE("UHJ disabled\n"); - } - } - } - - if(!device->Hrtf && !device->Uhj_Encoder && - GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) - { - if(!device->AmbiDecoder) - device->AmbiDecoder = bformatdec_alloc(); - } - else - { - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - } - if(device->Hrtf) - aluInitHrtfPanning(device); - else if(device->Uhj_Encoder) - aluInitUhjPanning(device); - else - aluInitPanning(device); + InitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); -- cgit v1.2.3 From 65a9b97e46de9a1d0d81e0e32e3232bac24f14ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Apr 2016 15:25:12 -0700 Subject: Move the InitRenderer method to panning.c --- Alc/ALc.c | 187 ++----------------------------------------------- Alc/panning.c | 171 +++++++++++++++++++++++++++++++++++++++++++- OpenAL32/Include/alu.h | 16 ++++- 3 files changed, 187 insertions(+), 187 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b6e3aa9c..e9a3a887 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -35,10 +35,7 @@ #include "alBuffer.h" #include "alAuxEffectSlot.h" #include "alError.h" -#include "bs2b.h" -#include "uhjfilter.h" #include "bformatdec.h" -#include "ambdec.h" #include "alu.h" #include "compat.h" @@ -1409,11 +1406,6 @@ DECL_CONST static ALCboolean IsValidALCChannels(ALCenum channels) /************************************************ * Miscellaneous ALC helpers ************************************************/ -enum HrtfRequestMode { - Hrtf_Default = 0, - Hrtf_Enable = 1, - Hrtf_Disable = 2, -}; extern inline void LockContext(ALCcontext *context); extern inline void UnlockContext(ALCcontext *context); @@ -1654,173 +1646,6 @@ static inline void UpdateClockBase(ALCdevice *device) device->SamplesDone = 0; } -/* InitRenderer - * - * Set up the appropriate panning method and mixing method given the device - * properties. - */ -static void InitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) -{ - ALCenum hrtf_status; - const char *mode; - bool headphones; - int bs2blevel; - int usehrtf; - size_t i; - - device->Hrtf = NULL; - al_string_clear(&device->Hrtf_Name); - device->Render_Mode = NormalRender; - - if(device->FmtChans != DevFmtStereo) - { - if(hrtf_appreq == Hrtf_Enable) - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - - if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) - { - if(!device->AmbiDecoder) - device->AmbiDecoder = bformatdec_alloc(); - } - else - { - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - } - - aluInitPanning(device); - return; - } - - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - - hrtf_status = device->Hrtf_Status; - headphones = device->IsHeadphones; - - if(device->Type != Loopback) - { - const char *mode; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) - { - if(strcasecmp(mode, "headphones") == 0) - headphones = true; - else if(strcasecmp(mode, "speakers") == 0) - headphones = false; - else if(strcasecmp(mode, "auto") != 0) - ERR("Unexpected stereo-mode: %s\n", mode); - } - } - - if(hrtf_userreq == Hrtf_Default) - { - usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable); - if(headphones && hrtf_appreq != Hrtf_Disable) - hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; - else if(usehrtf) - hrtf_status = ALC_HRTF_ENABLED_SOFT; - } - else - { - usehrtf = (hrtf_userreq == Hrtf_Enable); - if(!usehrtf) - hrtf_status = ALC_HRTF_DENIED_SOFT; - else - hrtf_status = ALC_HRTF_REQUIRED_SOFT; - } - - if(!usehrtf) - { - device->Hrtf_Status = hrtf_status; - goto no_hrtf; - } - - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - if(VECTOR_SIZE(device->Hrtf_List) == 0) - { - VECTOR_DEINIT(device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); - } - - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) - { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) - { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); - } - } - - for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) - { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) - { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); - } - } - - if(device->Hrtf) - { - device->Hrtf_Status = hrtf_status; - device->Render_Mode = NormalRender; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) - { - if(strcasecmp(mode, "full") == 0) - device->Render_Mode = HrtfRender; - else if(strcasecmp(mode, "basic") == 0) - device->Render_Mode = NormalRender; - else - ERR("Unexpected hrtf-mode: %s\n", mode); - } - - TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); - aluInitHrtfPanning(device); - return; - } - -no_hrtf: - TRACE("HRTF disabled\n"); - - bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; - if(device->Type != Loopback) - ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); - if(bs2blevel > 0 && bs2blevel <= 6) - { - device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); - bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); - device->Render_Mode = StereoPair; - TRACE("BS2B enabled\n"); - aluInitPanning(device); - return; - } - - TRACE("BS2B disabled\n"); - - device->Render_Mode = NormalRender; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) - { - if(strcasecmp(mode, "paired") == 0) - device->Render_Mode = StereoPair; - else if(strcasecmp(mode, "uhj") != 0) - ERR("Unexpected stereo-panning: %s\n", mode); - } - if(device->Render_Mode == NormalRender) - { - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); - TRACE("UHJ enabled\n"); - aluInitUhjPanning(device); - return; - } - - TRACE("UHJ disabled\n"); - aluInitPanning(device); -} - /* UpdateDeviceParams * * Updates device parameters according to the attribute list (caller is @@ -2139,11 +1964,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Flags &= ~DEVICE_FREQUENCY_REQUEST; } - TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->NumUpdates - ); - if((device->UpdateSize&3) != 0) { if((CPUCapFlags&CPU_CAP_SSE)) @@ -2152,7 +1972,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); } - InitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); + TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); + + aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); diff --git a/Alc/panning.c b/Alc/panning.c index c037cafc..1b240a61 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -32,6 +32,8 @@ #include "bool.h" #include "ambdec.h" #include "bformatdec.h" +#include "uhjfilter.h" +#include "bs2b.h" extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]); @@ -625,7 +627,7 @@ static const ChannelMap MonoCfg[1] = { { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; -ALvoid aluInitPanning(ALCdevice *device) +static void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; ALfloat ambiscale; @@ -715,7 +717,7 @@ ALvoid aluInitPanning(ALCdevice *device) } } -ALvoid aluInitHrtfPanning(ALCdevice *device) +static void InitHrtfPanning(ALCdevice *device) { static const struct { enum Channel Channel; @@ -756,7 +758,7 @@ ALvoid aluInitHrtfPanning(ALCdevice *device) } } -ALvoid aluInitUhjPanning(ALCdevice *device) +static void InitUhjPanning(ALCdevice *device) { const ChannelMap *chanmap = BFormat2D; size_t count = COUNTOF(BFormat2D); @@ -776,6 +778,169 @@ ALvoid aluInitUhjPanning(ALCdevice *device) sizeof(device->FOAOut.AmbiCoeffs)); } +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) +{ + ALCenum hrtf_status; + const char *mode; + bool headphones; + int bs2blevel; + int usehrtf; + size_t i; + + device->Hrtf = NULL; + al_string_clear(&device->Hrtf_Name); + device->Render_Mode = NormalRender; + + if(device->FmtChans != DevFmtStereo) + { + if(hrtf_appreq == Hrtf_Enable) + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) + { + if(!device->AmbiDecoder) + device->AmbiDecoder = bformatdec_alloc(); + } + else + { + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + } + + InitPanning(device); + return; + } + + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + + hrtf_status = device->Hrtf_Status; + headphones = device->IsHeadphones; + + if(device->Type != Loopback) + { + const char *mode; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + { + if(strcasecmp(mode, "headphones") == 0) + headphones = true; + else if(strcasecmp(mode, "speakers") == 0) + headphones = false; + else if(strcasecmp(mode, "auto") != 0) + ERR("Unexpected stereo-mode: %s\n", mode); + } + } + + if(hrtf_userreq == Hrtf_Default) + { + usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(headphones && hrtf_appreq != Hrtf_Disable) + hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + else if(usehrtf) + hrtf_status = ALC_HRTF_ENABLED_SOFT; + } + else + { + usehrtf = (hrtf_userreq == Hrtf_Enable); + if(!usehrtf) + hrtf_status = ALC_HRTF_DENIED_SOFT; + else + hrtf_status = ALC_HRTF_REQUIRED_SOFT; + } + + if(!usehrtf) + { + device->Hrtf_Status = hrtf_status; + goto no_hrtf; + } + + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + if(VECTOR_SIZE(device->Hrtf_List) == 0) + { + VECTOR_DEINIT(device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + } + + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + } + } + + for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + } + } + + if(device->Hrtf) + { + device->Hrtf_Status = hrtf_status; + device->Render_Mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + { + if(strcasecmp(mode, "full") == 0) + device->Render_Mode = HrtfRender; + else if(strcasecmp(mode, "basic") == 0) + device->Render_Mode = NormalRender; + else + ERR("Unexpected hrtf-mode: %s\n", mode); + } + + TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); + InitHrtfPanning(device); + return; + } + +no_hrtf: + TRACE("HRTF disabled\n"); + + bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; + if(device->Type != Loopback) + ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + if(bs2blevel > 0 && bs2blevel <= 6) + { + device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); + bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + device->Render_Mode = StereoPair; + TRACE("BS2B enabled\n"); + InitPanning(device); + return; + } + + TRACE("BS2B disabled\n"); + + device->Render_Mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) + { + if(strcasecmp(mode, "paired") == 0) + device->Render_Mode = StereoPair; + else if(strcasecmp(mode, "uhj") != 0) + ERR("Unexpected stereo-panning: %s\n", mode); + } + if(device->Render_Mode == NormalRender) + { + device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + TRACE("UHJ enabled\n"); + InitUhjPanning(device); + return; + } + + TRACE("UHJ disabled\n"); + InitPanning(device); +} + + void aluInitEffectPanning(ALeffectslot *slot) { static const ChannelMap FirstOrderN3D[4] = { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a70daa46..81f1cb77 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -278,11 +278,21 @@ inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat v } +enum HrtfRequestMode { + Hrtf_Default = 0, + Hrtf_Enable = 1, + Hrtf_Disable = 2, +}; + + void aluInitMixer(void); -ALvoid aluInitPanning(ALCdevice *Device); -ALvoid aluInitHrtfPanning(ALCdevice *device); -ALvoid aluInitUhjPanning(ALCdevice *device); +/* aluInitRenderer + * + * Set up the appropriate panning method and mixing method given the device + * properties. + */ +void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq); void aluInitEffectPanning(struct ALeffectslot *slot); -- cgit v1.2.3 From 21921cdaffbd6f66a8cdc452925ca407b830c406 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Apr 2016 16:42:32 -0700 Subject: Prepare the custom decoder in aluInitRenderer --- Alc/panning.c | 393 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 193 insertions(+), 200 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 1b240a61..fb707b2e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -381,190 +381,6 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe return true; } -static bool LoadChannelSetup(ALCdevice *device) -{ - ALuint speakermap[MAX_OUTPUT_CHANNELS]; - const char *fname = ""; - const char *devname; - const char *layout; - AmbDecConf conf; - ALuint i, j; - - layout = GetChannelLayoutName(device->FmtChans); - if(!layout) return false; - - devname = al_string_get_cstr(device->DeviceName); - if(!ConfigValueStr(devname, "decoder", layout, &fname)) - return false; - - ambdec_init(&conf); - if(!ambdec_load(&conf, fname)) - { - ERR("Failed to load layout file %s\n", fname); - goto fail; - } - - if(conf.ChanMask > 0xffff) - { - ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); - goto fail; - } - - if(!MakeSpeakerMap(device, &conf, speakermap)) - goto fail; - - if(device->AmbiDecoder && (conf.ChanMask & ~0x831b) && conf.ChanMask > 0x1ff) - { - ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", - conf.ChanMask); - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - } - - if(device->AmbiDecoder) - { - /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ - static const ChannelMap Ambi3D[9] = { - /* Zeroth order */ - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* First order */ - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Second order */ - { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, - }, Ambi2D[7] = { - /* Zeroth order */ - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* First order */ - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Second order */ - { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Third order */ - { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, - }; - const ChannelMap *chanmap = NULL; - const char *devname; - int decflags = 0; - size_t count; - - if((conf.ChanMask & ~0x831b)) - { - count = (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? 16 : 9 : 4; - chanmap = Ambi3D; - } - else - { - count = (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? 7 : 5 : 3; - chanmap = Ambi2D; - } - - devname = al_string_get_cstr(device->DeviceName); - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) - decflags |= BFDF_DistanceComp; - - for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_FALSE); - - TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", - (conf.FreqBands == 1) ? "single" : "dual", - (conf.ChanMask > 0xf) ? (conf.ChanMask > 0x1ff) ? "third" : "second" : "first", - (conf.ChanMask & ~0x831b) ? " periphonic" : "" - ); - bformatdec_reset(device->AmbiDecoder, &conf, count, device->Frequency, - speakermap, decflags); - - if(bformatdec_getOrder(device->AmbiDecoder) < 2) - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); - else - { - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); - device->FOAOut.AmbiCoeffs[0][0] = 1.0f; - device->FOAOut.AmbiCoeffs[1][1] = 1.0f; - device->FOAOut.AmbiCoeffs[2][2] = 1.0f; - device->FOAOut.AmbiCoeffs[3][3] = 1.0f; - } - } - else - { - ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; - const ALfloat *coeff_scale = UnitScale; - ALfloat ambiscale = 1.0f; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - - if(conf.FreqBands != 1) - ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", - conf.XOverFreq); - - if(conf.ChanMask > 0x1ff) - ambiscale = THIRD_ORDER_SCALE; - else if(conf.ChanMask > 0xf) - ambiscale = SECOND_ORDER_SCALE; - else if(conf.ChanMask > 0x1) - ambiscale = FIRST_ORDER_SCALE; - else - ambiscale = 0.0f; - - if(conf.CoeffScale == ADS_SN3D) - coeff_scale = SN3D2N3DScale; - else if(conf.CoeffScale == ADS_FuMa) - coeff_scale = FuMa2N3DScale; - - for(i = 0;i < conf.NumSpeakers;i++) - { - ALuint chan = speakermap[i]; - ALfloat gain; - ALuint k = 0; - - for(j = 0;j < MAX_AMBI_COEFFS;j++) - chanmap[i].Config[j] = 0.0f; - - chanmap[i].ChanName = device->RealOut.ChannelName[chan]; - for(j = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf.HFOrderGain[0]; - else if(j == 1) gain = conf.HFOrderGain[1]; - else if(j == 4) gain = conf.HFOrderGain[2]; - else if(j == 9) gain = conf.HFOrderGain[3]; - if((conf.ChanMask&(1<Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, - conf.NumSpeakers, &device->Dry.NumChannels, AL_FALSE); - - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); - for(i = 0;i < device->Dry.NumChannels;i++) - { - device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; - for(j = 1;j < 4;j++) - device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; - } - } - - ambdec_deinit(&conf); - return true; - -fail: - ambdec_deinit(&conf); - return false; -} - /* NOTE: These decoder coefficients are using FuMa channel ordering and * normalization, since that's what was produced by the Ambisonic Decoder @@ -637,19 +453,6 @@ static void InitPanning(ALCdevice *device) memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); device->Dry.NumChannels = 0; - /* Don't use custom decoders or HQ decoding with mono or stereo output. - * Mono only has one channel, and stereo doesn't have enough speakers to - * really be specified this way. - */ - if(device->FmtChans != DevFmtMono && device->FmtChans != DevFmtStereo) - { - if(LoadChannelSetup(device)) - return; - } - - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; @@ -717,6 +520,151 @@ static void InitPanning(ALCdevice *device) } } +static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS]) +{ + ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; + const ALfloat *coeff_scale = UnitScale; + ALfloat ambiscale = 1.0f; + ALuint i, j; + + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; + + if(conf->FreqBands != 1) + ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", + conf->XOverFreq); + + if(conf->ChanMask > 0x1ff) + ambiscale = THIRD_ORDER_SCALE; + else if(conf->ChanMask > 0xf) + ambiscale = SECOND_ORDER_SCALE; + else if(conf->ChanMask > 0x1) + ambiscale = FIRST_ORDER_SCALE; + else + ambiscale = 0.0f; + + if(conf->CoeffScale == ADS_SN3D) + coeff_scale = SN3D2N3DScale; + else if(conf->CoeffScale == ADS_FuMa) + coeff_scale = FuMa2N3DScale; + + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = speakermap[i]; + ALfloat gain; + ALuint k = 0; + + for(j = 0;j < MAX_AMBI_COEFFS;j++) + chanmap[i].Config[j] = 0.0f; + + chanmap[i].ChanName = device->RealOut.ChannelName[chan]; + for(j = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 4) gain = conf->HFOrderGain[2]; + else if(j == 9) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<HFMatrix[i][k++] / coeff_scale[j] * gain; + } + } + + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, + conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); + + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; + for(j = 1;j < 4;j++) + device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + } +} + +static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS]) +{ + /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ + static const ChannelMap Ambi3D[9] = { + /* Zeroth order */ + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* First order */ + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Second order */ + { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f } }, + { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, + { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, + { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, + }, Ambi2D[7] = { + /* Zeroth order */ + { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* First order */ + { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Second order */ + { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + /* Third order */ + { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, + { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, + }; + const ChannelMap *chanmap = NULL; + const char *devname; + int decflags = 0; + size_t count; + ALuint i; + + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.NumChannels = 0; + + if((conf->ChanMask & ~0x831b)) + { + count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 16 : 9 : 4; + chanmap = Ambi3D; + } + else + { + count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 7 : 5 : 3; + chanmap = Ambi2D; + } + + devname = al_string_get_cstr(device->DeviceName); + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) + decflags |= BFDF_DistanceComp; + + for(i = 0;i < count;i++) + device->Dry.ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = InvalidChannel; + SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + &device->Dry.NumChannels, AL_FALSE); + + TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", + (conf->FreqBands == 1) ? "single" : "dual", + (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", + (conf->ChanMask & ~0x831b) ? " periphonic" : "" + ); + bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, + speakermap, decflags); + + if(bformatdec_getOrder(device->AmbiDecoder) < 2) + memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, + sizeof(device->FOAOut.AmbiCoeffs)); + else + { + memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + device->FOAOut.AmbiCoeffs[0][0] = 1.0f; + device->FOAOut.AmbiCoeffs[1][1] = 1.0f; + device->FOAOut.AmbiCoeffs[2][2] = 1.0f; + device->FOAOut.AmbiCoeffs[3][3] = 1.0f; + } +} + static void InitHrtfPanning(ALCdevice *device) { static const struct { @@ -793,12 +741,50 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->FmtChans != DevFmtStereo) { + ALuint speakermap[MAX_OUTPUT_CHANNELS]; + const char *devname, *layout; + AmbDecConf conf, *pconf; + if(hrtf_appreq == Hrtf_Enable) device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "decoder", "hq-mode", 0)) + pconf = NULL; + ambdec_init(&conf); + + devname = al_string_get_cstr(device->DeviceName); + layout = NULL; + if(device->FmtChans != DevFmtMono) + layout = GetChannelLayoutName(device->FmtChans); + if(layout) { - if(!device->AmbiDecoder) + const char *fname; + if(ConfigValueStr(devname, "decoder", layout, &fname)) + { + if(!ambdec_load(&conf, fname)) + ERR("Failed to load layout file %s\n", fname); + else + { + if(conf.ChanMask > 0xffff) + ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); + else + { + if(MakeSpeakerMap(device, &conf, speakermap)) + pconf = &conf; + } + } + } + } + + if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) + { + if((conf.ChanMask & ~0x831b) && conf.ChanMask > 0x1ff) + { + ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", + conf.ChanMask); + bformatdec_free(device->AmbiDecoder); + device->AmbiDecoder = NULL; + } + else if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); } else @@ -807,7 +793,14 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->AmbiDecoder = NULL; } - InitPanning(device); + if(!pconf) + InitPanning(device); + else if(device->AmbiDecoder) + InitHQPanning(device, pconf, speakermap); + else + InitCustomPanning(device, pconf, speakermap); + + ambdec_deinit(&conf); return; } -- cgit v1.2.3 From fb97822d8c3e8a3f712099a2ecfcf0ec5a43c32e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Apr 2016 21:50:36 -0700 Subject: Avoid unnecessary loops for setting up effect slot b-format buffer mixing --- Alc/ALu.c | 24 +++++++++++------------ Alc/panning.c | 40 ++++++++++++++++++++++++++------------ OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/Include/alMain.h | 4 ++++ OpenAL32/Include/alu.h | 2 ++ 5 files changed, 47 insertions(+), 25 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index b679b3ca..5823bd5f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -537,8 +537,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A for(c = 0;c < num_channels;c++) { const ALeffectslot *Slot = SendSlots[i]; - ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c], - WetGain[i], voice->Send[i].Gains[c].Target); + ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], + WetGain[i], voice->Send[i].Gains[c].Target); } } } @@ -579,8 +579,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } @@ -636,8 +636,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } @@ -697,8 +697,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[c].Target); } } } @@ -1136,8 +1136,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[0].Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[0].Target); } } @@ -1198,8 +1198,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[0].Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i], voice->Send[i].Gains[0].Target); } } diff --git a/Alc/panning.c b/Alc/panning.c index fb707b2e..9248bb86 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -179,6 +179,16 @@ void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const gains[i] = 0.0f; } +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALuint i; + + for(i = 0;i < numchans;i++) + gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; @@ -194,6 +204,16 @@ void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, co gains[i] = 0.0f; } +void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALuint i; + + for(i = 0;i < numchans;i++) + gains[i] = chanmap[i].Scale * mtx[chanmap[i].Index] * ingain; + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) { @@ -936,19 +956,15 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { - static const ChannelMap FirstOrderN3D[4] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, - }; - static const enum Channel AmbiChannels[MAX_OUTPUT_CHANNELS] = { - Aux0, Aux1, Aux2, Aux3, InvalidChannel - }; + ALuint i; - memset(slot->AmbiCoeffs, 0, sizeof(slot->AmbiCoeffs)); + memset(slot->ChanMap, 0, sizeof(slot->ChanMap)); slot->NumChannels = 0; - SetChannelMap(AmbiChannels, slot->AmbiCoeffs, FirstOrderN3D, COUNTOF(FirstOrderN3D), - &slot->NumChannels, AL_FALSE); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + slot->ChanMap[i].Scale = 1.0f; + slot->ChanMap[i].Index = i; + } + slot->NumChannels = i; } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 2c9a83e5..7c939efb 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -86,7 +86,7 @@ typedef struct ALeffectslot { ALuint id; ALuint NumChannels; - ChannelConfig AmbiCoeffs[MAX_EFFECT_CHANNELS]; + BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS]; /* Wet buffer configuration is ACN channel order with N3D scaling: * * Channel 0 is the unattenuated mono signal. * * Channel 1 is OpenAL -X diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 909c42cd..9ba6d050 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -407,6 +407,10 @@ enum RenderMode { #define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; +typedef struct BFChannelConfig { + ALfloat Scale; + ALuint Index; +} BFChannelConfig; #define HRTF_HISTORY_BITS (6) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 81f1cb77..2869722b 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -338,6 +338,7 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo * pre-calculated direction or angle coefficients. */ void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeFirstOrderGains @@ -347,6 +348,7 @@ void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const * orient the sound samples. */ void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); ALvoid UpdateContextSources(ALCcontext *context); -- cgit v1.2.3 From d5e624391ba712779e41f2719b47bbbaca588b50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 10:50:46 -0700 Subject: Update a comment --- OpenAL32/Include/alAuxEffectSlot.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 7c939efb..e521ff82 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -94,8 +94,8 @@ typedef struct ALeffectslot { * * Channel 3 is OpenAL -Z * Consequently, effects that only want to work with mono input can use * channel 0 by itself. Effects that want multichannel can process the - * ambisonics signal and create a B-Format pan (ComputeBFormatGains) for - * the device output. + * ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for + * first-order device output (FOAOut). */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALeffectslot; -- cgit v1.2.3 From f4ff5fc106f39ad30cdf72eade4bade649777a85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 12:22:54 -0700 Subject: Shorten VECTOR_ITER_ macros to VECTOR_ --- Alc/backends/alsa.c | 19 ++++++++----------- Alc/backends/dsound.c | 6 +++--- Alc/backends/mmdevapi.c | 6 +++--- Alc/backends/pulseaudio.c | 12 ++++++------ Alc/backends/qsa.c | 4 ++-- Alc/backends/winmm.c | 12 ++++++------ Alc/helpers.c | 42 +++++++++++++++++++++--------------------- Alc/hrtf.c | 6 +++--- Alc/vector.h | 20 ++++++++++---------- OpenAL32/alAuxEffectSlot.c | 6 +++--- 10 files changed, 65 insertions(+), 68 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 3b37f3ca..7d23ecc3 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -237,16 +237,13 @@ static vector_DevMap CaptureDevices; static void clear_devlist(vector_DevMap *devlist) { - DevMap *iter, *end; - - iter = VECTOR_ITER_BEGIN(*devlist); - end = VECTOR_ITER_END(*devlist); - for(;iter != end;iter++) - { - AL_STRING_DEINIT(iter->name); - AL_STRING_DEINIT(iter->device_name); - } +#define FREE_DEV(i) do { \ + AL_STRING_DEINIT((i)->name); \ + AL_STRING_DEINIT((i)->device_name); \ +} while(0) + VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV); VECTOR_RESIZE(*devlist, 0); +#undef FREE_DEV } @@ -635,7 +632,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(PlaybackDevices)) + if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; driver = al_string_get_cstr(iter->device_name); } @@ -969,7 +966,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(CaptureDevices)) + if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; driver = al_string_get_cstr(iter->device_name); } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 68ac08f1..454f7fa0 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -156,7 +156,7 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA #define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(*devices)) break; + if(iter == VECTOR_END(*devices)) break; #undef MATCH_ENTRY count++; } @@ -351,7 +351,7 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(PlaybackDevices)) + if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; guid = &iter->guid; } @@ -712,7 +712,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(CaptureDevices)) + if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; guid = &iter->guid; } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index c47ddee6..8851678b 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -211,7 +211,7 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) #define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(*list)) break; + if(iter == VECTOR_END(*list)) break; #undef MATCH_ENTRY count++; } @@ -696,7 +696,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi hr = E_FAIL; #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); - if(iter == VECTOR_ITER_END(PlaybackDevices)) + if(iter == VECTOR_END(PlaybackDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); else { @@ -1332,7 +1332,7 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device hr = E_FAIL; #define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); - if(iter == VECTOR_ITER_END(CaptureDevices)) + if(iter == VECTOR_END(CaptureDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); else { diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index ca8441aa..ccce2e00 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -527,7 +527,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME); - if(iter != VECTOR_ITER_END(PlaybackDevices)) return; + if(iter != VECTOR_END(PlaybackDevices)) return; #undef MATCH_INFO_NAME AL_STRING_INIT(entry.name); @@ -548,7 +548,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p #define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(PlaybackDevices)) break; + if(iter == VECTOR_END(PlaybackDevices)) break; #undef MATCH_ENTRY count++; } @@ -861,7 +861,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name #define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(PlaybackDevices)) + if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; pulse_name = al_string_get_cstr(iter->device_name); dev_name = iter->name; @@ -1247,7 +1247,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME); - if(iter != VECTOR_ITER_END(CaptureDevices)) return; + if(iter != VECTOR_END(CaptureDevices)) return; #undef MATCH_INFO_NAME AL_STRING_INIT(entry.name); @@ -1268,7 +1268,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa #define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(CaptureDevices)) break; + if(iter == VECTOR_END(CaptureDevices)) break; #undef MATCH_ENTRY count++; } @@ -1439,7 +1439,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) #define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME - if(iter == VECTOR_ITER_END(CaptureDevices)) + if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; pulse_name = al_string_get_cstr(iter->device_name); al_string_copy(&device->DeviceName, iter->name); diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 291e49fc..a1fbce63 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -277,7 +277,7 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName) #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); #undef MATCH_DEVNAME - if(iter == VECTOR_ITER_END(DeviceNameMap)) + if(iter == VECTOR_END(DeviceNameMap)) { free(data); return ALC_INVALID_DEVICE; @@ -624,7 +624,7 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) #define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); #undef MATCH_DEVNAME - if(iter == VECTOR_ITER_END(CaptureNameMap)) + if(iter == VECTOR_END(CaptureNameMap)) { free(data); return ALC_INVALID_DEVICE; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 0085251d..664b3dfe 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -83,7 +83,7 @@ static void ProbePlaybackDevices(void) #define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(PlaybackDevices)) break; + if(iter == VECTOR_END(PlaybackDevices)) break; #undef MATCH_ENTRY } @@ -126,7 +126,7 @@ static void ProbeCaptureDevices(void) #define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); - if(iter == VECTOR_ITER_END(CaptureDevices)) break; + if(iter == VECTOR_END(CaptureDevices)) break; #undef MATCH_ENTRY } @@ -258,11 +258,11 @@ static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *devi #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \ (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0)) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); - if(iter == VECTOR_ITER_END(PlaybackDevices)) + if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); + DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); retry_open: memset(&self->Format, 0, sizeof(WAVEFORMATEX)); @@ -544,11 +544,11 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) // Find the Device ID matching the deviceName if valid #define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0)) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); - if(iter == VECTOR_ITER_END(CaptureDevices)) + if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); + DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); switch(device->FmtChans) { diff --git a/Alc/helpers.c b/Alc/helpers.c index 47851cf9..950a67bf 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -456,7 +456,7 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string FindClose(hdl); if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, sizeof(VECTOR_FRONT(*results)), StringSortCompare); } @@ -501,7 +501,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) if(is_slash(VECTOR_BACK(path))) { VECTOR_POP_BACK(path); - *VECTOR_ITER_END(path) = 0; + *VECTOR_END(path) = 0; } } else if(!(cwdbuf=_wgetcwd(NULL, 0))) @@ -512,7 +512,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) if(is_slash(VECTOR_BACK(path))) { VECTOR_POP_BACK(path); - *VECTOR_ITER_END(path) = 0; + *VECTOR_END(path) = 0; } free(cwdbuf); } @@ -629,8 +629,8 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string closedir(dir); if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); + qsort(VECTOR_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } } @@ -673,7 +673,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) if(VECTOR_BACK(path) == '/') { VECTOR_POP_BACK(path); - *VECTOR_ITER_END(path) = 0; + *VECTOR_END(path) = 0; } al_string_append_cstr(&path, "/.local/share/"); al_string_append_cstr(&path, subdir); @@ -826,7 +826,7 @@ void al_string_clear(al_string *str) */ VECTOR_RESERVE(*str, 1); VECTOR_RESIZE(*str, 0); - *VECTOR_ITER_END(*str) = 0; + *VECTOR_END(*str) = 0; } } @@ -858,8 +858,8 @@ void al_string_copy(al_string *str, const_al_string from) size_t len = al_string_length(from); VECTOR_RESERVE(*str, len+1); VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len); - *VECTOR_ITER_END(*str) = 0; + VECTOR_INSERT(*str, VECTOR_END(*str), VECTOR_BEGIN(from), VECTOR_BEGIN(from)+len); + *VECTOR_END(*str) = 0; } void al_string_copy_cstr(al_string *str, const al_string_char_type *from) @@ -867,8 +867,8 @@ void al_string_copy_cstr(al_string *str, const al_string_char_type *from) size_t len = strlen(from); VECTOR_RESERVE(*str, len+1); VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; + VECTOR_INSERT(*str, VECTOR_END(*str), from, from+len); + *VECTOR_END(*str) = 0; } void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) @@ -876,15 +876,15 @@ void al_string_copy_range(al_string *str, const al_string_char_type *from, const size_t len = to - from; VECTOR_RESERVE(*str, len+1); VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to); - *VECTOR_ITER_END(*str) = 0; + VECTOR_INSERT(*str, VECTOR_END(*str), from, to); + *VECTOR_END(*str) = 0; } void al_string_append_char(al_string *str, const al_string_char_type c) { VECTOR_RESERVE(*str, al_string_length(*str)+2); VECTOR_PUSH_BACK(*str, c); - *VECTOR_ITER_END(*str) = 0; + *VECTOR_END(*str) = 0; } void al_string_append_cstr(al_string *str, const al_string_char_type *from) @@ -893,8 +893,8 @@ void al_string_append_cstr(al_string *str, const al_string_char_type *from) if(len != 0) { VECTOR_RESERVE(*str, al_string_length(*str)+len+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; + VECTOR_INSERT(*str, VECTOR_END(*str), from, from+len); + *VECTOR_END(*str) = 0; } } @@ -903,8 +903,8 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con if(to != from) { VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to); - *VECTOR_ITER_END(*str) = 0; + VECTOR_INSERT(*str, VECTOR_END(*str), from, to); + *VECTOR_END(*str) = 0; } } @@ -917,7 +917,7 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from) VECTOR_RESERVE(*str, len); VECTOR_RESIZE(*str, len-1); WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + *VECTOR_END(*str) = 0; } } @@ -930,7 +930,7 @@ void al_string_append_wcstr(al_string *str, const wchar_t *from) VECTOR_RESERVE(*str, strlen+len); VECTOR_RESIZE(*str, strlen+len-1); WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + *VECTOR_END(*str) = 0; } } @@ -943,7 +943,7 @@ void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t VECTOR_RESERVE(*str, strlen+len+1); VECTOR_RESIZE(*str, strlen+len); WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; + *VECTOR_END(*str) = 0; } } #endif diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 49c9793b..9549c010 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -595,7 +595,7 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) #define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); #undef MATCH_NAME - } while(iter != VECTOR_ITER_END(*list)); + } while(iter != VECTOR_END(*list)); TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(*filename)); @@ -667,11 +667,11 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) /* Find the preferred HRTF and move it to the front of the list. */ #define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY); - if(iter != VECTOR_ITER_END(list) && iter != VECTOR_ITER_BEGIN(list)) + if(iter != VECTOR_END(list) && iter != VECTOR_BEGIN(list)) { HrtfEntry entry = *iter; memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), - (iter-VECTOR_ITER_BEGIN(list))*sizeof(HrtfEntry)); + (iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry)); VECTOR_ELEM(list,0) = entry; } else diff --git a/Alc/vector.h b/Alc/vector.h index c1fc925d..cb64b5a9 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -39,8 +39,8 @@ ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) #define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) -#define VECTOR_ITER_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) -#define VECTOR_ITER_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) +#define VECTOR_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) +#define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend); #ifdef __GNUC__ @@ -67,22 +67,22 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ #define VECTOR_ELEM(_x, _o) ((_x)->Data[(_o)]) #define VECTOR_FOR_EACH(_t, _x, _f) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ + _t *_iter = VECTOR_BEGIN((_x)); \ + _t *_end = VECTOR_END((_x)); \ for(;_iter != _end;++_iter) \ _f(_iter); \ } while(0) #define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ + _t *_iter = VECTOR_BEGIN((_x)); \ + _t *_end = VECTOR_END((_x)); \ for(;_iter != _end;++_iter) \ _f(__VA_ARGS__, _iter); \ } while(0) #define VECTOR_FIND_IF(_i, _t, _x, _f) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ + _t *_iter = VECTOR_BEGIN((_x)); \ + _t *_end = VECTOR_END((_x)); \ for(;_iter != _end;++_iter) \ { \ if(_f(_iter)) \ @@ -92,8 +92,8 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ } while(0) #define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ + _t *_iter = VECTOR_BEGIN((_x)); \ + _t *_end = VECTOR_END((_x)); \ for(;_iter != _end;++_iter) \ { \ if(_f(__VA_ARGS__, _iter)) \ diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 0364c33c..9780cff3 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -98,7 +98,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo effectslots[cur] = slot->id; } - err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n); + err = AddEffectSlotArray(context, VECTOR_BEGIN(slotvec), n); if(err != AL_NO_ERROR) { alDeleteAuxiliaryEffectSlots(cur, effectslots); @@ -394,7 +394,7 @@ static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsi ALenum err = AL_NO_ERROR; LockContext(context); - if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots), start, start+count)) + if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_END(context->ActiveAuxSlots), start, start+count)) err = AL_OUT_OF_MEMORY; UnlockContext(context); @@ -408,7 +408,7 @@ static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot) LockContext(context); #define MATCH_SLOT(_i) (slot == *(_i)) VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT); - if(iter != VECTOR_ITER_END(context->ActiveAuxSlots)) + if(iter != VECTOR_END(context->ActiveAuxSlots)) { *iter = VECTOR_BACK(context->ActiveAuxSlots); VECTOR_POP_BACK(context->ActiveAuxSlots); -- cgit v1.2.3 From e27fad90dec951f75b40004dcd32470ca404921d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 12:33:42 -0700 Subject: Fix possible out-of-bounds warning --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 9248bb86..a3b9b293 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -644,7 +644,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if((conf->ChanMask & ~0x831b)) { - count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 16 : 9 : 4; + count = (conf->ChanMask > 0xf) ? 9 : 4; chanmap = Ambi3D; } else @@ -662,7 +662,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_FALSE); + &device->Dry.NumChannels, AL_FALSE); TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf->FreqBands == 1) ? "single" : "dual", -- cgit v1.2.3 From bd65f64d0506be6f20d69311c9a6ade3d0a8d01d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 17:31:04 -0700 Subject: Avoid mixing all coefficients together when only some are used --- Alc/ALu.c | 10 ++++--- Alc/effects/chorus.c | 8 ++++-- Alc/effects/dedicated.c | 2 +- Alc/effects/echo.c | 8 +++--- Alc/effects/flanger.c | 10 ++++--- Alc/effects/reverb.c | 24 +++++++++------- Alc/panning.c | 72 +++++++++++++++++++++++++---------------------- OpenAL32/Include/alMain.h | 4 +++ OpenAL32/Include/alu.h | 2 +- 9 files changed, 80 insertions(+), 60 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 5823bd5f..1703b43b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -682,8 +682,9 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - DryGain, voice->Direct.Gains[c].Target); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, DryGain, voice->Direct.Gains[c].Target + ); } for(i = 0;i < NumSends;i++) @@ -1183,8 +1184,9 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - DryGain, voice->Direct.Gains[0].Target); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, DryGain, voice->Direct.Gains[0].Target + ); } for(i = 0;i < NumSends;i++) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index e212cd75..a55983ab 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -113,9 +113,13 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[0] + ); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[1] + ); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 893f3abc..9fd10177 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -84,7 +84,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * ALfloat coeffs[MAX_AMBI_COEFFS]; CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); ComputePanningGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, - coeffs, Gain, state->gains); + device->Dry.CoeffCount, coeffs, Gain, state->gains); } STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 1f5925ef..00bf5d9f 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -104,13 +104,13 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co /* First tap panning */ CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, gain, state->Gain[0]); /* Second tap panning */ CalcXYZCoeffs( lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, gain, state->Gain[1]); } static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index d29e0f25..c323c17a 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -113,11 +113,13 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[0] + ); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[1] + ); phase = Slot->EffectProps.Flanger.Phase; rate = Slot->EffectProps.Flanger.Rate; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 2aea0763..e5c19d82 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -720,7 +720,8 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) @@ -744,7 +745,8 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) @@ -785,8 +787,8 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Gain, DirGains); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; } @@ -808,8 +810,8 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Gain, DirGains); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; } @@ -859,8 +861,9 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Gain*EarlyGain*gain[i], State->Early.PanGain[i]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain*EarlyGain*gain[i], + State->Early.PanGain[i]); } gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; @@ -890,8 +893,9 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs, - Gain*LateGain*gain[i], State->Late.PanGain[i]); + ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, + Device->Dry.CoeffCount, coeffs, Gain*LateGain*gain[i], + State->Late.PanGain[i]); } } diff --git a/Alc/panning.c b/Alc/panning.c index a3b9b293..6691373e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -164,14 +164,14 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo gains[i] = 0.0f; } -void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; for(i = 0;i < numchans;i++) { float gain = 0.0f; - for(j = 0;j < MAX_AMBI_COEFFS;j++) + for(j = 0;j < numcoeffs;j++) gain += chancoeffs[i][j]*coeffs[j]; gains[i] = gain * ingain; } @@ -443,15 +443,6 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, -}, Cube8Cfg[8] = { - { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, - { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } }, - { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, - { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, }, BFormat2D[3] = { { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, @@ -466,16 +457,11 @@ static const ChannelMap MonoCfg[1] = { static void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; + ALuint coeffcount = 0; ALfloat ambiscale; size_t count = 0; ALuint i, j; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - ambiscale = 1.0f; switch(device->FmtChans) { @@ -483,53 +469,64 @@ static void InitPanning(ALCdevice *device) count = COUNTOF(MonoCfg); chanmap = MonoCfg; ambiscale = ZERO_ORDER_SCALE; + coeffcount = 1; break; case DevFmtStereo: count = COUNTOF(StereoCfg); chanmap = StereoCfg; ambiscale = FIRST_ORDER_SCALE; + coeffcount = 4; break; case DevFmtQuad: count = COUNTOF(QuadCfg); chanmap = QuadCfg; ambiscale = SECOND_ORDER_SCALE; + coeffcount = 9; break; case DevFmtX51: count = COUNTOF(X51SideCfg); chanmap = X51SideCfg; ambiscale = SECOND_ORDER_SCALE; + coeffcount = 9; break; case DevFmtX51Rear: count = COUNTOF(X51RearCfg); chanmap = X51RearCfg; ambiscale = SECOND_ORDER_SCALE; + coeffcount = 9; break; case DevFmtX61: count = COUNTOF(X61Cfg); chanmap = X61Cfg; ambiscale = THIRD_ORDER_SCALE; + coeffcount = 16; break; case DevFmtX71: count = COUNTOF(X71Cfg); chanmap = X71Cfg; ambiscale = THIRD_ORDER_SCALE; + coeffcount = 16; break; case DevFmtBFormat3D: count = COUNTOF(BFormat3D); chanmap = BFormat3D; ambiscale = FIRST_ORDER_SCALE; + coeffcount = 4; break; } + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); + device->Dry.CoeffCount = coeffcount; memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); for(i = 0;i < device->Dry.NumChannels;i++) @@ -547,12 +544,6 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A ALfloat ambiscale = 1.0f; ALuint i, j; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - if(conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); @@ -592,8 +583,12 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A } } + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, - conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); + conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); + device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : + (conf->ChanMask > 0xf) ? 9 : 4; memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); for(i = 0;i < device->Dry.NumChannels;i++) @@ -639,9 +634,6 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin size_t count; ALuint i; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; - if((conf->ChanMask & ~0x831b)) { count = (conf->ChanMask > 0xf) ? 9 : 4; @@ -663,6 +655,8 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_FALSE); + device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : + (conf->ChanMask > 0xf) ? 9 : 4; TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf->FreqBands == 1) ? "single" : "dual", @@ -687,6 +681,16 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin static void InitHrtfPanning(ALCdevice *device) { + static const ChannelMap Cube8Cfg[8] = { + { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, + { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, + { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } }, + { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } }, + { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } }, + { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, + { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, + { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, + }; static const struct { enum Channel Channel; ALfloat Angle; @@ -705,18 +709,16 @@ static void InitHrtfPanning(ALCdevice *device) size_t count = COUNTOF(Cube8Cfg); ALuint i; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; - for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); + device->Dry.CoeffCount = 4; memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); + sizeof(device->FOAOut.AmbiCoeffs)); for(i = 0;i < device->Dry.NumChannels;i++) { @@ -732,15 +734,13 @@ static void InitUhjPanning(ALCdevice *device) size_t count = COUNTOF(BFormat2D); ALuint i; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); - device->Dry.NumChannels = 0; - for(i = 0;i < count;i++) device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); + device->Dry.CoeffCount = 4; memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, sizeof(device->FOAOut.AmbiCoeffs)); @@ -759,6 +759,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf al_string_clear(&device->Hrtf_Name); device->Render_Mode = NormalRender; + memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = 0; + if(device->FmtChans != DevFmtStereo) { ALuint speakermap[MAX_OUTPUT_CHANNELS]; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9ba6d050..52296a15 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -511,6 +511,10 @@ struct ALCdevice_struct enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; /* Ambisonic coefficients for mixing to the dry buffer. */ ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; + /* Number of coefficients in each ChannelConfig to mix together (4 for + * first-order, 9 for second-order, etc). + */ + ALuint CoeffCount; /* Dry buffer will be aliased by the virtual or real output. */ ALfloat (*Buffer)[BUFFERSIZE]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 2869722b..8a0aa81e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -337,7 +337,7 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo * Computes panning gains using the given channel decoder coefficients and the * pre-calculated direction or angle coefficients. */ -void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** -- cgit v1.2.3 From e16032e1f0c92ff23c70393eccbac7def14d4bab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 18:14:19 -0700 Subject: Update some comments --- Alc/panning.c | 6 +++--- OpenAL32/Include/alu.h | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 6691373e..9ad9d2a7 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -138,12 +138,12 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]) coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ } -void CalcAngleCoeffs(ALfloat angle, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]) +void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]) { ALfloat dir[3] = { - sinf(angle) * cosf(elevation), + sinf(azimuth) * cosf(elevation), sinf(elevation), - -cosf(angle) * cosf(elevation) + -cosf(azimuth) * cosf(elevation) }; CalcDirectionCoeffs(dir, coeffs); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8a0aa81e..8b11bdd4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -300,7 +300,7 @@ void aluInitEffectPanning(struct ALeffectslot *slot); * CalcDirectionCoeffs * * Calculates ambisonic coefficients based on a direction vector. The vector - * must not be longer than 1 unit. + * must be normalized (unit length). */ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]); @@ -319,10 +319,11 @@ inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AM /** * CalcAngleCoeffs * - * Calculates ambisonic coefficients based on angle and elevation. The angle - * and elevation parameters are in radians, going right and up respectively. + * Calculates ambisonic coefficients based on azimuth and elevation. The + * azimuth and elevation parameters are in radians, going right and up + * respectively. */ -void CalcAngleCoeffs(ALfloat angle, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]); +void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]); /** * ComputeAmbientGains -- cgit v1.2.3 From a6c70992b01b168d561c448fa235a86c9697b6ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Apr 2016 22:05:47 -0700 Subject: More directly map coefficients for ambisonic mixing buffers Instead of looping over all the coefficients for each channel with multiplies, when we know only one will have a non-0 factor for ambisonic mixing buffers, just index the one with a non-0 factor. --- Alc/ALu.c | 13 ++-- Alc/effects/autowah.c | 2 +- Alc/effects/chorus.c | 8 +-- Alc/effects/compressor.c | 4 +- Alc/effects/dedicated.c | 11 ++- Alc/effects/distortion.c | 2 +- Alc/effects/echo.c | 6 +- Alc/effects/equalizer.c | 4 +- Alc/effects/flanger.c | 8 +-- Alc/effects/modulator.c | 4 +- Alc/effects/reverb.c | 21 ++---- Alc/panning.c | 166 ++++++++++++++++++++++++++-------------------- OpenAL32/Include/alMain.h | 16 +++-- OpenAL32/Include/alu.h | 25 ++++++- 14 files changed, 160 insertions(+), 130 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 1703b43b..769ea627 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -519,8 +519,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->Direct.OutBuffer = Device->FOAOut.Buffer; voice->Direct.OutChannels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(Device->FOAOut.AmbiCoeffs, Device->FOAOut.NumChannels, matrix.m[c], - DryGain, voice->Direct.Gains[c].Target); + ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, + voice->Direct.Gains[c].Target); for(i = 0;i < NumSends;i++) { @@ -682,9 +682,8 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A else { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, DryGain, voice->Direct.Gains[c].Target - ); + ComputePanningGains(Device->Dry, coeffs, DryGain, + voice->Direct.Gains[c].Target); } for(i = 0;i < NumSends;i++) @@ -1184,9 +1183,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte else { CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, DryGain, voice->Direct.Gains[0].Target - ); + ComputePanningGains(Device->Dry, coeffs, DryGain, voice->Direct.Gains[0].Target); } for(i = 0;i < NumSends;i++) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 20ae26e4..7c5abfb1 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -75,7 +75,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *devi state->PeakGain = slot->EffectProps.Autowah.PeakGain; state->Resonance = slot->EffectProps.Autowah.Resonance; - ComputeAmbientGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, slot->Gain, state->Gain); + ComputeAmbientGains(device->Dry, slot->Gain, state->Gain); } static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index a55983ab..94c9fc47 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -113,13 +113,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[0] - ); + ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[1] - ); + ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 4e1d55f1..bc4955b9 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -72,8 +72,8 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->FOAOut.AmbiCoeffs, device->FOAOut.NumChannels, - matrix.m[i], slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain, + state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 9fd10177..20acfdcf 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -59,9 +59,9 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * int idx; if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) { - state->gains[idx] = Gain; STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + state->gains[idx] = Gain; } } else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) @@ -71,23 +71,22 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * * plays from the front-center location. */ if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1) { - state->gains[idx] = Gain; STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; + state->gains[idx] = Gain; } else { + STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; if((idx=GetChannelIdxByName(device->Dry, FrontCenter)) != -1) state->gains[idx] = Gain; else { ALfloat coeffs[MAX_AMBI_COEFFS]; CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); - ComputePanningGains(device->Dry.AmbiCoeffs, device->Dry.NumChannels, - device->Dry.CoeffCount, coeffs, Gain, state->gains); + ComputePanningGains(device->Dry, coeffs, Gain, state->gains); } - STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 92eb1a6d..7a4c2f62 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -83,7 +83,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, Slot->Gain, state->Gain); + ComputeAmbientGains(Device->Dry, Slot->Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 00bf5d9f..9fd31864 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -104,13 +104,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co /* First tap panning */ CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, gain, state->Gain[0]); + ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]); /* Second tap panning */ CalcXYZCoeffs( lrpan, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, gain, state->Gain[1]); + ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]); } static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index f3383bd2..e0fa010e 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -113,8 +113,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->FOAOut.AmbiCoeffs, device->FOAOut.NumChannels, - matrix.m[i], slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain, + state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index c323c17a..e394f9f2 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -113,13 +113,9 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[0] - ); + ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Slot->Gain, state->Gain[1] - ); + ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Flanger.Phase; rate = Slot->EffectProps.Flanger.Rate; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 03e0d458..fb75043a 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -132,8 +132,8 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut.AmbiCoeffs, Device->FOAOut.NumChannels, - matrix.m[i], Slot->Gain, state->Gain[i]); + ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Gain, + state->Gain[i]); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index e5c19d82..bb980ac2 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -720,8 +720,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) @@ -745,8 +744,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; for(i = 0;i < Device->RealOut.NumChannels;i++) @@ -763,8 +761,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec ALuint i; /* Apply a boost of about 3dB to better match the expected stereo output volume. */ - ComputeAmbientGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Gain*1.414213562f, AmbientGains); + ComputeAmbientGains(Device->Dry, Gain*1.414213562f, AmbientGains); memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); @@ -787,8 +784,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; } @@ -810,8 +806,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec length = minf(length, 1.0f); CalcDirectionCoeffs(pan, coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain, DirGains); + ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; } @@ -861,8 +856,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain*EarlyGain*gain[i], + ComputePanningGains(Device->Dry, coeffs, Gain*EarlyGain*gain[i], State->Early.PanGain[i]); } @@ -893,8 +887,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { CalcDirectionCoeffs(PanDirs[i], coeffs); - ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, - Device->Dry.CoeffCount, coeffs, Gain*LateGain*gain[i], + ComputePanningGains(Device->Dry, coeffs, Gain*LateGain*gain[i], State->Late.PanGain[i]); } } diff --git a/Alc/panning.c b/Alc/panning.c index 9ad9d2a7..0e04f074 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -149,7 +149,7 @@ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI } -void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i; @@ -164,7 +164,22 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo gains[i] = 0.0f; } -void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALfloat gain = 0.0f; + ALuint i; + + for(i = 0;i < numchans;i++) + { + if(chanmap[i].Index == 0) + gain += chanmap[i].Scale; + } + gains[0] = gain * 1.414213562f * ingain; + for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; @@ -189,7 +204,7 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons gains[i] = 0.0f; } -void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALuint i, j; @@ -524,16 +539,34 @@ static void InitPanning(ALCdevice *device) for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); - device->Dry.CoeffCount = coeffcount; + if(device->FmtChans == DevFmtBFormat3D) + { + for(i = 0;i < count;i++) + { + ALuint acn = FuMa2ACN[i]; + device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; + device->Dry.Ambi.Map[i].Index = acn; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); - for(i = 0;i < device->Dry.NumChannels;i++) + memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + } + else { - device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; - for(j = 1;j < 4;j++) - device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, + &device->Dry.NumChannels, AL_TRUE); + device->Dry.CoeffCount = coeffcount; + + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < device->Dry.NumChannels;i++) + { + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; + for(j = 1;j < 4;j++) + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale; + } + device->FOAOut.CoeffCount = 4; } } @@ -585,78 +618,60 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, + SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); for(i = 0;i < device->Dry.NumChannels;i++) { - device->FOAOut.AmbiCoeffs[i][0] = device->Dry.AmbiCoeffs[i][0]; + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; for(j = 1;j < 4;j++) - device->FOAOut.AmbiCoeffs[i][j] = device->Dry.AmbiCoeffs[i][j] * ambiscale; + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale; } + device->FOAOut.CoeffCount = 4; } static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS]) { - /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */ - static const ChannelMap Ambi3D[9] = { - /* Zeroth order */ - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* First order */ - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Second order */ - { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux7, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux8, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, - }, Ambi2D[7] = { - /* Zeroth order */ - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* First order */ - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Second order */ - { Aux3, { 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux4, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - /* Third order */ - { Aux5, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } }, - { Aux6, { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }, - }; - const ChannelMap *chanmap = NULL; const char *devname; int decflags = 0; size_t count; ALuint i; if((conf->ChanMask & ~0x831b)) - { - count = (conf->ChanMask > 0xf) ? 9 : 4; - chanmap = Ambi3D; - } + count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 16: 9 : 4; else - { count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 7 : 5 : 3; - chanmap = Ambi2D; - } devname = al_string_get_cstr(device->DeviceName); if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) decflags |= BFDF_DistanceComp; for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; + device->Dry.ChannelName[i] = Aux0 + i; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_FALSE); - device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : - (conf->ChanMask > 0xf) ? 9 : 4; + if((conf->ChanMask & ~0x831b)) + { + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = i; + } + } + else + { + static int map[MAX_AMBI_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = map[i]; + } + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf->FreqBands == 1) ? "single" : "dual", @@ -667,15 +682,19 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin speakermap, decflags); if(bformatdec_getOrder(device->AmbiDecoder) < 2) - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); + { + memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + } else { - memset(device->FOAOut.AmbiCoeffs, 0, sizeof(device->FOAOut.AmbiCoeffs)); - device->FOAOut.AmbiCoeffs[0][0] = 1.0f; - device->FOAOut.AmbiCoeffs[1][1] = 1.0f; - device->FOAOut.AmbiCoeffs[2][2] = 1.0f; - device->FOAOut.AmbiCoeffs[3][3] = 1.0f; + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; } } @@ -713,12 +732,12 @@ static void InitHrtfPanning(ALCdevice *device) device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, + SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); device->Dry.CoeffCount = 4; - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); + memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.CoeffCount = device->Dry.CoeffCount; for(i = 0;i < device->Dry.NumChannels;i++) { @@ -738,12 +757,17 @@ static void InitUhjPanning(ALCdevice *device) device->Dry.ChannelName[i] = chanmap[i].ChanName; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); - device->Dry.CoeffCount = 4; + for(i = 0;i < count;i++) + { + ALuint acn = FuMa2ACN[i]; + device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; + device->Dry.Ambi.Map[i].Index = acn; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; - memcpy(device->FOAOut.AmbiCoeffs, device->Dry.AmbiCoeffs, - sizeof(device->FOAOut.AmbiCoeffs)); + memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.CoeffCount = device->Dry.CoeffCount; } void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) @@ -759,7 +783,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf al_string_clear(&device->Hrtf_Name); device->Render_Mode = NormalRender; - memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs)); + memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 52296a15..12c4c610 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -509,8 +509,12 @@ struct ALCdevice_struct struct { /* Channel names for the dry buffer mix. */ enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; - /* Ambisonic coefficients for mixing to the dry buffer. */ - ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; + union { + /* Ambisonic coefficients for mixing to the dry buffer. */ + ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS]; + /* Coefficient channel mapping for mixing to the dry buffer. */ + BFChannelConfig Map[MAX_OUTPUT_CHANNELS]; + } Ambi; /* Number of coefficients in each ChannelConfig to mix together (4 for * first-order, 9 for second-order, etc). */ @@ -523,8 +527,12 @@ struct ALCdevice_struct /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ struct { - /* Ambisonic coefficients for mixing. */ - ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS]; + union { + ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS]; + BFChannelConfig Map[MAX_OUTPUT_CHANNELS]; + } Ambi; + /* Will only be 4 or 0. */ + ALuint CoeffCount; ALfloat (*Buffer)[BUFFERSIZE]; ALuint NumChannels; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8b11bdd4..c6b5aba0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -330,7 +330,14 @@ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI * * Computes channel gains for ambient, omni-directional sounds. */ -void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +#define ComputeAmbientGains(b, g, o) do { \ + if((b).CoeffCount > 0) \ + ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o); \ + else \ + ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \ +} while (0) +void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputePanningGains @@ -338,7 +345,13 @@ void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALflo * Computes panning gains using the given channel decoder coefficients and the * pre-calculated direction or angle coefficients. */ -void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +#define ComputePanningGains(b, c, g, o) do { \ + if((b).CoeffCount > 0) \ + ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\ + else \ + ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \ +} while (0) +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** @@ -348,7 +361,13 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons * a 1x4 'slice' of a transform matrix for the input channel, used to scale and * orient the sound samples. */ -void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +#define ComputeFirstOrderGains(b, m, g, o) do { \ + if((b).CoeffCount > 0) \ + ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o); \ + else \ + ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \ +} while (0) +void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -- cgit v1.2.3 From 325245f4b80ce00250517af5d83206ffabbd0e40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Apr 2016 01:24:37 -0700 Subject: Silence possible out-of-bounds warning again --- Alc/panning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 0e04f074..a9774a01 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -649,7 +649,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) decflags |= BFDF_DistanceComp; - for(i = 0;i < count;i++) + for(i = 0;i < count && i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = Aux0 + i; for(;i < MAX_OUTPUT_CHANNELS;i++) device->Dry.ChannelName[i] = InvalidChannel; -- cgit v1.2.3 From d1f3a154704007ac06b480d0e454f231a17f6ae6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Apr 2016 14:00:22 -0700 Subject: Reorganize a bit of aluInitRenderer code --- Alc/panning.c | 76 +++++++++++++++++++++++------------------------------------ 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index a9774a01..83f394fb 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -269,23 +269,6 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) } -DECL_CONST static const char *GetChannelLayoutName(enum DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return "mono"; - case DevFmtStereo: return "stereo"; - case DevFmtQuad: return "quad"; - case DevFmtX51: return "surround51"; - case DevFmtX51Rear: return "surround51rear"; - case DevFmtX61: return "surround61"; - case DevFmtX71: return "surround71"; - case DevFmtBFormat3D: - break; - } - return NULL; -} - typedef struct ChannelMap { enum Channel ChanName; ChannelConfig Config; @@ -772,11 +755,9 @@ static void InitUhjPanning(ALCdevice *device) void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) { - ALCenum hrtf_status; const char *mode; bool headphones; int bs2blevel; - int usehrtf; size_t i; device->Hrtf = NULL; @@ -790,19 +771,28 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->FmtChans != DevFmtStereo) { ALuint speakermap[MAX_OUTPUT_CHANNELS]; - const char *devname, *layout; - AmbDecConf conf, *pconf; + const char *devname, *layout = NULL; + AmbDecConf conf, *pconf = NULL; if(hrtf_appreq == Hrtf_Enable) device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - pconf = NULL; ambdec_init(&conf); devname = al_string_get_cstr(device->DeviceName); - layout = NULL; - if(device->FmtChans != DevFmtMono) - layout = GetChannelLayoutName(device->FmtChans); + switch(device->FmtChans) + { + case DevFmtQuad: layout = "quad"; break; + case DevFmtX51: layout = "surround51"; break; + case DevFmtX51Rear: layout = "surround51rear"; break; + case DevFmtX61: layout = "surround61"; break; + case DevFmtX71: layout = "surround71"; break; + /* Mono, Stereo, and B-Fornat output don't use custom decoders. */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtBFormat3D: + break; + } if(layout) { const char *fname; @@ -855,9 +845,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; - hrtf_status = device->Hrtf_Status; headphones = device->IsHeadphones; - if(device->Type != Loopback) { const char *mode; @@ -874,29 +862,25 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_userreq == Hrtf_Default) { - usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || - (hrtf_appreq == Hrtf_Enable); + bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(!usehrtf) goto no_hrtf; + + device->Hrtf_Status = ALC_HRTF_ENABLED_SOFT; if(headphones && hrtf_appreq != Hrtf_Disable) - hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; - else if(usehrtf) - hrtf_status = ALC_HRTF_ENABLED_SOFT; + device->Hrtf_Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; } else { - usehrtf = (hrtf_userreq == Hrtf_Enable); - if(!usehrtf) - hrtf_status = ALC_HRTF_DENIED_SOFT; - else - hrtf_status = ALC_HRTF_REQUIRED_SOFT; - } - - if(!usehrtf) - { - device->Hrtf_Status = hrtf_status; - goto no_hrtf; + if(hrtf_userreq != Hrtf_Enable) + { + if(hrtf_appreq == Hrtf_Enable) + device->Hrtf_Status = ALC_HRTF_DENIED_SOFT; + goto no_hrtf; + } + device->Hrtf_Status = ALC_HRTF_REQUIRED_SOFT; } - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; if(VECTOR_SIZE(device->Hrtf_List) == 0) { VECTOR_DEINIT(device->Hrtf_List); @@ -925,8 +909,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Hrtf) { - device->Hrtf_Status = hrtf_status; - device->Render_Mode = NormalRender; + device->Render_Mode = HrtfRender; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) @@ -941,6 +924,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf InitHrtfPanning(device); return; } + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; no_hrtf: TRACE("HRTF disabled\n"); -- cgit v1.2.3 From d2e8fae005409d5fae0248c80ca252c79be56f99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Apr 2016 14:11:10 -0700 Subject: Don't look up the dry buffer's FrontCenter in the Dedicated effect The real FrontCenter output is used if it exists, and if it doesn't, it's unlikely the dry buffer will have it (and even if it does, it won't be any better than panning). --- Alc/effects/dedicated.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 20acfdcf..12b16137 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -77,16 +77,12 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * } else { + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); + STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - if((idx=GetChannelIdxByName(device->Dry, FrontCenter)) != -1) - state->gains[idx] = Gain; - else - { - ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, Gain, state->gains); - } + ComputePanningGains(device->Dry, coeffs, Gain, state->gains); } } } -- cgit v1.2.3 From 3b571e03aba0edd10090ff01ec3193d43b2a8f47 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Apr 2016 17:21:31 -0700 Subject: Avoid storing channel names for the dry buffer --- Alc/ALu.c | 9 ++++++--- Alc/panning.c | 32 ++++++++++---------------------- OpenAL32/Include/alMain.h | 2 -- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 769ea627..6d07afe2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -652,11 +652,14 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Special-case LFE */ if(chans[c].channel == LFE) { - int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1) - voice->Direct.Gains[c].Target[idx] = DryGain; + if(Device->Dry.Buffer == Device->RealOut.Buffer) + { + int idx; + if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) + voice->Direct.Gains[c].Target[idx] = DryGain; + } for(i = 0;i < NumSends;i++) { diff --git a/Alc/panning.c b/Alc/panning.c index 83f394fb..c676c809 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -520,8 +520,6 @@ static void InitPanning(ALCdevice *device) break; } - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; if(device->FmtChans == DevFmtBFormat3D) { for(i = 0;i < count;i++) @@ -538,8 +536,8 @@ static void InitPanning(ALCdevice *device) } else { - SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); + SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, + chanmap, count, &device->Dry.NumChannels, AL_TRUE); device->Dry.CoeffCount = coeffcount; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); @@ -599,9 +597,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A } } - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = device->RealOut.ChannelName[i]; - SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, + SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; @@ -632,10 +628,6 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) decflags |= BFDF_DistanceComp; - for(i = 0;i < count && i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = Aux0 + i; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; if((conf->ChanMask & ~0x831b)) { for(i = 0;i < count;i++) @@ -683,6 +675,11 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin static void InitHrtfPanning(ALCdevice *device) { + static const enum Channel CubeChannels[MAX_OUTPUT_CHANNELS] = { + UpperFrontLeft, UpperFrontRight, UpperBackLeft, UpperBackRight, + LowerFrontLeft, LowerFrontRight, LowerBackLeft, LowerBackRight, + InvalidChannel + }; static const ChannelMap Cube8Cfg[8] = { { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, @@ -711,11 +708,7 @@ static void InitHrtfPanning(ALCdevice *device) size_t count = COUNTOF(Cube8Cfg); ALuint i; - for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; - SetChannelMap(device->Dry.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, + SetChannelMap(CubeChannels, device->Dry.Ambi.Coeffs, chanmap, count, &device->Dry.NumChannels, AL_TRUE); device->Dry.CoeffCount = 4; @@ -724,7 +717,7 @@ static void InitHrtfPanning(ALCdevice *device) for(i = 0;i < device->Dry.NumChannels;i++) { - int chan = GetChannelIdxByName(device->Dry, CubeInfo[i].Channel); + int chan = GetChannelIndex(CubeChannels, CubeInfo[i].Channel); GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); } @@ -732,14 +725,9 @@ static void InitHrtfPanning(ALCdevice *device) static void InitUhjPanning(ALCdevice *device) { - const ChannelMap *chanmap = BFormat2D; size_t count = COUNTOF(BFormat2D); ALuint i; - for(i = 0;i < count;i++) - device->Dry.ChannelName[i] = chanmap[i].ChanName; - for(;i < MAX_OUTPUT_CHANNELS;i++) - device->Dry.ChannelName[i] = InvalidChannel; for(i = 0;i < count;i++) { ALuint acn = FuMa2ACN[i]; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 12c4c610..da4c5567 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -507,8 +507,6 @@ struct ALCdevice_struct /* The "dry" path corresponds to the main output. */ struct { - /* Channel names for the dry buffer mix. */ - enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; union { /* Ambisonic coefficients for mixing to the dry buffer. */ ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS]; -- cgit v1.2.3 From 894c7d0f7e2bf5e12b4a9310d4c9c1f82c837039 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Apr 2016 17:22:03 -0700 Subject: Trace the requested attribute values --- Alc/ALc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index e9a3a887..77522ec4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1691,11 +1691,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) stype = device->FmtType; freq = device->Frequency; +#define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) while(attrList[attrIdx]) { if(attrList[attrIdx] == ALC_FORMAT_CHANNELS_SOFT) { ALCint val = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, val); if(!IsValidALCChannels(val) || !ChannelsFromDevFmt(val)) return ALC_INVALID_VALUE; schans = val; @@ -1705,6 +1707,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_FORMAT_TYPE_SOFT) { ALCint val = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, val); if(!IsValidALCType(val) || !BytesFromDevFmt(val)) return ALC_INVALID_VALUE; stype = val; @@ -1714,6 +1717,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_FREQUENCY) { freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); if(freq < MIN_OUTPUT_RATE) return ALC_INVALID_VALUE; gotFmt |= GotFreq; @@ -1722,6 +1726,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_STEREO_SOURCES) { numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); if(numStereo > device->MaxNoOfSources) numStereo = device->MaxNoOfSources; @@ -1729,10 +1734,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) + { numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + } if(attrList[attrIdx] == ALC_HRTF_SOFT) { + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); if(attrList[attrIdx + 1] == ALC_FALSE) hrtf_appreq = Hrtf_Disable; else if(attrList[attrIdx + 1] == ALC_TRUE) @@ -1742,10 +1751,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) + { hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + } attrIdx += 2; } +#undef TRACE_ATTR if(gotFmt != GotAll) { @@ -1785,17 +1798,20 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) numStereo = device->NumStereoSources; numSends = device->NumAuxSends; +#define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) { if(attrList[attrIdx] == ALC_FREQUENCY) { freq = attrList[attrIdx + 1]; device->Flags |= DEVICE_FREQUENCY_REQUEST; + TRACE_ATTR(ALC_FREQUENCY, freq); } if(attrList[attrIdx] == ALC_STEREO_SOURCES) { numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); if(numStereo > device->MaxNoOfSources) numStereo = device->MaxNoOfSources; @@ -1803,10 +1819,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) + { numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + } if(attrList[attrIdx] == ALC_HRTF_SOFT) { + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); if(attrList[attrIdx + 1] == ALC_FALSE) hrtf_appreq = Hrtf_Disable; else if(attrList[attrIdx + 1] == ALC_TRUE) @@ -1816,10 +1836,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) + { hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + } attrIdx += 2; } +#undef TRACE_ATTR ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); -- cgit v1.2.3 From cd2e9114e8bdf6f45f47b72c0bb422b59bf24bf5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Apr 2016 22:11:15 -0700 Subject: Remove unneeded ChannelMaps for BFormat formats --- Alc/panning.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index c676c809..5803a4e0 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -441,15 +441,6 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, -}, BFormat2D[3] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, -}, BFormat3D[4] = { - { Aux0, { 1.0f, 0.0f, 0.0f, 0.0f } }, - { Aux1, { 0.0f, 1.0f, 0.0f, 0.0f } }, - { Aux2, { 0.0f, 0.0f, 1.0f, 0.0f } }, - { Aux3, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; static void InitPanning(ALCdevice *device) @@ -513,15 +504,12 @@ static void InitPanning(ALCdevice *device) break; case DevFmtBFormat3D: - count = COUNTOF(BFormat3D); - chanmap = BFormat3D; - ambiscale = FIRST_ORDER_SCALE; - coeffcount = 4; break; } if(device->FmtChans == DevFmtBFormat3D) { + count = 4; for(i = 0;i < count;i++) { ALuint acn = FuMa2ACN[i]; @@ -725,7 +713,7 @@ static void InitHrtfPanning(ALCdevice *device) static void InitUhjPanning(ALCdevice *device) { - size_t count = COUNTOF(BFormat2D); + size_t count = 3; ALuint i; for(i = 0;i < count;i++) -- cgit v1.2.3 From a59332f6221cbb0b0aedae90ff9b2becf464f543 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Apr 2016 13:58:33 -0700 Subject: Combine two if checks into one --- Alc/panning.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 5803a4e0..ed10c321 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -607,17 +607,13 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin size_t count; ALuint i; - if((conf->ChanMask & ~0x831b)) - count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 16: 9 : 4; - else - count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 7 : 5 : 3; - devname = al_string_get_cstr(device->DeviceName); if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) decflags |= BFDF_DistanceComp; if((conf->ChanMask & ~0x831b)) { + count = (conf->ChanMask > 0xf) ? 9 : 4; for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; @@ -627,6 +623,8 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin else { static int map[MAX_AMBI_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; + + count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 7 : 5 : 3; for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; -- cgit v1.2.3 From 42531703cc1010dd736650024de67ef8ea7d744c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Apr 2016 18:58:19 -0700 Subject: Increase max output channels to 16 This also enables fully periphonic 3rd order HQ decoding. --- Alc/panning.c | 25 ++++++++++++++----------- OpenAL32/Include/alMain.h | 9 ++++++++- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index ed10c321..51b8e5cc 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -262,6 +262,13 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) case Aux6: return "aux-6"; case Aux7: return "aux-7"; case Aux8: return "aux-8"; + case Aux9: return "aux-9"; + case Aux10: return "aux-10"; + case Aux11: return "aux-11"; + case Aux12: return "aux-12"; + case Aux13: return "aux-13"; + case Aux14: return "aux-14"; + case Aux15: return "aux-15"; case InvalidChannel: break; } @@ -613,7 +620,8 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if((conf->ChanMask & ~0x831b)) { - count = (conf->ChanMask > 0xf) ? 9 : 4; + count = (conf->ChanMask > 0x1ff) ? 16 : + (conf->ChanMask > 0xf) ? 9 : 4; for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; @@ -624,7 +632,8 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin { static int map[MAX_AMBI_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; - count = (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? 7 : 5 : 3; + count = (conf->ChanMask > 0x1ff) ? 7 : + (conf->ChanMask > 0xf) ? 5 : 3; for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; @@ -664,7 +673,8 @@ static void InitHrtfPanning(ALCdevice *device) static const enum Channel CubeChannels[MAX_OUTPUT_CHANNELS] = { UpperFrontLeft, UpperFrontRight, UpperBackLeft, UpperBackRight, LowerFrontLeft, LowerFrontRight, LowerBackLeft, LowerBackRight, - InvalidChannel + InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel, + InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel }; static const ChannelMap Cube8Cfg[8] = { { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, @@ -789,14 +799,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) { - if((conf.ChanMask & ~0x831b) && conf.ChanMask > 0x1ff) - { - ERR("Third-order is unsupported for periphonic HQ decoding (mask 0x%04x)\n", - conf.ChanMask); - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - } - else if(!device->AmbiDecoder) + if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); } else diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index da4c5567..fba9c012 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -336,6 +336,13 @@ enum Channel { Aux6, Aux7, Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, InvalidChannel }; @@ -368,7 +375,7 @@ enum DevFmtChannels { DevFmtChannelsDefault = DevFmtStereo }; -#define MAX_OUTPUT_CHANNELS (9) +#define MAX_OUTPUT_CHANNELS (16) ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST; ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST; -- cgit v1.2.3 From 3387f230740fb234ced25b53d2a5126f9eb35571 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Apr 2016 02:19:43 -0700 Subject: Update a config option comment --- alsoftrc.sample | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 3a22914d..f8127549 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -212,9 +212,8 @@ # dependent processing, creating a better reproduction of 3D sound rendering # over surround sound speakers. Enabling this also requires specifying decoder # configuration files for the appropriate speaker configuration you intend to -# use (see the quad, surround51, etc options below). Currently, periphonic -# (with height) configurations support up to second-order, and horizontal -# configurations support up to third-order. +# use (see the quad, surround51, etc options below). Currently, up to third- +# order decoding is supported. hq-mode = false ## distance-comp: -- cgit v1.2.3 From cec03f39ae551d68b85f6fd4fb99c00a4f7d759d Mon Sep 17 00:00:00 2001 From: gero Date: Fri, 22 Apr 2016 17:33:00 +0800 Subject: fix audio play error in sample fix audio play error in sample --- examples/alffplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index ab67d216..7feaa5ae 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -350,7 +350,7 @@ static int synchronize_audio(MovieState *movState) ref_clock = get_master_clock(movState); diff = ref_clock - get_audio_clock(&movState->audio); - if(!(diff < AV_NOSYNC_THRESHOLD)) + if(!(fabs(diff) < AV_NOSYNC_THRESHOLD)) { /* Difference is TOO big; reset diff stuff */ movState->audio.diff_accum = 0.0; -- cgit v1.2.3 From 80c90087984dbd55447f0251937c6d53dbfc22e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Apr 2016 14:12:43 -0700 Subject: Add docs for OpenAL Soft and standard decoder presets --- docs/3D7.1.txt | 82 ++++++++++++++++++++++++++++++++ docs/ambisonics.txt | 119 +++++++++++++++++++++++++++++++++++++++++++++++ presets/3D7.1.ambdec | 43 +++++++++++++++++ presets/hexagon.ambdec | 51 ++++++++++++++++++++ presets/presets.txt | 36 ++++++++++++++ presets/rectangle.ambdec | 45 ++++++++++++++++++ presets/square.ambdec | 45 ++++++++++++++++++ 7 files changed, 421 insertions(+) create mode 100644 docs/3D7.1.txt create mode 100644 docs/ambisonics.txt create mode 100644 presets/3D7.1.ambdec create mode 100644 presets/hexagon.ambdec create mode 100644 presets/presets.txt create mode 100644 presets/rectangle.ambdec create mode 100644 presets/square.ambdec diff --git a/docs/3D7.1.txt b/docs/3D7.1.txt new file mode 100644 index 00000000..1d40bec6 --- /dev/null +++ b/docs/3D7.1.txt @@ -0,0 +1,82 @@ +Overview +======== + +3D7.1 is a custom speaker layout designed by Simon Goodwin at Codemasters[1]. +Typical surround sound setups, like quad, 5.1, 6.1, and 7.1, only produce audio +on a 2D horizontal plane with no verticality, which means the envelopment of +"surround" sound is limited to left, right, front, and back panning. Sounds +that should come from above or below will still only play in 2D since there is +no height difference in the speaker array. + +To work around this, 3D7.1 was designed so that some speakers are placed higher +than the listener while others are lower, in a particular configuration that +tries to provide balanced output and maintain some compatibility with existing +audio content and software. Software that recognizes this setup, or can be +configured for it, can then take advantage of the height difference and +increase the perception of verticality for true 3D audio. The result is that +sounds can be perceived as coming from left, right, front, and back, as well as +up and down. + +[1] http://www.codemasters.com/research/3D_sound_for_3D_games.pdf + + +Hardware Setup +============== + +Setting up 3D7.1 requires an audio device capable of raw 8-channel or 7.1 +output, along with a 7.1 speaker kit. The speakers should be hooked up to the +device in the usual way, with front-left and front-right output going to the +front-left and front-right speakers, etc. The placement of the speakers should +be set up according to the table below. Azimuth is the horizontal angle in +degrees, with 0 directly in front and positive values go /left/, and elevation +is the vertical angle in degrees, with 0 at head level and positive values go +/up/. + +------------------------------------------------------------ +- Speaker label | Azimuth | Elevation | New label - +------------------------------------------------------------ +- Front left | 51 | 24 | Upper front left - +- Front right | -51 | 24 | Upper front right - +- Front center | 0 | 0 | Front center - +- Subwoofer/LFE | N/A | N/A | Subwoofer/LFE - +- Side left | 129 | -24 | Lower back left - +- Side right | -129 | -24 | Lower back right - +- Back left | 180 | 55 | Upper back center - +- Back right | 0 | -55 | Lower front center - +------------------------------------------------------------ + +Note that this speaker layout *IS NOT* compatible with standard 7.1 content. +Audio that should be played from the back will come out at the wrong location +since the back speakers are placed in the lower front and upper back positions. +However, this speaker layout *IS* more or less compatible with standard 5.1 +content. Though slightly tilted, to a listener sitting a bit further back from +the center, the front and side speakers will be close enough to their intended +locations that the output won't be too off. + + +Software Setup +============== + +To enable 3D7.1 on OpenAL Soft, first make sure the audio device is configured +for 7.1 output. Then in the alsoft-config utility, under the Renderer tab, +select the 3D7.1.ambdec preset for the 7.1 Surround decoder configuration. And +that's it. Any applications using OpenAL Soft can take advantage of fully 3D +audio, and multi-channel sounds will be properly remixed for the speaker +layout. + +Playback can be improved by (copying and) modifying the 3D7.1.ambdec preset, +changing the specified speaker distances to match the the real distance (in +meters) from the center of the speaker array, then enable High Quality Mode in +alsoft-config. That will improve the quality when the speakers are not all +equidistant. + +Note that care must be taken that the audio device is not treated as a "true" +7.1 device by non-3D7.1-capable applications. In particular, the audio server +should not try to upmix stereo and 5.1 content to "fill out" the back speakers, +and non-3D7.1 apps should be set to either stereo or 5.1 output. + +As such, if your system is capable of it, it may be useful to define a virtual +5.1 device that maps the front, side, and LFE channels to the main device for +output and disables upmixing, then use that virtual 5.1 device for apps that do +normal stereo or surround sound output, and use the main device for apps that +understand 3D7.1 output. diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt new file mode 100644 index 00000000..77ec8ef7 --- /dev/null +++ b/docs/ambisonics.txt @@ -0,0 +1,119 @@ +OpenAL Soft's renderer has advanced quite a bit since its start with panned +stereo output. Among these advancements is support for surround sound output, +using psychoacoustic modeling and more accurate plane wave reconstruction. The +concepts in use may not be immediately obvious to people just getting into 3D +audio, or people who only have more indirect experience through the use of 3D +audio APIs, so this document aims to introduce the ideas and purpose of +Ambisonics as used by OpenAL Soft. + + +What Is It? +=========== + +Originally developed in the 1970s by Michael Gerzon and a team others, +Ambisonics was created as a means of recording and playing back 3D sound. +Taking advantage of the way sound waves propogate, it is possible to record a +fully 3D soundfield using as few as 4 channels (or even just 3, if you don't +mind dropping down to 2 dimensions like many surround sound systems are). This +representation is called B-Format. It was designed to handle audio independent +of any specific speaker layout, so with a proper decoder the same recording can +be played back on a variety of speaker setups, from quadrophonic and hexagonal +to cubic and other periphonic (with height) layouts. + +Although it was developed over 30 years ago, various factors held ambisonics +back from really taking hold in the consumer market. However, given the solid +theories backing it, as well as the potential and practical benefits on offer, +it continued to be a topic of research over the years, with improvements being +made over the original design. One of the improvements made is the use of +Spherical Harmonics to increase the number of channels for greater spatial +definition. Where the original 4-channel design is termed as "First-Order +Ambisonics", or FOA, the increased channel count through the use of Spherical +Harmonics is termed as "Higher-Order Ambisonics", or HOA. The details of higher +order ambisonics are out of the scope of this document, but know that the added +channels are still independent of any speaker layout, and aim to further +improve the spatial detail for playback. + +Today, the processing power available on even low-end computers means real-time +Ambisonics processing is possible. Not only can decoders be implemented in +software, but so can encoders, synthesizing a soundfield using multiple panned +sources, thus taking advantage of what ambisonics offers in a virtual audio +environment. + + +How Does It Help? +================= + +Positional sound has come a long way from pan-pot stereo (aka pair-wise). +Although useful at the time, the issues became readily apparent when trying to +extend it for surround sound. Pan-pot doesn't work as well for depth (front- +back) or vertical panning, it has a rather small "sweet spot" (the area the +head needs to be in to perceive the sound in its intended direction), and it +misses key distance-related details of sound waves. + +Ambisonics takes a different approach. It uses all available speakers to help +localize a sound, and it also takes into account how the brain localizes low +frequency sounds compared to high frequency ones -- a so-called psychoacoustic +model. It may seem counter-intuitive (if a sound is coming from the front-left, +surely just play it on the front-left speaker?), but to properly model a sound +coming from where a speaker doesn't exist, more needs to be done to construct a +proper sound wave that's perceived to come from the intended direction. Doing +this creates a larger sweet spot, allowing the perceived sound direction to +remain correct over a larger area around the center of the speakers. + + +How Is It Used? +=============== + +As a 3D audio API, OpenAL is tasked with playing 3D sound as best it can with +the speaker setup the user has. Since the OpenAL API does not explicitly handle +the output channel configuration, it has a lot of leeway in how to deal with +the audio before it's played back for the user to hear. Consequently, OpenAL +Soft (or any other OpenAL implementation that wishes to) can render using +Ambisonics and decode the ambisonic mix for a high level of directional +accuracy over what simple pan-pot could provide. + +This is effectively what the high-quality mode option does, when given an +appropriate decoder configuation for the playback channel layout. 3D rendering +is done to an ambisonic buffer, which is later decoded for output utilizing the +benefits available to ambisonic processing. + +The basic, non-high-quality, renderer uses similar principles, however it skips +the frequency-dependent processing (so low frequency sounds are treated the +same as high frequency sounds) and does some creative manipulation of the +involved math to skip the intermediate ambisonic buffer, rendering more +directly to the output while still taking advantage of all the available +speakers to reconstruct the sound wave. This method trades away some playback +quality for less memory and processor usage. + +In addition to providing good support for surround sound playback, Ambisonics +also has benefits with stereo output. 2-channel UHJ is a stereo-compatible +format that encodes some surround sound information using a wide-band 90-degree +phase shift filter. It works by taking a B-Format signal, then deriving a +frontal stereo mix with some of the rear sounds filtered in with it. Although +the result is not as good as 3-channel (2D) B-Format, it has the distinct +advantage of only using 2 channels and being compatible with stereo output. +This means it will sound just fine when played as-is through a normal stereo +device, or it may optionally be fed to a properly configured surround sound +receiver which can extract the encoded information and restore some of the +original surround sound signal. + + +What Are Its Limitations? +========================= + +As good as Ambisonics is, it's not a magic bullet that can overcome all +problems. One of the bigger issues it has is dealing with irregular speaker +setups, such as 5.1 surround sound. The problem mainly lies in the imbalanced +speaker positioning -- there are three speakers within the front 60-degree area +(meaning only 30-degree gaps in between each of the three speakers), while only +two speakers cover the back 140-degree area, leaving 80-degree gaps on the +sides. It should be noted that this problem is inherent to the speaker layout +itself; there isn't much that can be done to get an optimal surround sound +response, with ambisonics or not. It will do the best it can, but there are +trade-offs between detail and accuracy. + +Another issue lies with HRTF. While it's certainly possible to play an +ambisonic mix using HRTF, doing so with a high degree of spatial detail +requires a fair amount of resources, in both memory and processing time. And +even with it, mixing sounds with HRTF directly will still be better for +positional accuracy. diff --git a/presets/3D7.1.ambdec b/presets/3D7.1.ambdec new file mode 100644 index 00000000..42b6a0bb --- /dev/null +++ b/presets/3D7.1.ambdec @@ -0,0 +1,43 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description 3D7_2h1v_allrad_5200_rE_max_1_band + +/version 3 + +/dec/chan_mask 1bf +/dec/freq_bands 1 +/dec/speakers 7 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp output +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.500000 51.000000 24.000000 +add_spkr RF 1.500000 -51.000000 24.000000 +add_spkr CE 1.500000 0.000000 0.000000 +add_spkr LB 1.500000 180.000000 55.000000 +add_spkr RB 1.500000 0.000000 -55.000000 +add_spkr LS 1.500000 129.000000 -24.000000 +add_spkr RS 1.500000 -129.000000 -24.000000 +/} + +/matrix/{ +order_gain 1.000000 0.774597 0.400000 0.000000 +add_row 0.325031 0.357638 0.206500 0.234037 0.202440 0.135692 0.116927 -0.098768 +add_row 0.325036 -0.357619 0.206537 0.234033 -0.202427 -0.135680 0.116934 -0.098768 +add_row 0.080073 -0.000010 -0.000296 0.155843 -0.000016 -0.000011 -0.000623 0.163306 +add_row 0.353556 0.000002 0.408453 -0.288377 -0.000004 -0.000003 -0.221039 0.077297 +add_row 0.325297 0.000008 -0.414018 0.232789 0.000004 0.000003 -0.232940 0.018311 +add_row 0.353558 0.352704 -0.203542 -0.290124 -0.191868 -0.134582 0.110616 -0.038294 +add_row 0.353556 -0.352691 -0.203576 -0.290115 0.191871 0.134585 0.110612 -0.038293 +/} + +/end diff --git a/presets/hexagon.ambdec b/presets/hexagon.ambdec new file mode 100644 index 00000000..d45f2732 --- /dev/null +++ b/presets/hexagon.ambdec @@ -0,0 +1,51 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Hexagon_2h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask 11b +/dec/freq_bands 2 +/dec/speakers 6 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RS 1.000000 -90.000000 0.000000 +add_spkr RB 1.000000 -150.000000 0.000000 +add_spkr LB 1.000000 150.000000 0.000000 +add_spkr LS 1.000000 90.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 1.000000 0.000000 +add_row 0.235702 0.166667 0.288675 0.288675 0.166667 +add_row 0.235702 -0.166667 0.288675 -0.288675 0.166667 +add_row 0.235702 -0.333333 0.000000 -0.000000 -0.333333 +add_row 0.235702 -0.166667 -0.288675 0.288675 0.166667 +add_row 0.235702 0.166667 -0.288675 -0.288675 0.166667 +add_row 0.235702 0.333333 0.000000 -0.000000 -0.333333 +/} + +/hfmatrix/{ +order_gain 1.414214 1.224745 0.707107 0.000000 +add_row 0.235702 0.166667 0.288675 0.288675 0.166667 +add_row 0.235702 -0.166667 0.288675 -0.288675 0.166667 +add_row 0.235702 -0.333333 0.000000 -0.000000 -0.333333 +add_row 0.235702 -0.166667 -0.288675 0.288675 0.166667 +add_row 0.235702 0.166667 -0.288675 -0.288675 0.166667 +add_row 0.235702 0.333333 0.000000 -0.000000 -0.333333 +/} + +/end diff --git a/presets/presets.txt b/presets/presets.txt new file mode 100644 index 00000000..fcc8128f --- /dev/null +++ b/presets/presets.txt @@ -0,0 +1,36 @@ +Ambisonic decoder configuration presets are provided here for common surround +sound speaker layouts. The presets are prepared to work with OpenAL Soft's high +quality decoder. By default all of the speaker distances within a preset are +set to the same value, which results in no effect from distance compensation. +If this doesn't match your physical speaker setup, it may be worth copying the +preset and modifying the distance values to match (note that modifying the +azimuth and elevation values in the presets will not have any effect; the +specified angles do not change the decoder behavior). + +Details of the individual presets are as follows. + +square.ambdec +Specifies a basic square speaker setup for Quadrophonic output, with identical +width and depth. Front speakers are placed at +45 and -45 degrees, and back +speakers are placed at +135 and -135 degrees. + +rectangle.ambdec +Specifies a narrower speaker setup for Quadrophonic output, with a little less +width but a little more depth over a basic square setup. Front speakers are +placed at +30 and -30 degrees, providing a bit more compatibility for existing +stereo content, with back speakers at +150 and -150 degrees. + +hexagon.ambdec +Specifies a flat-front hexagonal speaker setup for 7.1 Surround output. The +front left and right speakers are placed at +30 and -30 degrees, the side +speakers are placed at +90 and -90 degrees, and the back speakers are placed at ++150 and -150 degrees. Although this is for 7.1 output, no front-center speaker +is defined for the decoder, meaning that speaker will be silent for 3D sound +(however it may still be used with AL_SOFT_direct_channels or ALC_EXT_DEDICATED +output). A "proper" 7.1 decoder may be provided in the future, but due to the +nature of the speaker configuration will have trade-offs. + +3D7.1.ambdec +Specifies a 3D7.1 speaker setup for 7.1 Surround output. Although it's for 7.1 +output, the speakers for such a configuration need to be placed in different +positions for proper results. Please see docs/3D7.1.txt for more information. diff --git a/presets/rectangle.ambdec b/presets/rectangle.ambdec new file mode 100644 index 00000000..caf72318 --- /dev/null +++ b/presets/rectangle.ambdec @@ -0,0 +1,45 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Rectangle_1h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask b +/dec/freq_bands 2 +/dec/speakers 4 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RB 1.000000 -150.000000 0.000000 +add_spkr LB 1.000000 150.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 0.000000 0.000000 +add_row 0.353553 0.500000 0.288675 +add_row 0.353553 -0.500000 0.288675 +add_row 0.353553 -0.500000 -0.288675 +add_row 0.353553 0.500000 -0.288675 +/} + +/hfmatrix/{ +order_gain 1.414214 1.000000 0.000000 0.000000 +add_row 0.353553 0.500000 0.288675 +add_row 0.353553 -0.500000 0.288675 +add_row 0.353553 -0.500000 -0.288675 +add_row 0.353553 0.500000 -0.288675 +/} + +/end diff --git a/presets/square.ambdec b/presets/square.ambdec new file mode 100644 index 00000000..547ed367 --- /dev/null +++ b/presets/square.ambdec @@ -0,0 +1,45 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Square_1h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask b +/dec/freq_bands 2 +/dec/speakers 4 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 45.000000 0.000000 +add_spkr RF 1.000000 -45.000000 0.000000 +add_spkr RB 1.000000 -135.000000 0.000000 +add_spkr LB 1.000000 135.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 0.000000 0.000000 +add_row 0.353553 0.353553 0.353553 +add_row 0.353553 -0.353553 0.353553 +add_row 0.353553 -0.353553 -0.353553 +add_row 0.353553 0.353553 -0.353553 +/} + +/hfmatrix/{ +order_gain 1.414214 1.000000 0.000000 0.000000 +add_row 0.353553 0.353553 0.353553 +add_row 0.353553 -0.353553 0.353553 +add_row 0.353553 -0.353553 -0.353553 +add_row 0.353553 0.353553 -0.353553 +/} + +/end -- cgit v1.2.3 From be7938ed385e18c7800c663672262bb2976aa734 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Apr 2016 14:54:37 -0700 Subject: Move some docs to the docs directory --- alsoft_ambdec.txt | 182 ------------------------------------------------------ docs/ambdec.txt | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/env-vars.txt | 81 ++++++++++++++++++++++++ docs/hrtf.txt | 74 ++++++++++++++++++++++ env-vars.txt | 81 ------------------------ hrtf.txt | 74 ---------------------- 6 files changed, 337 insertions(+), 337 deletions(-) delete mode 100644 alsoft_ambdec.txt create mode 100644 docs/ambdec.txt create mode 100644 docs/env-vars.txt create mode 100644 docs/hrtf.txt delete mode 100644 env-vars.txt delete mode 100644 hrtf.txt diff --git a/alsoft_ambdec.txt b/alsoft_ambdec.txt deleted file mode 100644 index 0afc5064..00000000 --- a/alsoft_ambdec.txt +++ /dev/null @@ -1,182 +0,0 @@ -AmbDec Configuration Files -========================== - -AmbDec configuration files were developed by Fons Adriaensen as part of the -AmbDec program . - -Starting with OpenAL Soft 1.18, version 3 of the file format is supported as a -means of specifying custom surround sound speaker layouts. These configuration -files are also used to enable the high-quality ambisonic decoder. - - -File Format -=========== - -As of this writing, there is no official documentation of the .ambdec file -format. However, the format as OpenAL Soft sees it is as follows: - -The file is plain text. Comments start with a hash/pound character (#). There -may be any amount of whitespace in between the option and parameter values. -Strings are *not* enclosed in quotation marks. - -/description -Specifies a text description of the configuration. Ignored by OpenAL Soft. - -/version -Declares the format version used by the configuration file. OpenAL Soft -currently only supports version 3. - -/dec/chan_mask -Specifies a hexadecimal mask value of ambisonic input channels used by this -decoder. Counting up from the least significant bit, bit 0 maps to Ambisonic -Channel Number (ACN) 0, bit 1 maps to ACN 1, etc. As an example, a value of 'b' -enables bits 0, 1, and 3 (1011 in binary), which correspond to ACN 0, 1, and 3 -(first-order horizontal). - -/dec/freq_bands -Specifies the number of frequency bands used by the decoder. This must be 1 for -single-band or 2 for dual-band. - -/dec/speakers -Specifies the number of output speakers to decode to. - -/dec/coeff_scale -Specifies the scaling used by the decoder coefficients. Currently recognized -types are fuma, sn3d, and n3d, for Furse-Malham (FuMa), semi-normalized (SN3D), -and fully normalized (N3D) scaling, respectively. - -/opt/input_scale -Specifies the scaling used by the ambisonic input data. As OpenAL Soft renders -the data itself and knows the scaling, this is ignored. - -/opt/nfeff_comp -Specifies whether near-field effect compensation is off (not applied at all), -applied on input (faster, less accurate with varying speaker distances) or -output (slower, more accurate with varying speaker distances). Ignored by -OpenAL Soft. - -/opt/delay_comp -Specifies whether delay compensation is applied for output. This is used to -correct for time variations caused by different speaker distances. As OpenAL -Soft has its own config option for this, this is ignored. - -/opt/level_comp -Specifies whether gain compensation is applied for output. This is used to -correct for volume variations caused by different speaker distances. As OpenAL -Soft has its own config option for this, this is ignored. - -/opt/xover_freq -Specifies the crossover frequency for dual-band decoders. Frequencies less than -this are fed to the low-frequency matrix, and frequencies greater than this are -fed to the high-freqyency matrix. Unused for single-band decoders. - -/opt/xover_ratio -Specifies the volume ratio between the frequency bands. Values greater than 0 -decrease the low-frequency output by half the specified value and increase the -high-frequency output by half the specified value, while values less than 0 -increase the low-frequency output and decrease the high-frequency output to -similar effect. Unused for single-band decoders. - -/speakers/{ -Begins the output speaker definitions. A speaker is defined using the add_spkr -command, and there must be a matching number of speaker definitions as the -specified speaker count. The definitions are ended with a "/}". - -add_spkr -Defines an output speaker. The ID is a string identifier for the output speaker -(see Speaker IDs below). The distance is in meters from the center-point of the -physical speaker array. The azimuth is the horizontal angle of the speaker, in -degrees, where 0 is directly front and positive values go left. The elevation -is the vertical angle of the speaker, in degrees, where 0 is directly front and -positive goes upward. The connection string is the JACK port name the speaker -should connect to. Currently, OpenAL Soft uses the ID and distance, and ignores -the rest. - -/lfmatrix/{ -Begins the low-frequency decoder matrix definition. The definition should -include an order_gain command to specify the base gain for the ambisonic -orders. Each matrix row is defined using the add_row command, and there must be -a matching number of rows as the number of speakers. Additionally the row -definitions are in the same order as the speaker definitions. The definitions -are ended with a "/}". Only valid for dual-band decoders. - -/hfmatrix/{ -Begins the high-frequency decoder matrix definition. The definition should -include an order_gain command to specify the base gain for the ambisonic -orders. Each matrix row is defined using the add_row command, and there must be -a matching number of rows as the number of speakers, Additionally the row -definitions are in the same order as the speaker definitions. The definitions -are ended with a "/}". Only valid for dual-band decoders. - -/matrix/{ -Begins the decoder matrix definition. The definition should include an -order_gain command to specify the base gain for the ambisonic orders. Each -matrix row is defined using the add_row command, and there must be a matching -number of rows as the number of speakers. Additionally the row definitions are -in the same order as the speaker definitions. The definitions are ended with a -"/}". Only valid for single-band decoders. - -order_gain -Specifies the base gain for the zeroth-, first-, second-, and third-order -coefficients in the given matrix, automatically scaling the related -coefficients. This should be specified at the beginning of the matrix -definition. - -add_row ... -Specifies a row of coefficients for the matrix. There should be one coefficient -for each enabled bit in the channel mask, and corresponds to the matching ACN -channel. - -/end -Marks the end of the configuration file. - - -Speaker IDs -=========== - -The AmbDec program uses the speaker ID as a label to display in its config -dialog, but does not otherwise use it for any particular purpose. However, -since OpenAL Soft needs to match a speaker definition to an output channel, the -speaker ID is used to identify what output channel it correspond to. Therefore, -OpenAL Soft requires these channel labels to be recognized: - -LF = Front left -RF = Front right -LS = Side left -RS = Side right -LB = Back left -RB = Back right -CE = Front center -CB = Back center - -Additionally, configuration files for surround51 will acknowledge back speakers -for side channels, and surround51rear will acknowledge side speakers for back -channels, to avoid issues with a configuration expecting 5.1 to use the side -channels when the device is configured for back, or vice-versa. - -Furthermore, OpenAL Soft does not require a speaker definition for each output -channel the configuration is used with. So for example a 5.1 configuration may -omit a front center speaker definition, in which case the front center output -channel will not contribute to the ambisonic decode (though OpenAL Soft will -still use it in certain scenarios, such as the AL_EFFECT_DEDICATED_DIALOGUE -effect). - - -Creating Configuration Files -============================ - -Configuration files can be created or modified by hand in a text editor. The -AmbDec program also has a GUI for creating and editing them. However, these -methods rely on you having the coefficients to fill in... they won't be -generated for you. - -Another option is to use the Ambisonic Decoder Toolbox -. This is a collection of -MATLAB and GNU Octave scripts that can generate AmbDec configuration files from -an array of speaker definitions (labels and positions). If you're familiar with -using MATLAB or GNU Octave, this may be a good option. - -There are plans for OpenAL Soft to include a utility to generate coefficients -and make configuration files. However, calculating proper coefficients for -anything other than regular or semi-regular speaker setups is somewhat of a -black art, so may take some time. diff --git a/docs/ambdec.txt b/docs/ambdec.txt new file mode 100644 index 00000000..0afc5064 --- /dev/null +++ b/docs/ambdec.txt @@ -0,0 +1,182 @@ +AmbDec Configuration Files +========================== + +AmbDec configuration files were developed by Fons Adriaensen as part of the +AmbDec program . + +Starting with OpenAL Soft 1.18, version 3 of the file format is supported as a +means of specifying custom surround sound speaker layouts. These configuration +files are also used to enable the high-quality ambisonic decoder. + + +File Format +=========== + +As of this writing, there is no official documentation of the .ambdec file +format. However, the format as OpenAL Soft sees it is as follows: + +The file is plain text. Comments start with a hash/pound character (#). There +may be any amount of whitespace in between the option and parameter values. +Strings are *not* enclosed in quotation marks. + +/description +Specifies a text description of the configuration. Ignored by OpenAL Soft. + +/version +Declares the format version used by the configuration file. OpenAL Soft +currently only supports version 3. + +/dec/chan_mask +Specifies a hexadecimal mask value of ambisonic input channels used by this +decoder. Counting up from the least significant bit, bit 0 maps to Ambisonic +Channel Number (ACN) 0, bit 1 maps to ACN 1, etc. As an example, a value of 'b' +enables bits 0, 1, and 3 (1011 in binary), which correspond to ACN 0, 1, and 3 +(first-order horizontal). + +/dec/freq_bands +Specifies the number of frequency bands used by the decoder. This must be 1 for +single-band or 2 for dual-band. + +/dec/speakers +Specifies the number of output speakers to decode to. + +/dec/coeff_scale +Specifies the scaling used by the decoder coefficients. Currently recognized +types are fuma, sn3d, and n3d, for Furse-Malham (FuMa), semi-normalized (SN3D), +and fully normalized (N3D) scaling, respectively. + +/opt/input_scale +Specifies the scaling used by the ambisonic input data. As OpenAL Soft renders +the data itself and knows the scaling, this is ignored. + +/opt/nfeff_comp +Specifies whether near-field effect compensation is off (not applied at all), +applied on input (faster, less accurate with varying speaker distances) or +output (slower, more accurate with varying speaker distances). Ignored by +OpenAL Soft. + +/opt/delay_comp +Specifies whether delay compensation is applied for output. This is used to +correct for time variations caused by different speaker distances. As OpenAL +Soft has its own config option for this, this is ignored. + +/opt/level_comp +Specifies whether gain compensation is applied for output. This is used to +correct for volume variations caused by different speaker distances. As OpenAL +Soft has its own config option for this, this is ignored. + +/opt/xover_freq +Specifies the crossover frequency for dual-band decoders. Frequencies less than +this are fed to the low-frequency matrix, and frequencies greater than this are +fed to the high-freqyency matrix. Unused for single-band decoders. + +/opt/xover_ratio +Specifies the volume ratio between the frequency bands. Values greater than 0 +decrease the low-frequency output by half the specified value and increase the +high-frequency output by half the specified value, while values less than 0 +increase the low-frequency output and decrease the high-frequency output to +similar effect. Unused for single-band decoders. + +/speakers/{ +Begins the output speaker definitions. A speaker is defined using the add_spkr +command, and there must be a matching number of speaker definitions as the +specified speaker count. The definitions are ended with a "/}". + +add_spkr +Defines an output speaker. The ID is a string identifier for the output speaker +(see Speaker IDs below). The distance is in meters from the center-point of the +physical speaker array. The azimuth is the horizontal angle of the speaker, in +degrees, where 0 is directly front and positive values go left. The elevation +is the vertical angle of the speaker, in degrees, where 0 is directly front and +positive goes upward. The connection string is the JACK port name the speaker +should connect to. Currently, OpenAL Soft uses the ID and distance, and ignores +the rest. + +/lfmatrix/{ +Begins the low-frequency decoder matrix definition. The definition should +include an order_gain command to specify the base gain for the ambisonic +orders. Each matrix row is defined using the add_row command, and there must be +a matching number of rows as the number of speakers. Additionally the row +definitions are in the same order as the speaker definitions. The definitions +are ended with a "/}". Only valid for dual-band decoders. + +/hfmatrix/{ +Begins the high-frequency decoder matrix definition. The definition should +include an order_gain command to specify the base gain for the ambisonic +orders. Each matrix row is defined using the add_row command, and there must be +a matching number of rows as the number of speakers, Additionally the row +definitions are in the same order as the speaker definitions. The definitions +are ended with a "/}". Only valid for dual-band decoders. + +/matrix/{ +Begins the decoder matrix definition. The definition should include an +order_gain command to specify the base gain for the ambisonic orders. Each +matrix row is defined using the add_row command, and there must be a matching +number of rows as the number of speakers. Additionally the row definitions are +in the same order as the speaker definitions. The definitions are ended with a +"/}". Only valid for single-band decoders. + +order_gain +Specifies the base gain for the zeroth-, first-, second-, and third-order +coefficients in the given matrix, automatically scaling the related +coefficients. This should be specified at the beginning of the matrix +definition. + +add_row ... +Specifies a row of coefficients for the matrix. There should be one coefficient +for each enabled bit in the channel mask, and corresponds to the matching ACN +channel. + +/end +Marks the end of the configuration file. + + +Speaker IDs +=========== + +The AmbDec program uses the speaker ID as a label to display in its config +dialog, but does not otherwise use it for any particular purpose. However, +since OpenAL Soft needs to match a speaker definition to an output channel, the +speaker ID is used to identify what output channel it correspond to. Therefore, +OpenAL Soft requires these channel labels to be recognized: + +LF = Front left +RF = Front right +LS = Side left +RS = Side right +LB = Back left +RB = Back right +CE = Front center +CB = Back center + +Additionally, configuration files for surround51 will acknowledge back speakers +for side channels, and surround51rear will acknowledge side speakers for back +channels, to avoid issues with a configuration expecting 5.1 to use the side +channels when the device is configured for back, or vice-versa. + +Furthermore, OpenAL Soft does not require a speaker definition for each output +channel the configuration is used with. So for example a 5.1 configuration may +omit a front center speaker definition, in which case the front center output +channel will not contribute to the ambisonic decode (though OpenAL Soft will +still use it in certain scenarios, such as the AL_EFFECT_DEDICATED_DIALOGUE +effect). + + +Creating Configuration Files +============================ + +Configuration files can be created or modified by hand in a text editor. The +AmbDec program also has a GUI for creating and editing them. However, these +methods rely on you having the coefficients to fill in... they won't be +generated for you. + +Another option is to use the Ambisonic Decoder Toolbox +. This is a collection of +MATLAB and GNU Octave scripts that can generate AmbDec configuration files from +an array of speaker definitions (labels and positions). If you're familiar with +using MATLAB or GNU Octave, this may be a good option. + +There are plans for OpenAL Soft to include a utility to generate coefficients +and make configuration files. However, calculating proper coefficients for +anything other than regular or semi-regular speaker setups is somewhat of a +black art, so may take some time. diff --git a/docs/env-vars.txt b/docs/env-vars.txt new file mode 100644 index 00000000..b2268643 --- /dev/null +++ b/docs/env-vars.txt @@ -0,0 +1,81 @@ +Useful Environment Variables + +Below is a list of environment variables that can be set to aid with running or +debugging apps that use OpenAL Soft. They should be set before the app is run. + +*** Logging *** + +ALSOFT_LOGLEVEL +Specifies the amount of logging OpenAL Soft will write out: +0 - Effectively disables all logging +1 - Prints out errors only +2 - Prints out warnings and errors +3 - Prints out additional information, as well as warnings and errors +4 - Same as 3, but also device and context reference count changes. This will + print out *a lot* of info, and is generally not useful unless you're trying + to track a reference leak within the library. + +ALSOFT_LOGFILE +Specifies a filename that logged output will be written to. Note that the file +will be first cleared when logging is initialized. + +*** Overrides *** + +ALSOFT_CONF +Specifies an additional configuration file to load settings from. These +settings will take precedence over the global and user configs, but not other +environment variable settings. + +ALSOFT_DRIVERS +Overrides the drivers config option. This specifies which backend drivers to +consider or not consider for use. Please see the drivers option in +alsoftrc.sample for a list of available drivers. + +ALSOFT_DEFAULT_REVERB +Specifies the default reverb preset to apply to sources. Please see the +default-reverb option in alsoftrc.sample for additional information and a list +of available presets. + +ALSOFT_TRAP_AL_ERROR +Set to "true" or "1" to force trapping AL errors. Like the trap-al-error config +option, this will raise a SIGTRAP signal (or a breakpoint exception under +Windows) when a context-level error is generated. Useful when run under a +debugger as it will break execution right when the error occurs, making it +easier to track the cause. + +ALSOFT_TRAP_ALC_ERROR +Set to "true" or "1" to force trapping ALC errors. Like the trap-alc-error +config option, this will raise a SIGTRAP signal (or a breakpoint exception +under Windows) when a device-level error is generated. Useful when run under a +debugger as it will break execution right when the error occurs, making it +easier to track the cause. + +ALSOFT_TRAP_ERROR +Set to "true" or "1" to force trapping both ALC and AL errors. + +*** Compatibility *** + +__ALSOFT_HALF_ANGLE_CONES +Older versions of OpenAL Soft incorrectly calculated the cone angles to range +between 0 and 180 degrees, instead of the expected range of 0 to 360 degrees. +Setting this to "true" or "1" restores the old buggy behavior, for apps that +were written to expect the incorrect range. + +__ALSOFT_REVERSE_Z +Applications that don't natively use OpenAL's coordinate system have to convert +to it before passing in 3D coordinates. Depending on how exactly this is done, +it can cause correct output for stereo but incorrect Z panning for surround +sound (i.e., sounds that are supposed to be behind you sound like they're in +front, and vice-versa). Setting this to "true" or "1" will negate the localized +Z coordinate to attempt to fix output for apps that have incorrect front/back +panning. + +__ALSOFT_SUSPEND_CONTEXT +Due to the OpenAL spec not being very clear about them, behavior of the +alcSuspendContext and alcProcessContext methods has varied, and because of +that, previous versions of OpenAL Soft had them no-op. Creative's hardware +drivers and the Rapture3D driver, however, use these methods to batch changes, +which some applications make use of to protect against partial updates. In an +attempt to standardize on that behavior, OpenAL Soft has changed those methods +accordingly. Setting this to "ignore" restores the previous no-op behavior for +applications that interact poorly with the new behavior. diff --git a/docs/hrtf.txt b/docs/hrtf.txt new file mode 100644 index 00000000..37a329d2 --- /dev/null +++ b/docs/hrtf.txt @@ -0,0 +1,74 @@ +HRTF Support +============ + +Starting with OpenAL Soft 1.14, HRTFs can be used to enable enhanced +spatialization for both 3D (mono) and multi-channel sources, when used with +headphones/stereo output. This can be enabled using the 'hrtf' config option. + +For multi-channel sources this creates a virtual speaker effect, making it +sound as if speakers provide a discrete position for each channel around the +listener. For mono sources this provides much more versatility in the perceived +placement of sounds, making it seem as though they are coming from all around, +including above and below the listener, instead of just to the front, back, and +sides. + +The default data set is based on the KEMAR HRTF data provided by MIT, which can +be found at . It's only +available when using 44100hz or 48000hz playback. + + +Custom HRTF Data Sets +===================== + +OpenAL Soft also provides an option to use user-specified data sets, in +addition to or in place of the default set. This allows users to provide their +own data sets, which could be better suited for their heads, or to work with +stereo speakers instead of headphones, or to support more playback sample +rates, for example. + +The file format is specified below. It uses little-endian byte order. + +== +ALchar magic[8] = "MinPHR01"; +ALuint sampleRate; + +ALubyte hrirSize; /* Can be 8 to 128 in steps of 8. */ +ALubyte evCount; /* Can be 5 to 128. */ + +ALubyte azCount[evCount]; /* Each can be 1 to 128. */ + +/* NOTE: hrirCount is the sum of all azCounts */ +ALshort coefficients[hrirCount][hrirSize]; +ALubyte delays[hrirCount]; /* Each can be 0 to 63. */ +== + +The data is described as thus: + +The file first starts with the 8-byte marker, "MinPHR01", to identify it as an +HRTF data set. This is followed by an unsigned 32-bit integer, specifying the +sample rate the data set is designed for (OpenAL Soft will not use it if the +output device's playback rate doesn't match). + +Afterward, an unsigned 8-bit integer specifies how many sample points (or +finite impulse response filter coefficients) make up each HRIR. + +The following unsigned 8-bit integer specifies the number of elevations used +by the data set. The elevations start at the bottom (-90 degrees), and +increment upwards. Following this is an array of unsigned 8-bit integers, one +for each elevation which specifies the number of azimuths (and thus HRIRs) that +make up each elevation. Azimuths start clockwise from the front, constructing +a full circle for the left ear only. The right ear uses the same HRIRs but in +reverse (ie, left = angle, right = 360-angle). + +The actual coefficients follow. Each coefficient is a signed 16-bit sample, +with each HRIR being a consecutive number of sample points. The HRIRs must be +minimum-phase. This allows the use of a smaller filter length, reducing +computation. For reference, the built-in data set uses a 32-point filter while +even the smallest data set provided by MIT used a 128-sample filter (a 4x +reduction by applying minimum-phase reconstruction). Theoretically, one could +further reduce the minimum-phase version down to a 16-point filter with only a +small reduction in quality. + +After the coefficients is an array of unsigned 8-bit delay values, one for +each HRIR. This is the propagation delay (in samples) a signal must wait before +being convolved with the corresponding minimum-phase HRIR filter. diff --git a/env-vars.txt b/env-vars.txt deleted file mode 100644 index b2268643..00000000 --- a/env-vars.txt +++ /dev/null @@ -1,81 +0,0 @@ -Useful Environment Variables - -Below is a list of environment variables that can be set to aid with running or -debugging apps that use OpenAL Soft. They should be set before the app is run. - -*** Logging *** - -ALSOFT_LOGLEVEL -Specifies the amount of logging OpenAL Soft will write out: -0 - Effectively disables all logging -1 - Prints out errors only -2 - Prints out warnings and errors -3 - Prints out additional information, as well as warnings and errors -4 - Same as 3, but also device and context reference count changes. This will - print out *a lot* of info, and is generally not useful unless you're trying - to track a reference leak within the library. - -ALSOFT_LOGFILE -Specifies a filename that logged output will be written to. Note that the file -will be first cleared when logging is initialized. - -*** Overrides *** - -ALSOFT_CONF -Specifies an additional configuration file to load settings from. These -settings will take precedence over the global and user configs, but not other -environment variable settings. - -ALSOFT_DRIVERS -Overrides the drivers config option. This specifies which backend drivers to -consider or not consider for use. Please see the drivers option in -alsoftrc.sample for a list of available drivers. - -ALSOFT_DEFAULT_REVERB -Specifies the default reverb preset to apply to sources. Please see the -default-reverb option in alsoftrc.sample for additional information and a list -of available presets. - -ALSOFT_TRAP_AL_ERROR -Set to "true" or "1" to force trapping AL errors. Like the trap-al-error config -option, this will raise a SIGTRAP signal (or a breakpoint exception under -Windows) when a context-level error is generated. Useful when run under a -debugger as it will break execution right when the error occurs, making it -easier to track the cause. - -ALSOFT_TRAP_ALC_ERROR -Set to "true" or "1" to force trapping ALC errors. Like the trap-alc-error -config option, this will raise a SIGTRAP signal (or a breakpoint exception -under Windows) when a device-level error is generated. Useful when run under a -debugger as it will break execution right when the error occurs, making it -easier to track the cause. - -ALSOFT_TRAP_ERROR -Set to "true" or "1" to force trapping both ALC and AL errors. - -*** Compatibility *** - -__ALSOFT_HALF_ANGLE_CONES -Older versions of OpenAL Soft incorrectly calculated the cone angles to range -between 0 and 180 degrees, instead of the expected range of 0 to 360 degrees. -Setting this to "true" or "1" restores the old buggy behavior, for apps that -were written to expect the incorrect range. - -__ALSOFT_REVERSE_Z -Applications that don't natively use OpenAL's coordinate system have to convert -to it before passing in 3D coordinates. Depending on how exactly this is done, -it can cause correct output for stereo but incorrect Z panning for surround -sound (i.e., sounds that are supposed to be behind you sound like they're in -front, and vice-versa). Setting this to "true" or "1" will negate the localized -Z coordinate to attempt to fix output for apps that have incorrect front/back -panning. - -__ALSOFT_SUSPEND_CONTEXT -Due to the OpenAL spec not being very clear about them, behavior of the -alcSuspendContext and alcProcessContext methods has varied, and because of -that, previous versions of OpenAL Soft had them no-op. Creative's hardware -drivers and the Rapture3D driver, however, use these methods to batch changes, -which some applications make use of to protect against partial updates. In an -attempt to standardize on that behavior, OpenAL Soft has changed those methods -accordingly. Setting this to "ignore" restores the previous no-op behavior for -applications that interact poorly with the new behavior. diff --git a/hrtf.txt b/hrtf.txt deleted file mode 100644 index 37a329d2..00000000 --- a/hrtf.txt +++ /dev/null @@ -1,74 +0,0 @@ -HRTF Support -============ - -Starting with OpenAL Soft 1.14, HRTFs can be used to enable enhanced -spatialization for both 3D (mono) and multi-channel sources, when used with -headphones/stereo output. This can be enabled using the 'hrtf' config option. - -For multi-channel sources this creates a virtual speaker effect, making it -sound as if speakers provide a discrete position for each channel around the -listener. For mono sources this provides much more versatility in the perceived -placement of sounds, making it seem as though they are coming from all around, -including above and below the listener, instead of just to the front, back, and -sides. - -The default data set is based on the KEMAR HRTF data provided by MIT, which can -be found at . It's only -available when using 44100hz or 48000hz playback. - - -Custom HRTF Data Sets -===================== - -OpenAL Soft also provides an option to use user-specified data sets, in -addition to or in place of the default set. This allows users to provide their -own data sets, which could be better suited for their heads, or to work with -stereo speakers instead of headphones, or to support more playback sample -rates, for example. - -The file format is specified below. It uses little-endian byte order. - -== -ALchar magic[8] = "MinPHR01"; -ALuint sampleRate; - -ALubyte hrirSize; /* Can be 8 to 128 in steps of 8. */ -ALubyte evCount; /* Can be 5 to 128. */ - -ALubyte azCount[evCount]; /* Each can be 1 to 128. */ - -/* NOTE: hrirCount is the sum of all azCounts */ -ALshort coefficients[hrirCount][hrirSize]; -ALubyte delays[hrirCount]; /* Each can be 0 to 63. */ -== - -The data is described as thus: - -The file first starts with the 8-byte marker, "MinPHR01", to identify it as an -HRTF data set. This is followed by an unsigned 32-bit integer, specifying the -sample rate the data set is designed for (OpenAL Soft will not use it if the -output device's playback rate doesn't match). - -Afterward, an unsigned 8-bit integer specifies how many sample points (or -finite impulse response filter coefficients) make up each HRIR. - -The following unsigned 8-bit integer specifies the number of elevations used -by the data set. The elevations start at the bottom (-90 degrees), and -increment upwards. Following this is an array of unsigned 8-bit integers, one -for each elevation which specifies the number of azimuths (and thus HRIRs) that -make up each elevation. Azimuths start clockwise from the front, constructing -a full circle for the left ear only. The right ear uses the same HRIRs but in -reverse (ie, left = angle, right = 360-angle). - -The actual coefficients follow. Each coefficient is a signed 16-bit sample, -with each HRIR being a consecutive number of sample points. The HRIRs must be -minimum-phase. This allows the use of a smaller filter length, reducing -computation. For reference, the built-in data set uses a 32-point filter while -even the smallest data set provided by MIT used a 128-sample filter (a 4x -reduction by applying minimum-phase reconstruction). Theoretically, one could -further reduce the minimum-phase version down to a 16-point filter with only a -small reduction in quality. - -After the coefficients is an array of unsigned 8-bit delay values, one for -each HRIR. This is the propagation delay (in samples) a signal must wait before -being convolved with the corresponding minimum-phase HRIR filter. -- cgit v1.2.3 From c6a11770c591fb65f1dfad0c8775efac500b3413 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Apr 2016 15:01:44 -0700 Subject: Add some general info about how ambdec works to ambdec.txt --- docs/ambdec.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/ambdec.txt b/docs/ambdec.txt index 0afc5064..5a3ba988 100644 --- a/docs/ambdec.txt +++ b/docs/ambdec.txt @@ -4,6 +4,13 @@ AmbDec Configuration Files AmbDec configuration files were developed by Fons Adriaensen as part of the AmbDec program . +The file works by specifying a decoder matrix or matrices which transform +ambisonic channels into speaker feeds. Single-band decoders specify a single +matrix that transforms all frequencies, while dual-band decoders specifies two +matrices where one transforms low frequency sounds and the other transforms +high frequency sounds. See docs/ambisonics.txt for more general information +about ambisonics. + Starting with OpenAL Soft 1.18, version 3 of the file format is supported as a means of specifying custom surround sound speaker layouts. These configuration files are also used to enable the high-quality ambisonic decoder. -- cgit v1.2.3 From c2dec5008b02a3d85669036a4096430ce91275f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Apr 2016 17:29:51 -0700 Subject: Install the ambdec preset files --- CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c89a0d5..b713e261 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ OPTION(ALSOFT_TESTS "Build and install test programs" ON) OPTION(ALSOFT_CONFIG "Install alsoft.conf sample configuration file" ON) OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON) +OPTION(ALSOFT_AMBDEC_PRESETS "Install AmbDec preset files" ON) OPTION(ALSOFT_INSTALL "Install headers and libraries" ON) @@ -1227,6 +1228,19 @@ IF(ALSOFT_HRTF_DEFS) MESSAGE(STATUS "") ENDIF() +# Install AmbDec presets +IF(ALSOFT_AMBDEC_PRESETS) + INSTALL(FILES presets/3D7.1.ambdec + presets/hexagon.ambdec + presets/rectangle.ambdec + presets/square.ambdec + presets/presets.txt + DESTINATION ${SHARE_INSTALL_DIR}/openal/presets + ) + MESSAGE(STATUS "Installing HRTF definitions") + MESSAGE(STATUS "") +ENDIF() + IF(ALSOFT_UTILS) ADD_EXECUTABLE(openal-info utils/openal-info.c) TARGET_LINK_LIBRARIES(openal-info ${LIBNAME}) -- cgit v1.2.3 From c796f99d3614f023800a5db5d1b031866c7e5b4c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Apr 2016 17:31:34 -0700 Subject: Open the file selector to an existing path for presets --- utils/alsoft-config/mainwindow.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4d286367..8f703f7f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1,6 +1,7 @@ #include "config.h" +#include #include #include @@ -1091,8 +1092,22 @@ void MainWindow::select71DecoderFile() { selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) { + QString dir = line->text(); + if(dir.isEmpty() || QDir::isRelativePath(dir)) + { + QStringList paths = getAllDataPaths("/openal/presets"); + while(!paths.isEmpty()) + { + if(QDir(paths.last()).exists()) + { + dir = paths.last(); + break; + } + paths.removeLast(); + } + } QString fname = QFileDialog::getOpenFileName(this, tr(caption), - line->text(), tr("AmbDec Files (*.ambdec);;All Files (*.*)") + dir, tr("AmbDec Files (*.ambdec);;All Files (*.*)") ); if(!fname.isEmpty()) { -- cgit v1.2.3 From fdee577940a4669e9723a16c4c625567694589ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Apr 2016 21:08:59 -0700 Subject: Provide a decoder preset for 5.1 Surround output --- CMakeLists.txt | 1 + presets/itu5.1.ambdec | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ presets/presets.txt | 6 ++++++ 3 files changed, 55 insertions(+) create mode 100644 presets/itu5.1.ambdec diff --git a/CMakeLists.txt b/CMakeLists.txt index b713e261..6deb43a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1232,6 +1232,7 @@ ENDIF() IF(ALSOFT_AMBDEC_PRESETS) INSTALL(FILES presets/3D7.1.ambdec presets/hexagon.ambdec + presets/itu5.1.ambdec presets/rectangle.ambdec presets/square.ambdec presets/presets.txt diff --git a/presets/itu5.1.ambdec b/presets/itu5.1.ambdec new file mode 100644 index 00000000..74386034 --- /dev/null +++ b/presets/itu5.1.ambdec @@ -0,0 +1,48 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description itu50_2h0p_allrad_5200_rE_max_1_band + +/version 3 + +/dec/chan_mask 11b +/dec/freq_bands 2 +/dec/speakers 5 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp output +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 3.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LS 1.000000 110.000000 0.000000 +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr CE 1.000000 0.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RS 1.000000 -110.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 1.000000 0.000000 +add_row 0.420330 0.330200 -0.312250 0.019350 -0.027010 +add_row 0.197700 0.288820 0.287820 0.049110 0.007420 +add_row 0.058030 0.000000 0.205970 0.000000 0.050790 +add_row 0.197700 -0.288820 0.287820 -0.049110 0.007420 +add_row 0.420330 -0.330200 -0.312250 -0.019350 -0.027010 +/} + +/hfmatrix/{ +order_gain 1.000000 0.866025 0.500000 0.000000 +add_row 0.470934 0.378170 -0.400085 -0.082226 -0.044377 +add_row 0.208954 0.257988 0.230383 0.288520 -0.025085 +add_row 0.109403 -0.000002 0.194278 -0.000003 0.200863 +add_row 0.208950 -0.257989 0.230379 -0.288516 -0.025088 +add_row 0.470936 -0.378173 -0.400081 0.082228 -0.044372 +/} + +/end diff --git a/presets/presets.txt b/presets/presets.txt index fcc8128f..94968720 100644 --- a/presets/presets.txt +++ b/presets/presets.txt @@ -20,6 +20,12 @@ width but a little more depth over a basic square setup. Front speakers are placed at +30 and -30 degrees, providing a bit more compatibility for existing stereo content, with back speakers at +150 and -150 degrees. +itu5.1.ambdec +Specifies a standard ITU 5.0/5.1 setup for 5.1 Surround output. The front- +center speaker is placed directly in front at 0 degrees, with the front-left +and front-right at +30 and -30 degrees, and the surround speakers (side or +back) at +110 and -110 degrees. + hexagon.ambdec Specifies a flat-front hexagonal speaker setup for 7.1 Surround output. The front left and right speakers are placed at +30 and -30 degrees, the side -- cgit v1.2.3 From f0871c8cfcb329e847fd48256fd32f20d2c7e827 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Apr 2016 21:42:59 -0700 Subject: Improve radius behavior with scaling of ambisonic coefficients --- Alc/ALu.c | 57 ++++++++++++++++++++----------------------------- Alc/bformatdec.c | 26 +++++++++++----------- Alc/effects/chorus.c | 4 ++-- Alc/effects/dedicated.c | 2 +- Alc/effects/echo.c | 14 ++++++++---- Alc/effects/flanger.c | 4 ++-- Alc/effects/reverb.c | 12 +++++------ Alc/hrtf.c | 5 ++++- Alc/hrtf.h | 2 +- Alc/panning.c | 57 ++++++++++++++++++++++++++++++++++++++++++++----- OpenAL32/Include/alu.h | 11 +++++----- 11 files changed, 120 insertions(+), 74 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 6d07afe2..e137a904 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -567,7 +567,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A * channel-match. */ for(c = 0;c < num_channels;c++) { - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); for(i = 0;i < NumSends;i++) { @@ -618,13 +618,13 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Get the static HRIR coefficients and delays for this channel. */ GetLerpedHrtfCoeffs(Device->Hrtf, - chans[c].elevation, chans[c].angle, 1.0f, DryGain, + chans[c].elevation, chans[c].angle, 0.0f, DryGain, voice->Direct.Hrtf[c].Target.Coeffs, voice->Direct.Hrtf[c].Target.Delay ); /* Normal panning for auxiliary sends. */ - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); for(i = 0;i < NumSends;i++) { @@ -680,11 +680,11 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Gains[c].Target[j] = 0.0f; - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); } else { - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, DryGain, voice->Direct.Gains[c].Target); } @@ -1091,8 +1091,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }}; ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; - ALfloat dirfact = 1.0f; ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat spread = 0.0f; voice->Direct.OutBuffer = Device->RealOut.Buffer; voice->Direct.OutChannels = Device->RealOut.NumChannels; @@ -1110,23 +1110,17 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ev = asinf(clampf(dir.v[1], -1.0f, 1.0f)); az = atan2f(dir.v[0], -dir.v[2]); } - if(radius > 0.0f) - { - if(radius >= Distance) - dirfact *= Distance / radius * 0.5f; - else - dirfact *= 1.0f - (asinf(radius / Distance) / F_PI); - } + if(radius > Distance) + spread = F_TAU - Distance/radius*F_PI; + else if(Distance > FLT_EPSILON) + spread = asinf(radius / Distance) * 2.0f; /* Get the HRIR coefficients and delays. */ - GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, + GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, spread, DryGain, voice->Direct.Hrtf[0].Target.Coeffs, voice->Direct.Hrtf[0].Target.Delay); - dir.v[0] *= dirfact; - dir.v[1] *= dirfact; - dir.v[2] *= dirfact; - CalcDirectionCoeffs(dir.v, coeffs); + CalcDirectionCoeffs(dir.v, spread, coeffs); for(i = 0;i < NumSends;i++) { @@ -1152,6 +1146,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat spread = 0.0f; /* Get the localized direction, and compute panned gains. */ if(Distance > FLT_EPSILON) @@ -1160,32 +1155,26 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte dir[1] = -SourceToListener.v[1]; dir[2] = -SourceToListener.v[2] * ZScale; } - if(radius > 0.0f) - { - ALfloat dirfact; - if(radius >= Distance) - dirfact = Distance / radius * 0.5f; - else - dirfact = 1.0f - (asinf(radius / Distance) / F_PI); - dir[0] *= dirfact; - dir[1] *= dirfact; - dir[2] *= dirfact; - } + if(radius > Distance) + spread = F_TAU - Distance/radius*F_PI; + else if(Distance > FLT_EPSILON) + spread = asinf(radius / Distance) * 2.0f; if(Device->Render_Mode == StereoPair) { /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ - coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5f; - voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain; - voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain; + ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f)); + x = clampf(x, -0.5f, 0.5f) + 0.5f; + voice->Direct.Gains[0].Target[0] = x * DryGain; + voice->Direct.Gains[0].Target[1] = (1.0f-x) * DryGain; for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) voice->Direct.Gains[0].Target[i] = 0.0f; - CalcDirectionCoeffs(dir, coeffs); + CalcDirectionCoeffs(dir, spread, coeffs); } else { - CalcDirectionCoeffs(dir, coeffs); + CalcDirectionCoeffs(dir, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, DryGain, voice->Direct.Gains[0].Target); } diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index dd0561d0..e32053c8 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -150,19 +150,19 @@ static void init_encoder(void) { ALuint i, j; - CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[0]); - CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, CubeEncoder[1]); - CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[2]); - CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, CubeEncoder[3]); - CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[4]); - CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, CubeEncoder[5]); - CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[6]); - CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, CubeEncoder[7]); - - CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, SquareEncoder[0]); - CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, SquareEncoder[1]); - CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, SquareEncoder[2]); - CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, SquareEncoder[3]); + CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[0]); + CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[1]); + CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[2]); + CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[3]); + CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[4]); + CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[5]); + CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[6]); + CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[7]); + + CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[0]); + CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[1]); + CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[2]); + CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[3]); for(i = 0;i < 4;i++) { diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 94c9fc47..9deb2a1f 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -112,9 +112,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ - CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); - CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 12b16137..f510e8fe 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -78,7 +78,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * else { ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcXYZCoeffs(0.0f, 0.0f, -1.0f, coeffs); + CalcXYZCoeffs(0.0f, 0.0f, -1.0f, 0.0f, coeffs); STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 9fd31864..8600db70 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -85,13 +85,19 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co { ALuint frequency = Device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat gain, lrpan; + ALfloat gain, lrpan, spread; 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; + spread = Slot->EffectProps.Echo.Spread; + if(spread < 0.0f) lrpan = -1.0f; + else lrpan = 1.0f; + /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage + * spread (where 0 = point, tau = omni). + */ + spread = asinf(1.0f - fabsf(spread))*4.0f; state->FeedGain = Slot->EffectProps.Echo.Feedback; @@ -103,11 +109,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co gain = Slot->Gain; /* First tap panning */ - CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]); /* Second tap panning */ - CalcXYZCoeffs( lrpan, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs( lrpan, 0.0f, 0.0f, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]); } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index e394f9f2..a71eb9c2 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -112,9 +112,9 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency); /* Gains for left and right sides */ - CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); - CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, coeffs); + CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Flanger.Phase; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index bb980ac2..ef3ab6c3 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -719,7 +719,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect }; length = minf(length, 1.0f); - CalcDirectionCoeffs(pan, coeffs); + CalcDirectionCoeffs(pan, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; @@ -743,7 +743,7 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect }; length = minf(length, 1.0f); - CalcDirectionCoeffs(pan, coeffs); + CalcDirectionCoeffs(pan, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; @@ -783,7 +783,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec }; length = minf(length, 1.0f); - CalcDirectionCoeffs(pan, coeffs); + CalcDirectionCoeffs(pan, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; @@ -805,7 +805,7 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec }; length = minf(length, 1.0f); - CalcDirectionCoeffs(pan, coeffs); + CalcDirectionCoeffs(pan, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); for(i = 0;i < Device->Dry.NumChannels;i++) State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; @@ -855,7 +855,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection } for(i = 0;i < 4;i++) { - CalcDirectionCoeffs(PanDirs[i], coeffs); + CalcDirectionCoeffs(PanDirs[i], 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain*EarlyGain*gain[i], State->Early.PanGain[i]); } @@ -886,7 +886,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection } for(i = 0;i < 4;i++) { - CalcDirectionCoeffs(PanDirs[i], coeffs); + CalcDirectionCoeffs(PanDirs[i], 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Gain*LateGain*gain[i], State->Late.PanGain[i]); } diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9549c010..1f972f87 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -96,12 +96,15 @@ static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *az * increase the apparent resolution of the HRIR data set. The coefficients * are also normalized and attenuated by the specified gain. */ -void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) +void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) { ALuint evidx[2], lidx[4], ridx[4]; ALfloat mu[3], blend[4]; + ALfloat dirfact; ALuint i; + dirfact = 1.0f - (spread / F_TAU); + /* Claculate elevation indices and interpolation factor. */ CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 2b96a583..e8a127c7 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -30,6 +30,6 @@ void FreeHrtfList(vector_HrtfEntry *list); ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf); ALuint GetHrtfIrSize(const struct Hrtf *Hrtf); -void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); +void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 51b8e5cc..9ff97477 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -36,7 +36,7 @@ #include "bs2b.h" -extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); #define ZERO_ORDER_SCALE 0.0f @@ -109,7 +109,7 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; -void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]) +void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { /* Convert from OpenAL coords to Ambisonics. */ ALfloat x = -dir[2]; @@ -136,16 +136,63 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]) coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + + if(spread > 0.0f) + { + /* Implement the spread by using a spherical source that subtends the + * angle spread. See: + * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 + * + * The gain of the source is compensated for size, so that the + * loundness doesn't depend on the spread. + * + * ZH0 = (-sqrt_pi * (-1.f + ca)); + * ZH1 = ( 0.5f*sqrtf(3.f)*sqrt_pi * sa*sa); + * ZH2 = (-0.5f*sqrtf(5.f)*sqrt_pi * ca*(-1.f+ca)*(ca+1.f)); + * ZH3 = (-0.125f*sqrtf(7.f)*sqrt_pi * (-1.f+ca)*(ca+1.f)*(5.f*ca*ca-1.f)); + * solidangle = 2.f*F_PI*(1.f-ca) + * size_normalisation_coef = 1.f/ZH0; + * + * This is then adjusted for N3D normalization over SN3D. + */ + ALfloat ca = cosf(spread * 0.5f); + + ALfloat ZH0_norm = 1.0f; + ALfloat ZH1_norm = 0.5f * (ca+1.f); + ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca; + ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f); + + /* Zeroth-order */ + coeffs[0] *= ZH0_norm; + /* First-order */ + coeffs[1] *= ZH1_norm; + coeffs[2] *= ZH1_norm; + coeffs[3] *= ZH1_norm; + /* Second-order */ + coeffs[4] *= ZH2_norm; + coeffs[5] *= ZH2_norm; + coeffs[6] *= ZH2_norm; + coeffs[7] *= ZH2_norm; + coeffs[8] *= ZH2_norm; + /* Third-order */ + coeffs[9] *= ZH3_norm; + coeffs[10] *= ZH3_norm; + coeffs[11] *= ZH3_norm; + coeffs[12] *= ZH3_norm; + coeffs[13] *= ZH3_norm; + coeffs[14] *= ZH3_norm; + coeffs[15] *= ZH3_norm; + } } -void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]) +void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { ALfloat dir[3] = { sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation) }; - CalcDirectionCoeffs(dir, coeffs); + CalcDirectionCoeffs(dir, spread, coeffs); } @@ -714,7 +761,7 @@ static void InitHrtfPanning(ALCdevice *device) for(i = 0;i < device->Dry.NumChannels;i++) { int chan = GetChannelIndex(CubeChannels, CubeInfo[i].Channel); - GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f, + GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 0.0f, device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); } } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c6b5aba0..76a8a921 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -300,9 +300,10 @@ void aluInitEffectPanning(struct ALeffectslot *slot); * CalcDirectionCoeffs * * Calculates ambisonic coefficients based on a direction vector. The vector - * must be normalized (unit length). + * must be normalized (unit length), and the spread is the angular width of the + * sound (0...tau). */ -void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]); +void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); /** * CalcXYZCoeffs @@ -310,10 +311,10 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat coeffs[MAX_AMBI_COEFFS]); * Same as CalcDirectionCoeffs except the direction is specified as separate x, * y, and z parameters instead of an array. */ -inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]) +inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { ALfloat dir[3] = { x, y, z }; - CalcDirectionCoeffs(dir, coeffs); + CalcDirectionCoeffs(dir, spread, coeffs); } /** @@ -323,7 +324,7 @@ inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AM * azimuth and elevation parameters are in radians, going right and up * respectively. */ -void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS]); +void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); /** * ComputeAmbientGains -- cgit v1.2.3 From 574ec13e5b884c83ffb3502f71d9c832e2869acd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Apr 2016 23:35:11 -0700 Subject: Avoid an unnecessary aluVector --- Alc/ALu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e137a904..adc72416 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1088,7 +1088,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. */ - aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }}; + ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -1099,16 +1099,16 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte if(Distance > FLT_EPSILON) { - dir.v[0] = -SourceToListener.v[0]; - dir.v[1] = -SourceToListener.v[1]; - dir.v[2] = -SourceToListener.v[2] * ZScale; + dir[0] = -SourceToListener.v[0]; + dir[1] = -SourceToListener.v[1]; + dir[2] = -SourceToListener.v[2] * ZScale; /* Calculate elevation and azimuth only when the source is not at * the listener. This prevents +0 and -0 Z from producing * inconsistent panning. Also, clamp Y in case FP precision errors * cause it to land outside of -1..+1. */ - ev = asinf(clampf(dir.v[1], -1.0f, 1.0f)); - az = atan2f(dir.v[0], -dir.v[2]); + ev = asinf(clampf(dir[1], -1.0f, 1.0f)); + az = atan2f(dir[0], -dir[2]); } if(radius > Distance) spread = F_TAU - Distance/radius*F_PI; @@ -1120,7 +1120,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte voice->Direct.Hrtf[0].Target.Coeffs, voice->Direct.Hrtf[0].Target.Delay); - CalcDirectionCoeffs(dir.v, spread, coeffs); + CalcDirectionCoeffs(dir, spread, coeffs); for(i = 0;i < NumSends;i++) { -- cgit v1.2.3 From 7555c86e7dc433e9b6b9880ece6f98c89951ce8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Apr 2016 23:58:11 -0700 Subject: Drop support for AL_SOFT_buffer_samples and AL_SOFT_buffer_sub_data Unfortunately they conflict with AL_EXT_SOURCE_RADIUS, as AL_SOURCE_RADIUS and AL_BYTE_RW_OFFSETS_SOFT share the same source property value. A replacement for AL_SOFT_buffer_samples will eventually be made. --- Alc/ALc.c | 15 +++------------ OpenAL32/alSource.c | 49 ------------------------------------------------- 2 files changed, 3 insertions(+), 61 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 77522ec4..12fc782f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -272,13 +272,6 @@ static const ALCfunction alcFunctions[] = { DECL(alGetAuxiliaryEffectSlotf), DECL(alGetAuxiliaryEffectSlotfv), - DECL(alBufferSubDataSOFT), - - DECL(alBufferSamplesSOFT), - DECL(alBufferSubSamplesSOFT), - DECL(alGetBufferSamplesSOFT), - DECL(alIsBufferFormatSupportedSOFT), - DECL(alDeferUpdatesSOFT), DECL(alProcessUpdatesSOFT), @@ -391,9 +384,7 @@ static const ALCenums enumeration[] = { DECL(AL_MAX_DISTANCE), DECL(AL_SEC_OFFSET), DECL(AL_SAMPLE_OFFSET), - DECL(AL_SAMPLE_RW_OFFSETS_SOFT), DECL(AL_BYTE_OFFSET), - DECL(AL_BYTE_RW_OFFSETS_SOFT), DECL(AL_SOURCE_TYPE), DECL(AL_STATIC), DECL(AL_STREAMING), @@ -713,9 +704,9 @@ static const ALchar alExtList[] = "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS " "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " "AL_EXT_source_distance_model AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic " - "AL_SOFT_block_alignment AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data " - "AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points " - "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length"; + "AL_SOFT_block_alignment AL_SOFT_deferred_updates AL_SOFT_direct_channels " + "AL_SOFT_loop_points AL_SOFT_MSADPCM AL_SOFT_source_latency " + "AL_SOFT_source_length"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 03eae080..43b935fa 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -97,10 +97,6 @@ typedef enum SourceProp { srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT, srcSecLengthSOFT = AL_SEC_LENGTH_SOFT, - /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */ - srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, - srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, - /* AL_SOFT_source_latency */ srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, @@ -159,8 +155,6 @@ static ALint FloatValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: return 1; - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: case AL_STEREO_ANGLES: return 2; @@ -223,8 +217,6 @@ static ALint DoubleValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: return 1; - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: case AL_STEREO_ANGLES: return 2; @@ -288,10 +280,6 @@ static ALint IntValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: return 1; - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - return 2; - case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: @@ -351,8 +339,6 @@ static ALint Int64ValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: return 1; - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: case AL_SAMPLE_OFFSET_LATENCY_SOFT: return 2; @@ -385,8 +371,6 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p switch(prop) { - case AL_BYTE_RW_OFFSETS_SOFT: - case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: @@ -615,8 +599,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SOURCE_TYPE: case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: @@ -870,8 +852,6 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: case AL_SOURCE_STATE: - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: @@ -969,7 +949,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; ALdouble offsets[2]; - ALdouble updateLen; ALint ivals[3]; ALboolean err; @@ -1061,14 +1040,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p ReadUnlock(&Source->queue_lock); return AL_TRUE; - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - LockContext(Context); - updateLen = (ALdouble)device->UpdateSize / device->Frequency; - GetSourceOffsets(Source, prop, values, updateLen); - UnlockContext(Context); - return AL_TRUE; - case AL_SEC_OFFSET_LATENCY_SOFT: LockContext(Context); values[0] = GetSourceSecOffset(Source); @@ -1316,16 +1287,6 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values = (ALint)dvals[0]; return err; - /* 2x float/double */ - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - } - return err; - /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: @@ -1406,16 +1367,6 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp *values = (ALint64)dvals[0]; return err; - /* 2x float/double */ - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - } - return err; - /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: -- cgit v1.2.3 From 0ed6791a58e674d43536cb0c0d10725d884d98ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Apr 2016 00:30:47 -0700 Subject: Add support for AL_EXT_SOURCE_RADIUS --- Alc/ALc.c | 10 ++++++---- OpenAL32/alSource.c | 33 +++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 12fc782f..d9cf4e69 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -512,6 +512,8 @@ static const ALCenums enumeration[] = { DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), + DECL(AL_SOURCE_RADIUS), + DECL(AL_STEREO_ANGLES), DECL(AL_UNUSED), @@ -703,10 +705,10 @@ static const ALchar alExtList[] = "AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE " "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS " "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " - "AL_EXT_source_distance_model AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic " - "AL_SOFT_block_alignment AL_SOFT_deferred_updates AL_SOFT_direct_channels " - "AL_SOFT_loop_points AL_SOFT_MSADPCM AL_SOFT_source_latency " - "AL_SOFT_source_length"; + "AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES " + "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " + "AL_SOFT_direct_channels AL_SOFT_loop_points AL_SOFT_MSADPCM " + "AL_SOFT_source_latency AL_SOFT_source_length"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 43b935fa..9cc95f89 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -104,6 +104,9 @@ typedef enum SourceProp { /* AL_EXT_STEREO_ANGLES */ srcAngles = AL_STEREO_ANGLES, + /* AL_EXT_SOURCE_RADIUS */ + srcRadius = AL_SOURCE_RADIUS, + /* AL_EXT_BFORMAT */ srcOrientation = AL_ORIENTATION, } SourceProp; @@ -153,6 +156,7 @@ static ALint FloatValsByProp(ALenum prop) case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: return 1; case AL_STEREO_ANGLES: @@ -215,6 +219,7 @@ static ALint DoubleValsByProp(ALenum prop) case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: return 1; case AL_SEC_OFFSET_LATENCY_SOFT: @@ -278,6 +283,7 @@ static ALint IntValsByProp(ALenum prop) case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: return 1; case AL_POSITION: @@ -337,6 +343,7 @@ static ALint Int64ValsByProp(ALenum prop) case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: return 1; case AL_SAMPLE_OFFSET_LATENCY_SOFT: @@ -500,6 +507,12 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p UnlockContext(Context); return AL_TRUE; + case AL_SOURCE_RADIUS: + CHECKVAL(*values >= 0.0f && isfinite(*values)); + + Source->Radius = *values; + ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + return AL_TRUE; case AL_STEREO_ANGLES: CHECKVAL(isfinite(values[0]) && isfinite(values[1])); @@ -809,6 +822,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_CONE_OUTER_GAINHF: case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: fvals[0] = (ALfloat)*values; return SetSourcefv(Source, Context, (int)prop, fvals); @@ -910,6 +924,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_CONE_OUTER_GAINHF: case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: + case AL_SOURCE_RADIUS: fvals[0] = (ALfloat)*values; return SetSourcefv(Source, Context, (int)prop, fvals); @@ -1040,12 +1055,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p ReadUnlock(&Source->queue_lock); return AL_TRUE; - case AL_SEC_OFFSET_LATENCY_SOFT: - LockContext(Context); - values[0] = GetSourceSecOffset(Source); - values[1] = (ALdouble)(V0(device->Backend,getLatency)()) / - 1000000000.0; - UnlockContext(Context); + case AL_SOURCE_RADIUS: + *values = Source->Radius; return AL_TRUE; case AL_STEREO_ANGLES: @@ -1055,6 +1066,14 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p UnlockContext(Context); return AL_TRUE; + case AL_SEC_OFFSET_LATENCY_SOFT: + LockContext(Context); + values[0] = GetSourceSecOffset(Source); + values[1] = (ALdouble)(V0(device->Backend,getLatency)()) / + 1000000000.0; + UnlockContext(Context); + return AL_TRUE; + case AL_POSITION: LockContext(Context); values[0] = Source->Position.v[0]; @@ -1283,6 +1302,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint)dvals[0]; return err; @@ -1363,6 +1383,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: case AL_SEC_LENGTH_SOFT: + case AL_SOURCE_RADIUS: if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint64)dvals[0]; return err; -- cgit v1.2.3 From b9eacf46414ad5916a5c2c9a342d4d05d8628de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Apr 2016 02:22:54 -0700 Subject: Remove unnecessary code for the now-unused write offset --- OpenAL32/alSource.c | 70 +++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 9cc95f89..b4da90cd 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -46,7 +46,7 @@ extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static ALvoid InitSourceParams(ALsource *Source); static ALint64 GetSourceSampleOffset(ALsource *Source); static ALdouble GetSourceSecOffset(ALsource *Source); -static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen); +static ALdouble GetSourceOffset(ALsource *Source, ALenum name); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); typedef enum SourceProp { @@ -963,7 +963,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; - ALdouble offsets[2]; ALint ivals[3]; ALboolean err; @@ -1013,9 +1012,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: LockContext(Context); - GetSourceOffsets(Source, prop, offsets, 0.0); + *values = GetSourceOffset(Source, prop); UnlockContext(Context); - *values = offsets[0]; return AL_TRUE; case AL_CONE_OUTER_GAINHF: @@ -2781,33 +2779,29 @@ static ALdouble GetSourceSecOffset(ALsource *Source) return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency; } -/* GetSourceOffsets +/* GetSourceOffset * - * Gets the current read and write offsets for the given Source, in the - * appropriate format (Bytes, Samples or Seconds). The offsets are relative to - * the start of the queue (not the start of the current buffer). + * Gets the current read offset for the given Source, in the appropriate format + * (Bytes, Samples or Seconds). The offset is relative to the start of the + * queue (not the start of the current buffer). */ -static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen) +static ALdouble GetSourceOffset(ALsource *Source, ALenum name) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; ALboolean readFin = AL_FALSE; - ALuint readPos, readPosFrac, writePos; + ALuint readPos, readPosFrac; ALuint totalBufferLen; + ALdouble offset = 0.0; ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) { - offset[0] = 0.0; - offset[1] = 0.0; ReadUnlock(&Source->queue_lock); - return; + return 0.0; } - if(updateLen > 0.0 && updateLen < 0.015) - updateLen = 0.015; - /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ totalBufferLen = 0; @@ -2829,40 +2823,26 @@ static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, } assert(Buffer != NULL); - if(Source->state == AL_PLAYING) - writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f); - else - writePos = readPos; - if(Source->Looping) - { readPos %= totalBufferLen; - writePos %= totalBufferLen; - } else { - /* Wrap positions back to 0 */ + /* Wrap back to 0 */ if(readPos >= totalBufferLen) readPos = readPosFrac = 0; - if(writePos >= totalBufferLen) - writePos = 0; } switch(name) { case AL_SEC_OFFSET: - offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency; - offset[1] = (ALdouble)writePos/Buffer->Frequency; + offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency; break; case AL_SAMPLE_OFFSET: - case AL_SAMPLE_RW_OFFSETS_SOFT: - offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE; - offset[1] = (ALdouble)writePos; + offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; break; case AL_BYTE_OFFSET: - case AL_BYTE_RW_OFFSETS_SOFT: if(Buffer->OriginalType == UserFmtIMA4) { ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; @@ -2870,15 +2850,7 @@ static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALuint FrameBlockSize = Buffer->OriginalAlign; /* Round down to nearest ADPCM block */ - offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize); - if(Source->state != AL_PLAYING) - offset[1] = offset[0]; - else - { - /* Round up to nearest ADPCM block */ - offset[1] = (ALdouble)((writePos+FrameBlockSize-1) / - FrameBlockSize * BlockSize); - } + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); } else if(Buffer->OriginalType == UserFmtMSADPCM) { @@ -2887,26 +2859,18 @@ static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALuint FrameBlockSize = Buffer->OriginalAlign; /* Round down to nearest ADPCM block */ - offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize); - if(Source->state != AL_PLAYING) - offset[1] = offset[0]; - else - { - /* Round up to nearest ADPCM block */ - offset[1] = (ALdouble)((writePos+FrameBlockSize-1) / - FrameBlockSize * BlockSize); - } + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); } else { ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); - offset[0] = (ALdouble)(readPos * FrameSize); - offset[1] = (ALdouble)(writePos * FrameSize); + offset = (ALdouble)(readPos * FrameSize); } break; } ReadUnlock(&Source->queue_lock); + return offset; } -- cgit v1.2.3 From 3556da0d022dca2a65ed7d1fe736855fac728c95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Apr 2016 18:56:59 -0700 Subject: Start AL_SOFT_buffer_samples2 as a replacement for AL_SOFT_buffer_samples --- Alc/ALc.c | 30 ++++++++++++++----- OpenAL32/Include/alBuffer.h | 22 +++++++------- OpenAL32/Include/alMain.h | 73 +++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/alBuffer.c | 15 ++++++---- 4 files changed, 115 insertions(+), 25 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d9cf4e69..ae678b19 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -288,6 +288,10 @@ static const ALCfunction alcFunctions[] = { DECL(alGetSource3i64SOFT), DECL(alGetSourcei64vSOFT), + DECL(alBufferSamplesSOFT), + DECL(alGetBufferSamplesSOFT), + DECL(alIsBufferFormatSupportedSOFT), + { NULL, NULL } }; #undef DECL @@ -452,6 +456,15 @@ static const ALCenums enumeration[] = { DECL(AL_FORMAT_MONO_ALAW_EXT), DECL(AL_FORMAT_STEREO_ALAW_EXT), + DECL(AL_FORMAT_BFORMAT2D_8), + DECL(AL_FORMAT_BFORMAT2D_16), + DECL(AL_FORMAT_BFORMAT2D_FLOAT32), + DECL(AL_FORMAT_BFORMAT2D_MULAW), + DECL(AL_FORMAT_BFORMAT3D_8), + DECL(AL_FORMAT_BFORMAT3D_16), + DECL(AL_FORMAT_BFORMAT3D_FLOAT32), + DECL(AL_FORMAT_BFORMAT3D_MULAW), + DECL(AL_MONO8_SOFT), DECL(AL_MONO16_SOFT), DECL(AL_MONO32F_SOFT), @@ -473,14 +486,12 @@ static const ALCenums enumeration[] = { DECL(AL_7POINT1_8_SOFT), DECL(AL_7POINT1_16_SOFT), DECL(AL_7POINT1_32F_SOFT), - DECL(AL_FORMAT_BFORMAT2D_8), - DECL(AL_FORMAT_BFORMAT2D_16), - DECL(AL_FORMAT_BFORMAT2D_FLOAT32), - DECL(AL_FORMAT_BFORMAT2D_MULAW), - DECL(AL_FORMAT_BFORMAT3D_8), - DECL(AL_FORMAT_BFORMAT3D_16), - DECL(AL_FORMAT_BFORMAT3D_FLOAT32), - DECL(AL_FORMAT_BFORMAT3D_MULAW), + DECL(AL_BFORMAT2D_8_SOFT), + DECL(AL_BFORMAT2D_16_SOFT), + DECL(AL_BFORMAT2D_32F_SOFT), + DECL(AL_BFORMAT3D_8_SOFT), + DECL(AL_BFORMAT3D_16_SOFT), + DECL(AL_BFORMAT3D_32F_SOFT), DECL(AL_MONO_SOFT), DECL(AL_STEREO_SOFT), @@ -489,6 +500,8 @@ static const ALCenums enumeration[] = { DECL(AL_5POINT1_SOFT), DECL(AL_6POINT1_SOFT), DECL(AL_7POINT1_SOFT), + DECL(AL_BFORMAT2D_SOFT), + DECL(AL_BFORMAT3D_SOFT), DECL(AL_BYTE_SOFT), DECL(AL_UNSIGNED_BYTE_SOFT), @@ -500,6 +513,7 @@ static const ALCenums enumeration[] = { DECL(AL_DOUBLE_SOFT), DECL(AL_BYTE3_SOFT), DECL(AL_UNSIGNED_BYTE3_SOFT), + DECL(AL_MULAW_SOFT), DECL(AL_FREQUENCY), DECL(AL_BITS), diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index dd046da8..71fe7e30 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -19,21 +19,21 @@ enum UserFmtType { UserFmtDouble = AL_DOUBLE_SOFT, UserFmtByte3 = AL_BYTE3_SOFT, UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT, - UserFmtMulaw, - UserFmtAlaw, + UserFmtMulaw = AL_MULAW_SOFT, + UserFmtAlaw = 0x10000000, UserFmtIMA4, UserFmtMSADPCM, }; enum UserFmtChannels { - UserFmtMono = AL_MONO_SOFT, - UserFmtStereo = AL_STEREO_SOFT, - UserFmtRear = AL_REAR_SOFT, - UserFmtQuad = AL_QUAD_SOFT, - UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ - UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ - UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ - UserFmtBFormat2D = 0x10000000, /* WXY */ - UserFmtBFormat3D, /* WXYZ */ + UserFmtMono = AL_MONO_SOFT, + UserFmtStereo = AL_STEREO_SOFT, + UserFmtRear = AL_REAR_SOFT, + UserFmtQuad = AL_QUAD_SOFT, + UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ + UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ + UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ + UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */ + UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */ }; ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fba9c012..e3f272df 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -51,6 +51,79 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, #endif #endif +#ifndef AL_SOFT_buffer_samples2 +#define AL_SOFT_buffer_samples2 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 +#define AL_BFORMAT2D_SOFT 0x1507 +#define AL_BFORMAT3D_SOFT 0x1508 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 +#define AL_MULAW_SOFT 0x140A + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 +#define AL_BFORMAT2D_8_SOFT 0x20021 +#define AL_BFORMAT2D_16_SOFT 0x20022 +#define AL_BFORMAT2D_32F_SOFT 0x20023 +#define AL_BFORMAT3D_8_SOFT 0x20031 +#define AL_BFORMAT3D_16_SOFT 0x20032 +#define AL_BFORMAT3D_32F_SOFT 0x20033 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +#if 0 +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif +#endif + typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 904fd61d..c5c9ea21 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1201,13 +1201,13 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm { AL_7POINT1_16_SOFT, FmtX71, FmtShort }, { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat }, - { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte }, - { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, + { AL_BFORMAT2D_8_SOFT, FmtBFormat2D, FmtByte }, + { AL_BFORMAT2D_16_SOFT, FmtBFormat2D, FmtShort }, + { AL_BFORMAT2D_32F_SOFT, FmtBFormat2D, FmtFloat }, - { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte }, - { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, + { AL_BFORMAT3D_8_SOFT, FmtBFormat3D, FmtByte }, + { AL_BFORMAT3D_16_SOFT, FmtBFormat3D, FmtShort }, + { AL_BFORMAT3D_32F_SOFT, FmtBFormat3D, FmtFloat }, }; ALuint i; @@ -1277,6 +1277,7 @@ static ALboolean IsValidType(ALenum type) case AL_DOUBLE_SOFT: case AL_BYTE3_SOFT: case AL_UNSIGNED_BYTE3_SOFT: + case AL_MULAW_SOFT: return AL_TRUE; } return AL_FALSE; @@ -1293,6 +1294,8 @@ static ALboolean IsValidChannels(ALenum channels) case AL_5POINT1_SOFT: case AL_6POINT1_SOFT: case AL_7POINT1_SOFT: + case AL_BFORMAT2D_SOFT: + case AL_BFORMAT3D_SOFT: return AL_TRUE; } return AL_FALSE; -- cgit v1.2.3 From d1e98c36d375433cb11a7a74ce20c968491773aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Apr 2016 17:14:55 -0700 Subject: Don't crash when there's no backend to probe --- Alc/ALc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ae678b19..ff7e6429 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1127,6 +1127,11 @@ static void alc_initconfig(void) V0(factory,init)(); } + if(!PlaybackBackend.name) + WARN("No playback backend available!\n"); + if(!CaptureBackend.name) + WARN("No capture backend available!\n"); + if(ConfigValueStr(NULL, NULL, "excludefx", &str)) { size_t len; @@ -1240,9 +1245,9 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum LockLists(); al_string_clear(list); - if(!backendinfo->getFactory) + if(backendinfo->Probe) backendinfo->Probe(type); - else + else if(backendinfo->getFactory) { ALCbackendFactory *factory = backendinfo->getFactory(); V(factory,probe)(type); -- cgit v1.2.3 From b0224485aaecd0f98f61c0c77663ecba14302687 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 3 May 2016 05:38:36 -0400 Subject: Fix placement of alignas - fixes Mac OS X build --- Alc/mixer_sse2.c | 4 ++-- Alc/mixer_sse3.c | 8 ++++---- Alc/mixer_sse41.c | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index 32f29227..004dba9e 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -33,8 +33,8 @@ const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALflo const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i; diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 7085c537..1b946461 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -36,8 +36,8 @@ const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfl { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i; @@ -100,8 +100,8 @@ const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfl { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i, j; diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index e832e5df..ed49447d 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -34,8 +34,8 @@ const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfl const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i; @@ -89,8 +89,8 @@ const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALf { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i; @@ -156,8 +156,8 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALf { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) union { ALuint i[4]; float f[4]; } pos_; - alignas(16) union { ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALuint pos; ALuint i, j; -- cgit v1.2.3 From c2611f10ab5bdffe1aa0be4d4ec61662d868fde5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 9 May 2016 11:26:49 -0700 Subject: Store more "active" listener and context properties separately This helps ensure async listener/context property changes affect all playing sources at the same time. --- Alc/ALc.c | 5 +++++ Alc/ALu.c | 31 ++++++++++++++++++++----------- OpenAL32/Include/alListener.h | 6 ++++++ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ff7e6429..d083825b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2272,6 +2272,7 @@ static ALvoid InitContext(ALCcontext *Context) listener->Up[0] = 0.0f; listener->Up[1] = 1.0f; listener->Up[2] = 0.0f; + aluMatrixdSet(&listener->Params.Matrix, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, @@ -2279,6 +2280,10 @@ static ALvoid InitContext(ALCcontext *Context) 0.0, 0.0, 0.0, 1.0 ); aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener->Params.Gain = 1.0f; + listener->Params.MetersPerUnit = 1.0f; + listener->Params.DopplerFactor = 1.0f; + listener->Params.SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; //Validate Context ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); diff --git a/Alc/ALu.c b/Alc/ALu.c index adc72416..4786c785 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -266,8 +266,9 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) } -static ALvoid CalcListenerParams(ALlistener *Listener) +static ALvoid CalcListenerParams(ALCcontext *Context) { + ALlistener *Listener = Context->Listener; ALdouble N[3], V[3], U[3], P[3]; /* AT then UP */ @@ -297,6 +298,12 @@ static ALvoid CalcListenerParams(ALlistener *Listener) aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity); + + Listener->Params.Gain = Listener->Gain; + Listener->Params.MetersPerUnit = Listener->MetersPerUnit; + + Listener->Params.DopplerFactor = Context->DopplerFactor; + Listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; } ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) @@ -338,6 +345,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A }; const ALCdevice *Device = ALContext->Device; + const ALlistener *Listener = ALContext->Listener; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum FmtChannels Channels; @@ -364,7 +372,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A Frequency = Device->Frequency; /* Get listener properties */ - ListenerGain = ALContext->Listener->Gain; + ListenerGain = Listener->Params.Gain; /* Get source properties */ SourceVolume = ALSource->Gain; @@ -499,7 +507,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A aluNormalize(V); if(!Relative) { - const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix; + const aluMatrixd *lmatrix = &Listener->Params.Matrix; aluMatrixdFloat3(N, 0.0f, lmatrix); aluMatrixdFloat3(V, 0.0f, lmatrix); } @@ -756,6 +764,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; + const ALlistener *Listener = ALContext->Listener; aluVector Position, Velocity, Direction, SourceToListener; ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; @@ -794,14 +803,14 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } /* Get context/device properties */ - DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor; - SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity; + DopplerFactor = Listener->Params.DopplerFactor * ALSource->DopplerFactor; + SpeedOfSound = Listener->Params.SpeedOfSound; NumSends = Device->NumAuxSends; Frequency = Device->Frequency; /* Get listener properties */ - ListenerGain = ALContext->Listener->Gain; - MetersPerUnit = ALContext->Listener->MetersPerUnit; + ListenerGain = Listener->Params.Gain; + MetersPerUnit = Listener->Params.MetersPerUnit; /* Get source properties */ SourceVolume = ALSource->Gain; @@ -877,7 +886,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte /* Transform source to listener space (convert to head relative) */ if(ALSource->HeadRelative == AL_FALSE) { - const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix; + const aluMatrixd *Matrix = &Listener->Params.Matrix; /* Transform source vectors */ Position = aluMatrixdVector(Matrix, &Position); Velocity = aluMatrixdVector(Matrix, &Velocity); @@ -885,7 +894,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } else { - const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; + const aluVector *lvelocity = &Listener->Params.Velocity; /* Offset the source velocity to be relative of the listener velocity */ Velocity.v[0] += lvelocity->v[0]; Velocity.v[1] += lvelocity->v[1]; @@ -1047,7 +1056,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte /* Calculate velocity-based doppler effect */ if(DopplerFactor > 0.0f) { - const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; + const aluVector *lvelocity = &Listener->Params.Velocity; ALfloat VSS, VLS; if(SpeedOfSound < 1.0f) @@ -1242,7 +1251,7 @@ void UpdateContextSources(ALCcontext *ctx) if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE)) { - CalcListenerParams(ctx->Listener); + CalcListenerParams(ctx); voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index c9bd9be0..f28561fa 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -19,6 +19,12 @@ typedef struct ALlistener { struct { aluMatrixd Matrix; aluVector Velocity; + + ALfloat Gain; + ALfloat MetersPerUnit; + + ALfloat DopplerFactor; + ALfloat SpeedOfSound; } Params; } ALlistener; -- cgit v1.2.3 From 182c0cb61abaff36554653d6a94c8a66fc263411 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 9 May 2016 14:22:26 -0700 Subject: Find a valid source buffer before updating the voice --- Alc/ALc.c | 17 +++++++-- Alc/ALu.c | 92 ++++++++++++++++++++++----------------------- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 5 ++- 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d083825b..f8eda9a5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2106,11 +2106,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALvoice *voice = &context->Voices[pos]; ALsource *source = voice->Source; + ALbufferlistitem *BufferListItem; - if(source) + if(!source) + continue; + + BufferListItem = ATOMIC_LOAD(&source->queue); + while(BufferListItem != NULL) { - ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); - voice->Update(voice, source, context); + ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + voice->Update(voice, source, buffer, context); + break; + } + BufferListItem = BufferListItem->next; } } diff --git a/Alc/ALu.c b/Alc/ALu.c index 4786c785..709b7127 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -306,7 +306,7 @@ static ALvoid CalcListenerParams(ALCcontext *Context) Listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; } -ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) +ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } @@ -347,8 +347,6 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; - ALbufferlistitem *BufferListItem; - enum FmtChannels Channels; ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; @@ -407,25 +405,12 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } /* Calculate the stepping value */ - Channels = FmtMono; - BufferListItem = ATOMIC_LOAD(&ALSource->queue); - while(BufferListItem != NULL) - { - ALbuffer *ALBuffer; - if((ALBuffer=BufferListItem->buffer) != NULL) - { - Pitch = Pitch * ALBuffer->Frequency / Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); - BsincPrepare(voice->Step, &voice->SincState); - - Channels = ALBuffer->FmtChannels; - break; - } - BufferListItem = BufferListItem->next; - } + Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; + if(Pitch > (ALfloat)MAX_PITCH) + voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + BsincPrepare(voice->Step, &voice->SincState); /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); @@ -440,7 +425,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A WetGainLF[i] = ALSource->Send[i].GainLF; } - switch(Channels) + switch(ALBuffer->FmtChannels) { case FmtMono: chans = MonoMap; @@ -761,7 +746,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } } -ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) +ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; @@ -772,7 +757,6 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte ALfloat DopplerFactor, SpeedOfSound; ALfloat AirAbsorptionFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; - ALbufferlistitem *BufferListItem; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat Attenuation; ALfloat RoomAttenuation[MAX_SENDS]; @@ -1072,25 +1056,15 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); } - BufferListItem = ATOMIC_LOAD(&ALSource->queue); - while(BufferListItem != NULL) - { - ALbuffer *ALBuffer; - if((ALBuffer=BufferListItem->buffer) != NULL) - { - /* Calculate fixed-point stepping value, based on the pitch, buffer - * frequency, and output frequency. */ - Pitch = Pitch * ALBuffer->Frequency / Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); - BsincPrepare(voice->Step, &voice->SincState); - - break; - } - BufferListItem = BufferListItem->next; - } + /* Calculate fixed-point stepping value, based on the pitch, buffer + * frequency, and output frequency. + */ + Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; + if(Pitch > (ALfloat)MAX_PITCH) + voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + BsincPrepare(voice->Step, &voice->SincState); if(Device->Render_Mode == HrtfRender) { @@ -1262,8 +1236,19 @@ void UpdateContextSources(ALCcontext *ctx) voice->Source = NULL; else { - ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); - voice->Update(voice, source, ctx); + ALbufferlistitem *BufferListItem; + BufferListItem = ATOMIC_LOAD(&source->queue); + while(BufferListItem != NULL) + { + ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + voice->Update(voice, source, buffer, ctx); + break; + } + BufferListItem = BufferListItem->next; + } } } } @@ -1277,7 +1262,20 @@ void UpdateContextSources(ALCcontext *ctx) if(source->state != AL_PLAYING && source->state != AL_PAUSED) voice->Source = NULL; else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE)) - voice->Update(voice, source, ctx); + { + ALbufferlistitem *BufferListItem; + BufferListItem = ATOMIC_LOAD(&source->queue); + while(BufferListItem != NULL) + { + ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + voice->Update(voice, source, buffer, ctx); + break; + } + BufferListItem = BufferListItem->next; + } + } } } } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index b7c08fcd..6c821703 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -25,7 +25,7 @@ typedef struct ALvoice { struct ALsource *volatile Source; /** Method to update mixing parameters. */ - ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context); + ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const struct ALbuffer *ALBuffer, const ALCcontext *context); /** Current target parameters used for mixing. */ ALint Step; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 76a8a921..c20c6404 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -36,6 +36,7 @@ extern "C" { struct ALsource; struct ALvoice; struct ALeffectslot; +struct ALbuffer; /* The number of distinct scale and phase intervals within the filter table. */ @@ -374,8 +375,8 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, c ALvoid UpdateContextSources(ALCcontext *context); -ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext); -ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext); +ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext); +ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext); ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo); -- cgit v1.2.3 From 7dac02148bca67ceae56e880f5f2a490faff1a38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 9 May 2016 16:34:54 -0700 Subject: Use the source's offset type to determine if there's an offset --- Alc/ALc.c | 2 +- OpenAL32/alSource.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f8eda9a5..b8dae07c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1604,7 +1604,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) ALenum new_state; if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - Source->Offset >= 0.0) + Source->OffsetType != AL_NONE) { WriteLock(&Source->queue_lock); ApplyOffset(Source); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b4da90cd..749f2ec4 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2544,7 +2544,8 @@ static ALvoid InitSourceParams(ALsource *Source) Source->state = AL_INITIAL; Source->new_state = AL_NONE; Source->SourceType = AL_UNDETERMINED; - Source->Offset = -1.0; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; ATOMIC_INIT(&Source->queue, NULL); ATOMIC_INIT(&Source->current_buffer, NULL); @@ -2608,7 +2609,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } // Check if an Offset has been set - if(Source->Offset >= 0.0) + if(Source->OffsetType != AL_NONE) { ApplyOffset(Source); /* discontinuity = AL_TRUE;??? */ @@ -2680,7 +2681,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->state = AL_STOPPED; ATOMIC_STORE(&Source->current_buffer, NULL); } - Source->Offset = -1.0; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; } else if(state == AL_INITIAL) { @@ -2691,7 +2693,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->position_fraction = 0; ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue)); } - Source->Offset = -1.0; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; } WriteUnlock(&Source->queue_lock); } @@ -2942,7 +2945,8 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) } if(!Buffer) { - Source->Offset = -1.0; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; return AL_FALSE; } @@ -2980,7 +2984,8 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; } - Source->Offset = -1.0; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; return AL_TRUE; } -- cgit v1.2.3 From c026f44a092a566a18fef78d2517fead84ed2db8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 May 2016 17:07:44 -0700 Subject: Add a comment about CoeffCount being 0 --- OpenAL32/Include/alMain.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e3f272df..e818245b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -594,7 +594,9 @@ struct ALCdevice_struct BFChannelConfig Map[MAX_OUTPUT_CHANNELS]; } Ambi; /* Number of coefficients in each ChannelConfig to mix together (4 for - * first-order, 9 for second-order, etc). + * first-order, 9 for second-order, etc). If the count is 0, the + * BFChannelConfig is used instead to map each output to a coefficient + * index. */ ALuint CoeffCount; -- cgit v1.2.3 From 906a4bb22d6811615ccff417b6086fa36f310c00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 May 2016 22:49:24 -0700 Subject: Hold the source map lock while handling it --- OpenAL32/Include/alSource.h | 13 +++++++-- OpenAL32/alSource.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ common/uintmap.c | 47 +++++++++++++++++++++++++++++++ include/uintmap.h | 2 ++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 6c821703..187d7e07 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -138,10 +138,19 @@ typedef struct ALsource { ALuint id; } ALsource; +inline void LockSourcesRead(ALCcontext *context) +{ LockUIntMapRead(&context->SourceMap); } +inline void UnlockSourcesRead(ALCcontext *context) +{ UnlockUIntMapRead(&context->SourceMap); } +inline void LockSourcesWrite(ALCcontext *context) +{ LockUIntMapWrite(&context->SourceMap); } +inline void UnlockSourcesWrite(ALCcontext *context) +{ UnlockUIntMapWrite(&context->SourceMap); } + inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)LookupUIntMapKey(&context->SourceMap, id); } +{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); } inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)RemoveUIntMapKey(&context->SourceMap, id); } +{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 749f2ec4..fc5d309b 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -40,6 +40,10 @@ #include "almalloc.h" +extern inline void LockSourcesRead(ALCcontext *context); +extern inline void UnlockSourcesRead(ALCcontext *context); +extern inline void LockSourcesWrite(ALCcontext *context); +extern inline void UnlockSourcesWrite(ALCcontext *context); extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); @@ -1509,6 +1513,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; + LockSourcesWrite(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -1560,6 +1565,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) } done: + UnlockSourcesWrite(context); ALCcontext_DecRef(context); } @@ -1572,7 +1578,9 @@ AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) context = GetContextRef(); if(!context) return AL_FALSE; + LockSourcesRead(context); ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); + UnlockSourcesRead(context); ALCcontext_DecRef(context); @@ -1588,12 +1596,14 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(FloatValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM); else SetSourcefv(Source, Context, param, &value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1606,6 +1616,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(FloatValsByProp(param) == 3)) @@ -1615,6 +1626,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 ALfloat fvals[3] = { value1, value2, value3 }; SetSourcefv(Source, Context, param, fvals); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1627,6 +1639,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1635,6 +1648,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat alSetError(Context, AL_INVALID_ENUM); else SetSourcefv(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1648,6 +1662,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(DoubleValsByProp(param) == 1)) @@ -1657,6 +1672,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va ALfloat fval = (ALfloat)value; SetSourcefv(Source, Context, param, &fval); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1669,6 +1685,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(DoubleValsByProp(param) == 3)) @@ -1678,6 +1695,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; SetSourcefv(Source, Context, param, fvals); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1691,6 +1709,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1706,6 +1725,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo fvals[i] = (ALfloat)values[i]; SetSourcefv(Source, Context, param, fvals); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1719,12 +1739,14 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(IntValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM); else SetSourceiv(Source, Context, param, &value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1737,6 +1759,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(IntValsByProp(param) == 3)) @@ -1746,6 +1769,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL ALint ivals[3] = { value1, value2, value3 }; SetSourceiv(Source, Context, param, ivals); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1758,6 +1782,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1766,6 +1791,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val alSetError(Context, AL_INVALID_ENUM); else SetSourceiv(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1779,12 +1805,14 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(Int64ValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM); else SetSourcei64v(Source, Context, param, &value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1797,6 +1825,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(Int64ValsByProp(param) == 3)) @@ -1806,6 +1835,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF ALint64SOFT i64vals[3] = { value1, value2, value3 }; SetSourcei64v(Source, Context, param, i64vals); } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1818,6 +1848,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1826,6 +1857,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin alSetError(Context, AL_INVALID_ENUM); else SetSourcei64v(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1839,6 +1871,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!value) @@ -1851,6 +1884,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val if(GetSourcedv(Source, Context, param, &dval)) *value = (ALfloat)dval; } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1864,6 +1898,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(value1 && value2 && value3)) @@ -1880,6 +1915,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va *value3 = (ALfloat)dvals[2]; } } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1894,6 +1930,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1910,6 +1947,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va values[i] = (ALfloat)dvals[i]; } } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1923,6 +1961,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!value) @@ -1931,6 +1970,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * alSetError(Context, AL_INVALID_ENUM); else GetSourcedv(Source, Context, param, value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1943,6 +1983,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(value1 && value2 && value3)) @@ -1959,6 +2000,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value3 = dvals[2]; } } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1971,6 +2013,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -1979,6 +2022,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble alSetError(Context, AL_INVALID_ENUM); else GetSourcedv(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -1992,6 +2036,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!value) @@ -2000,6 +2045,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value alSetError(Context, AL_INVALID_ENUM); else GetSourceiv(Source, Context, param, value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2013,6 +2059,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(value1 && value2 && value3)) @@ -2029,6 +2076,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 *value3 = ivals[2]; } } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2042,6 +2090,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -2050,6 +2099,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values alSetError(Context, AL_INVALID_ENUM); else GetSourceiv(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2063,6 +2113,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!value) @@ -2071,6 +2122,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S alSetError(Context, AL_INVALID_ENUM); else GetSourcei64v(Source, Context, param, value); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2083,6 +2135,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!(value1 && value2 && value3)) @@ -2099,6 +2152,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 *value3 = i64vals[2]; } } + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2111,6 +2165,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; + LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); else if(!values) @@ -2119,6 +2174,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 alSetError(Context, AL_INVALID_ENUM); else GetSourcei64v(Source, Context, param, values); + UnlockSourcesRead(Context); ALCcontext_DecRef(Context); } @@ -2137,6 +2193,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; + LockSourcesRead(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); for(i = 0;i < n;i++) @@ -2174,6 +2231,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) UnlockContext(context); done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } @@ -2190,6 +2248,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; + LockSourcesRead(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); for(i = 0;i < n;i++) @@ -2208,6 +2267,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) UnlockContext(context); done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } @@ -2224,6 +2284,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; + LockSourcesRead(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); for(i = 0;i < n;i++) @@ -2242,6 +2303,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) UnlockContext(context); done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } @@ -2258,6 +2320,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; + LockSourcesRead(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); for(i = 0;i < n;i++) @@ -2276,6 +2339,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) UnlockContext(context); done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } @@ -2298,6 +2362,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu device = context->Device; + LockSourcesRead(context); if(!(nb >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if((source=LookupSource(context, src)) == NULL) @@ -2413,6 +2478,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu WriteUnlock(&source->queue_lock); done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } @@ -2431,6 +2497,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint context = GetContextRef(); if(!context) return; + LockSourcesRead(context); if(!(nb >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -2494,6 +2561,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } done: + UnlockSourcesRead(context); ALCcontext_DecRef(context); } diff --git a/common/uintmap.c b/common/uintmap.c index b7a9a29c..d5e7c9ae 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -120,6 +120,33 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) return ptr; } +ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key) +{ + if(map->size > 0) + { + ALsizei low = 0; + ALsizei high = map->size - 1; + while(low < high) + { + ALsizei mid = low + (high-low)/2; + if(map->array[mid].key < key) + low = mid + 1; + else + high = mid; + } + if(map->array[low].key == key) + { + ALvoid *ptr = map->array[low].value; + if(low < map->size-1) + memmove(&map->array[low], &map->array[low+1], + (map->size-1-low)*sizeof(map->array[0])); + map->size--; + return ptr; + } + } + return NULL; +} + ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) { ALvoid *ptr = NULL; @@ -142,3 +169,23 @@ ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) ReadUnlock(&map->lock); return ptr; } + +ALvoid *LookupUIntMapKeyNoLock(UIntMap *map, ALuint key) +{ + if(map->size > 0) + { + ALsizei low = 0; + ALsizei high = map->size - 1; + while(low < high) + { + ALsizei mid = low + (high-low)/2; + if(map->array[mid].key < key) + low = mid + 1; + else + high = mid; + } + if(map->array[low].key == key) + return map->array[low].value; + } + return NULL; +} diff --git a/include/uintmap.h b/include/uintmap.h index 2c4c5e7a..c41c20ad 100644 --- a/include/uintmap.h +++ b/include/uintmap.h @@ -25,7 +25,9 @@ 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 *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key); ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); +ALvoid *LookupUIntMapKeyNoLock(UIntMap *map, ALuint key); inline void LockUIntMapRead(UIntMap *map) { ReadLock(&map->lock); } -- cgit v1.2.3 From 21bc0f5ef8f0e410ea840061589b844d6e401afc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 May 2016 23:42:44 -0700 Subject: Hold the buffer map lock while handling the buffer --- OpenAL32/Include/alBuffer.h | 13 +++++++++++-- OpenAL32/alBuffer.c | 43 ++++++++++++++++++++++++++++++++++++++++++- OpenAL32/alSource.c | 12 +++++++++++- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 71fe7e30..4807dd16 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -106,10 +106,19 @@ void DeleteBuffer(ALCdevice *device, ALbuffer *buffer); ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc); +inline void LockBuffersRead(ALCdevice *device) +{ LockUIntMapRead(&device->BufferMap); } +inline void UnlockBuffersRead(ALCdevice *device) +{ UnlockUIntMapRead(&device->BufferMap); } +inline void LockBuffersWrite(ALCdevice *device) +{ LockUIntMapWrite(&device->BufferMap); } +inline void UnlockBuffersWrite(ALCdevice *device) +{ UnlockUIntMapWrite(&device->BufferMap); } + inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ return (struct ALbuffer*)LookupUIntMapKey(&device->BufferMap, id); } +{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id) -{ return (struct ALbuffer*)RemoveUIntMapKey(&device->BufferMap, id); } +{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); } ALvoid ReleaseALBuffers(ALCdevice *device); diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index c5c9ea21..8e2c5cf2 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -36,6 +36,10 @@ #include "sample_cvt.h" +extern inline void LockBuffersRead(ALCdevice *device); +extern inline void UnlockBuffersRead(ALCdevice *device); +extern inline void LockBuffersWrite(ALCdevice *device); +extern inline void UnlockBuffersWrite(ALCdevice *device); 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); @@ -85,10 +89,12 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) context = GetContextRef(); if(!context) return; + device = context->Device; + + LockBuffersWrite(device); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - device = context->Device; for(i = 0;i < n;i++) { if(!buffers[i]) @@ -108,6 +114,7 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) } done: + UnlockBuffersWrite(device); ALCcontext_DecRef(context); } @@ -119,8 +126,10 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) context = GetContextRef(); if(!context) return AL_FALSE; + LockBuffersRead(context->Device); ret = ((!buffer || LookupBuffer(context->Device, buffer)) ? AL_TRUE : AL_FALSE); + UnlockBuffersRead(context->Device); ALCcontext_DecRef(context); @@ -144,6 +153,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(size >= 0 && freq > 0)) @@ -272,6 +282,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -291,6 +302,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(length >= 0 && offset >= 0)) @@ -351,6 +363,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons WriteUnlock(&albuf->lock); done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -369,6 +382,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(samples >= 0 && samplerate != 0)) @@ -388,6 +402,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, err, done); done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -404,6 +419,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(samples >= 0 && offset >= 0)) @@ -441,6 +457,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, WriteUnlock(&albuf->lock); done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -457,6 +474,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(samples >= 0 && offset >= 0)) @@ -494,6 +512,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ReadUnlock(&albuf->lock); done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -524,6 +543,7 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -534,6 +554,7 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -547,6 +568,7 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -557,6 +579,7 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -570,6 +593,7 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -582,6 +606,7 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -596,6 +621,7 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -618,6 +644,7 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -666,6 +693,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -697,6 +725,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -711,6 +740,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -732,6 +762,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -745,6 +776,7 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -757,6 +789,7 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -777,6 +810,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -789,6 +823,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -803,6 +838,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -854,6 +890,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -867,6 +904,7 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 if(!context) return; device = context->Device; + LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -879,6 +917,7 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -908,6 +947,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values if(!context) return; device = context->Device; + LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); @@ -927,6 +967,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values } done: + UnlockBuffersRead(device); ALCcontext_DecRef(context); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index fc5d309b..8cab5ab3 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -636,12 +636,18 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_BUFFER: - CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL); + LockBuffersRead(device); + if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) + { + UnlockBuffersRead(device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + } WriteLock(&Source->queue_lock); if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL)) { WriteUnlock(&Source->queue_lock); + UnlockBuffersRead(device); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); } @@ -670,6 +676,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist); ATOMIC_STORE(&Source->current_buffer, newlist); WriteUnlock(&Source->queue_lock); + UnlockBuffersRead(device); /* Delete all elements in the previous queue */ while(oldlist != NULL) @@ -2388,6 +2395,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = BufferList->next; } + LockBuffersRead(device); BufferListStart = NULL; BufferList = NULL; for(i = 0;i < nb;i++) @@ -2447,6 +2455,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu free(BufferListStart); BufferListStart = next; } + UnlockBuffersRead(device); goto done; } } @@ -2458,6 +2467,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(buffer) ReadUnlock(&buffer->lock); BufferList = BufferList->next; } + UnlockBuffersRead(device); /* Source is now streaming */ source->SourceType = AL_STREAMING; -- cgit v1.2.3 From 186b54aa3d5f1398a384fa318aa000210d82437e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 11 May 2016 18:40:17 -0700 Subject: Use a lockless method for updating listener and context properties This uses a separate container to provide the relevant properties to the internal update method, using atomic pointer swaps. A free-list is used to avoid having too many individual containers. This allows the mixer to update the internal listener properties without requiring the lock to protect against async updates. It also allows concurrent read access to the user-facing property values, even the multi-value ones (e.g. the vectors). --- Alc/ALc.c | 35 ++++++++-- Alc/ALu.c | 58 ++++++++++++----- OpenAL32/Include/alListener.h | 30 ++++++++- OpenAL32/Include/alMain.h | 7 +- OpenAL32/alAuxEffectSlot.c | 7 +- OpenAL32/alListener.c | 148 ++++++++++++++++++++++++++++++------------ OpenAL32/alState.c | 27 ++++++-- 7 files changed, 234 insertions(+), 78 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b8dae07c..058dd242 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2064,7 +2064,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALsizei pos; - ATOMIC_STORE(&context->UpdateSources, AL_FALSE); LockUIntMapRead(&context->EffectSlotMap); for(pos = 0;pos < context->EffectSlotMap.size;pos++) { @@ -2272,11 +2271,16 @@ static ALCboolean VerifyDevice(ALCdevice **device) static ALvoid InitContext(ALCcontext *Context) { ALlistener *listener = Context->Listener; + //Initialise listener listener->Gain = 1.0f; listener->MetersPerUnit = 1.0f; - aluVectorSet(&listener->Position, 0.0f, 0.0f, 0.0f, 1.0f); - aluVectorSet(&listener->Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener->Position[0] = 0.0f; + listener->Position[1] = 0.0f; + listener->Position[2] = 0.0f; + listener->Velocity[0] = 0.0f; + listener->Velocity[1] = 0.0f; + listener->Velocity[2] = 0.0f; listener->Forward[0] = 0.0f; listener->Forward[1] = 0.0f; listener->Forward[2] = -1.0f; @@ -2296,9 +2300,12 @@ static ALvoid InitContext(ALCcontext *Context) listener->Params.DopplerFactor = 1.0f; listener->Params.SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + ATOMIC_INIT(&listener->Update, NULL); + ATOMIC_INIT(&listener->FreeList, NULL); + //Validate Context + RWLockInit(&Context->PropLock); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - ATOMIC_INIT(&Context->UpdateSources, AL_FALSE); InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); @@ -2321,6 +2328,10 @@ static ALvoid InitContext(ALCcontext *Context) */ static void FreeContext(ALCcontext *context) { + ALlistener *listener = context->Listener; + struct ALlistenerProps *lprops; + size_t count; + TRACE("%p\n", context); if(context->SourceMap.size > 0) @@ -2344,6 +2355,22 @@ static void FreeContext(ALCcontext *context) VECTOR_DEINIT(context->ActiveAuxSlots); + if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != NULL) + { + TRACE("Freed unapplied listener update %p\n", lprops); + al_free(lprops); + } + count = 0; + lprops = ATOMIC_LOAD(&listener->FreeList, almemory_order_consume); + while(lprops) + { + struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_consume); + al_free(lprops); + lprops = next; + ++count; + } + TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); + ALCdevice_DecRef(context->Device); context->Device = NULL; diff --git a/Alc/ALu.c b/Alc/ALu.c index 709b7127..82553cc7 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -266,19 +266,25 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) } -static ALvoid CalcListenerParams(ALCcontext *Context) +static ALboolean CalcListenerParams(ALCcontext *Context) { ALlistener *Listener = Context->Listener; ALdouble N[3], V[3], U[3], P[3]; + struct ALlistenerProps *first; + struct ALlistenerProps *props; + aluVector vel; + + props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel); + if(!props) return AL_FALSE; /* AT then UP */ - N[0] = Listener->Forward[0]; - N[1] = Listener->Forward[1]; - N[2] = Listener->Forward[2]; + N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed); + N[1] = ATOMIC_LOAD(&props->Forward[1], almemory_order_relaxed); + N[2] = ATOMIC_LOAD(&props->Forward[2], almemory_order_relaxed); aluNormalized(N); - V[0] = Listener->Up[0]; - V[1] = Listener->Up[1]; - V[2] = Listener->Up[2]; + V[0] = ATOMIC_LOAD(&props->Up[0], almemory_order_relaxed); + V[1] = ATOMIC_LOAD(&props->Up[1], almemory_order_relaxed); + V[2] = ATOMIC_LOAD(&props->Up[2], almemory_order_relaxed); aluNormalized(V); /* Build and normalize right-vector */ aluCrossproductd(N, V, U); @@ -291,19 +297,37 @@ static ALvoid CalcListenerParams(ALCcontext *Context) 0.0, 0.0, 0.0, 1.0 ); - P[0] = Listener->Position.v[0]; - P[1] = Listener->Position.v[1]; - P[2] = Listener->Position.v[2]; + P[0] = ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed); + P[1] = ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed); + P[2] = ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed); aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix); aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); - Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity); + aluVectorSet(&vel, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed), + ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed), + ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed), + 0.0f); + Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &vel); + + Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); + Listener->Params.MetersPerUnit = ATOMIC_LOAD(&props->MetersPerUnit, almemory_order_relaxed); - Listener->Params.Gain = Listener->Gain; - Listener->Params.MetersPerUnit = Listener->MetersPerUnit; + Listener->Params.DopplerFactor = ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed); + Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) * + ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed); - Listener->Params.DopplerFactor = Context->DopplerFactor; - Listener->Params.SpeedOfSound = Context->SpeedOfSound * Context->DopplerVelocity; + /* WARNING: A livelock is theoretically possible if another thread keeps + * changing the freelist head without giving this a chance to actually swap + * in the old container (practically impossible with this little code, + * but...). + */ + first = ATOMIC_LOAD(&Listener->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, + &Listener->FreeList, &first, props) == 0); + + return AL_TRUE; } ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) @@ -1223,10 +1247,8 @@ void UpdateContextSources(ALCcontext *ctx) ALvoice *voice, *voice_end; ALsource *source; - if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE)) + if(CalcListenerParams(ctx)) { - CalcListenerParams(ctx); - voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index f28561fa..75a3fb46 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -8,14 +8,38 @@ extern "C" { #endif +struct ALlistenerProps { + ATOMIC(ALfloat) Position[3]; + ATOMIC(ALfloat) Velocity[3]; + ATOMIC(ALfloat) Forward[3]; + ATOMIC(ALfloat) Up[3]; + ATOMIC(ALfloat) Gain; + ATOMIC(ALfloat) MetersPerUnit; + + ATOMIC(ALfloat) DopplerFactor; + ATOMIC(ALfloat) DopplerVelocity; + ATOMIC(ALfloat) SpeedOfSound; + + ATOMIC(struct ALlistenerProps*) next; +}; + typedef struct ALlistener { - aluVector Position; - aluVector Velocity; + volatile ALfloat Position[3]; + volatile ALfloat Velocity[3]; volatile ALfloat Forward[3]; volatile ALfloat Up[3]; volatile ALfloat Gain; volatile ALfloat MetersPerUnit; + /* Pointer to the most recent property values that are awaiting an update. + */ + ATOMIC(struct ALlistenerProps*) Update; + + /* A linked list of unused property containers, free to use for future + * updates. + */ + ATOMIC(struct ALlistenerProps*) FreeList; + struct { aluMatrixd Matrix; aluVector Velocity; @@ -28,6 +52,8 @@ typedef struct ALlistener { } Params; } ALlistener; +void UpdateListenerProps(ALCcontext *context); + #ifdef __cplusplus } #endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e818245b..44ce4fe0 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -679,8 +679,7 @@ struct ALCdevice_struct #define RECORD_THREAD_NAME "alsoft-record" -struct ALCcontext_struct -{ +struct ALCcontext_struct { RefCount ref; struct ALlistener *Listener; @@ -690,8 +689,6 @@ struct ALCcontext_struct ATOMIC(ALenum) LastError; - ATOMIC(ALenum) UpdateSources; - volatile enum DistanceModel DistanceModel; volatile ALboolean SourceDistanceModel; @@ -700,6 +697,8 @@ struct ALCcontext_struct volatile ALfloat SpeedOfSound; volatile ALenum DeferUpdates; + RWLock PropLock; + struct ALvoice *Voices; ALsizei VoiceCount; ALsizei MaxVoices; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 9780cff3..7f570ef8 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -29,6 +29,7 @@ #include "alAuxEffectSlot.h" #include "alThunk.h" #include "alError.h" +#include "alListener.h" #include "alSource.h" #include "almalloc.h" @@ -187,7 +188,6 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param err = InitializeEffect(device, slot, effect); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: @@ -195,12 +195,15 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); slot->AuxSendAuto = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + /* HACK: Force sources to update by doing a listener update */ + ReadLock(&context->PropLock); + UpdateListenerProps(context); + ReadUnlock(&context->PropLock); done: ALCcontext_DecRef(context); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 66865473..b215f678 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -33,29 +33,28 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(param) { case AL_GAIN: if(!(value >= 0.0f && isfinite(value))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - context->Listener->Gain = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; case AL_METERS_PER_UNIT: if(!(value >= 0.0f && isfinite(value))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - context->Listener->MetersPerUnit = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -67,33 +66,32 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(param) { case AL_POSITION: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - LockContext(context); - aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f); - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); - UnlockContext(context); + context->Listener->Position[0] = value1; + context->Listener->Position[1] = value2; + context->Listener->Position[2] = value3; break; case AL_VELOCITY: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - LockContext(context); - aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f); - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); - UnlockContext(context); + context->Listener->Velocity[0] = value1; + context->Listener->Velocity[1] = value2; + context->Listener->Velocity[2] = value3; break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -121,6 +119,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); if(!(values)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) @@ -129,8 +128,6 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) 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]; @@ -138,15 +135,15 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) context->Listener->Up[0] = values[3]; context->Listener->Up[1] = values[4]; context->Listener->Up[2] = values[5]; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); - UnlockContext(context); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -158,13 +155,16 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(param) { default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -184,13 +184,16 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(param) { default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -224,6 +227,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); if(!(values)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) @@ -231,8 +235,10 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateListenerProps(context); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -244,6 +250,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(value)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) @@ -261,6 +268,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -272,24 +280,21 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(value1 && value2 && value3)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) { case AL_POSITION: - LockContext(context); - *value1 = context->Listener->Position.v[0]; - *value2 = context->Listener->Position.v[1]; - *value3 = context->Listener->Position.v[2]; - UnlockContext(context); + *value1 = context->Listener->Position[0]; + *value2 = context->Listener->Position[1]; + *value3 = context->Listener->Position[2]; break; case AL_VELOCITY: - LockContext(context); - *value1 = context->Listener->Velocity.v[0]; - *value2 = context->Listener->Velocity.v[1]; - *value3 = context->Listener->Velocity.v[2]; - UnlockContext(context); + *value1 = context->Listener->Velocity[0]; + *value2 = context->Listener->Velocity[1]; + *value3 = context->Listener->Velocity[2]; break; default: @@ -297,6 +302,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -321,12 +327,12 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(values)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) { case AL_ORIENTATION: - LockContext(context); // AT then UP values[0] = context->Listener->Forward[0]; values[1] = context->Listener->Forward[1]; @@ -334,7 +340,6 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) values[3] = context->Listener->Up[0]; values[4] = context->Listener->Up[1]; values[5] = context->Listener->Up[2]; - UnlockContext(context); break; default: @@ -342,6 +347,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -353,6 +359,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(value)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) @@ -362,6 +369,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -373,24 +381,21 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(value1 && value2 && value3)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch (param) { case AL_POSITION: - LockContext(context); - *value1 = (ALint)context->Listener->Position.v[0]; - *value2 = (ALint)context->Listener->Position.v[1]; - *value3 = (ALint)context->Listener->Position.v[2]; - UnlockContext(context); + *value1 = (ALint)context->Listener->Position[0]; + *value2 = (ALint)context->Listener->Position[1]; + *value3 = (ALint)context->Listener->Position[2]; break; case AL_VELOCITY: - LockContext(context); - *value1 = (ALint)context->Listener->Velocity.v[0]; - *value2 = (ALint)context->Listener->Velocity.v[1]; - *value3 = (ALint)context->Listener->Velocity.v[2]; - UnlockContext(context); + *value1 = (ALint)context->Listener->Velocity[0]; + *value2 = (ALint)context->Listener->Velocity[1]; + *value3 = (ALint)context->Listener->Velocity[2]; break; default: @@ -398,6 +403,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -417,12 +423,12 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) context = GetContextRef(); if(!context) return; + ReadLock(&context->PropLock); if(!(values)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) { case AL_ORIENTATION: - LockContext(context); // AT then UP values[0] = (ALint)context->Listener->Forward[0]; values[1] = (ALint)context->Listener->Forward[1]; @@ -430,7 +436,6 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) 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: @@ -438,5 +443,64 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) } done: + ReadUnlock(&context->PropLock); ALCcontext_DecRef(context); } + + +void UpdateListenerProps(ALCcontext *context) +{ + ALlistener *listener = context->Listener; + struct ALlistenerProps *props; + + /* Get an unused proprty container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire); + if(!props) + props = al_calloc(16, sizeof(*props)); + else + { + struct ALlistenerProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, + &listener->FreeList, &props, next, almemory_order_seq_cst, + almemory_order_consume) == 0); + } + + /* Copy in current property values. */ + ATOMIC_STORE(&props->Position[0], listener->Position[0], almemory_order_relaxed); + ATOMIC_STORE(&props->Position[1], listener->Position[1], almemory_order_relaxed); + ATOMIC_STORE(&props->Position[2], listener->Position[2], almemory_order_relaxed); + + ATOMIC_STORE(&props->Velocity[0], listener->Velocity[0], almemory_order_relaxed); + ATOMIC_STORE(&props->Velocity[1], listener->Velocity[1], almemory_order_relaxed); + ATOMIC_STORE(&props->Velocity[2], listener->Velocity[2], almemory_order_relaxed); + + ATOMIC_STORE(&props->Forward[0], listener->Forward[0], almemory_order_relaxed); + ATOMIC_STORE(&props->Forward[1], listener->Forward[1], almemory_order_relaxed); + ATOMIC_STORE(&props->Forward[2], listener->Forward[2], almemory_order_relaxed); + ATOMIC_STORE(&props->Up[0], listener->Up[0], almemory_order_relaxed); + ATOMIC_STORE(&props->Up[1], listener->Up[1], almemory_order_relaxed); + ATOMIC_STORE(&props->Up[2], listener->Up[2], almemory_order_relaxed); + + ATOMIC_STORE(&props->Gain, listener->Gain, almemory_order_relaxed); + ATOMIC_STORE(&props->MetersPerUnit, listener->MetersPerUnit, almemory_order_relaxed); + + ATOMIC_STORE(&props->DopplerFactor, context->DopplerFactor, almemory_order_relaxed); + ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed); + ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed); + + /* Set the new container for updating internal parameters. */ + props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + struct ALlistenerProps *first = ATOMIC_LOAD(&listener->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, + &listener->FreeList, &first, props) == 0); + } +} diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index dca41363..899dacd4 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -26,6 +26,7 @@ #include "AL/al.h" #include "AL/alext.h" #include "alError.h" +#include "alListener.h" #include "alSource.h" #include "alAuxEffectSlot.h" @@ -55,12 +56,15 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) { case AL_SOURCE_DISTANCE_MODEL: context->SourceDistanceModel = AL_TRUE; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + /* HACK: Force sources to update by doing a listener update */ + ReadLock(&context->PropLock); + UpdateListenerProps(context); + ReadUnlock(&context->PropLock); done: ALCcontext_DecRef(context); @@ -77,12 +81,15 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) { case AL_SOURCE_DISTANCE_MODEL: context->SourceDistanceModel = AL_FALSE; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + /* HACK: Force sources to update by doing a listener update */ + ReadLock(&context->PropLock); + UpdateListenerProps(context); + ReadUnlock(&context->PropLock); done: ALCcontext_DecRef(context); @@ -547,8 +554,10 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) if(!(value >= 0.0f && isfinite(value))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&context->PropLock); context->DopplerFactor = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); + UpdateListenerProps(context); + WriteUnlock(&context->PropLock); done: ALCcontext_DecRef(context); @@ -564,8 +573,10 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) if(!(value >= 0.0f && isfinite(value))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&context->PropLock); context->DopplerVelocity = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); + UpdateListenerProps(context); + WriteUnlock(&context->PropLock); done: ALCcontext_DecRef(context); @@ -581,8 +592,10 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) if(!(value > 0.0f && isfinite(value))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&context->PropLock); context->SpeedOfSound = value; - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); + UpdateListenerProps(context); + WriteUnlock(&context->PropLock); done: ALCcontext_DecRef(context); @@ -601,9 +614,11 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) value == AL_NONE)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&context->PropLock); context->DistanceModel = value; if(!context->SourceDistanceModel) - ATOMIC_STORE(&context->UpdateSources, AL_TRUE); + UpdateListenerProps(context); + WriteUnlock(&context->PropLock); done: ALCcontext_DecRef(context); -- cgit v1.2.3 From ef0d4f8210fe6aa65b9df96f3b64bf6f355e845a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 May 2016 18:26:33 -0700 Subject: Provide (mostly) lockless updates for effect slots Similar to the listener, separate containers are provided atomically for the mixer thread to apply updates without needing to block, and a free-list is used to reuse container objects. A couple things to note. First, the lock is still used when the effect state's deviceUpdate method is called to prevent asynchronous calls to reset the device from interfering. This can be fixed by using the list lock in ALc.c instead. Secondly, old effect states aren't immediately deleted when the effect type changes (the actual type, not just its properties). This is because the mixer thread is intended to be real-time safe, and so can't be freeing anything. They are cleared away when updates reuse the container they were kept in, and they don't incur any extra processing cost, but there may be cases where the memory is kept around until the effect slot is deleted. --- Alc/ALc.c | 56 ++++++------- Alc/ALu.c | 103 +++++++++++++++-------- Alc/effects/autowah.c | 13 +-- Alc/effects/chorus.c | 17 ++-- Alc/effects/compressor.c | 7 +- Alc/effects/dedicated.c | 9 +- Alc/effects/distortion.c | 15 ++-- Alc/effects/echo.c | 13 +-- Alc/effects/equalizer.c | 29 ++++--- Alc/effects/flanger.c | 17 ++-- Alc/effects/modulator.c | 15 ++-- Alc/effects/null.c | 6 +- Alc/effects/reverb.c | 9 +- OpenAL32/Include/alAuxEffectSlot.h | 44 ++++++++-- OpenAL32/alAuxEffectSlot.c | 166 ++++++++++++++++++++++++++----------- 15 files changed, 332 insertions(+), 187 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 058dd242..b3d7eb38 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1570,12 +1570,6 @@ void ALCcontext_DeferUpdates(ALCcontext *context) /* Make sure all pending updates are performed */ UpdateContextSources(context); -#define UPDATE_SLOT(iter) do { \ - if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ - V((*iter)->EffectState,update)(device, *iter); \ -} while(0) - VECTOR_FOR_EACH(ALeffectslot*, context->ActiveAuxSlots, UPDATE_SLOT); -#undef UPDATE_SLOT } V0(device->Backend,unlock)(); @@ -2059,6 +2053,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) SetMixerFPUMode(&oldMode); V0(device->Backend,lock)(); + if(device->DefaultSlot) + { + ALeffectslot *slot = device->DefaultSlot; + ALeffectState *state = slot->Params.EffectState; + + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + if(V(state,deviceUpdate)(device) == AL_FALSE) + { + V0(device->Backend,unlock)(); + RestoreFPUMode(&oldMode); + return ALC_INVALID_DEVICE; + } + UpdateEffectSlotProps(slot); + } + context = ATOMIC_LOAD(&device->ContextList); while(context) { @@ -2069,17 +2079,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALeffectslot *slot = context->EffectSlotMap.array[pos].value; - slot->EffectState->OutBuffer = device->Dry.Buffer; - slot->EffectState->OutChannels = device->Dry.NumChannels; - if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE) + slot->Params.EffectState->OutBuffer = device->Dry.Buffer; + slot->Params.EffectState->OutChannels = device->Dry.NumChannels; + if(V(slot->Params.EffectState,deviceUpdate)(device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE); - V(slot->EffectState,update)(device, slot); + UpdateEffectSlotProps(slot); } UnlockUIntMapRead(&context->EffectSlotMap); @@ -2126,22 +2135,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = context->next; } - if(device->DefaultSlot) - { - ALeffectslot *slot = device->DefaultSlot; - ALeffectState *state = slot->EffectState; - - state->OutBuffer = device->Dry.Buffer; - state->OutChannels = device->Dry.NumChannels; - if(V(state,deviceUpdate)(device) == AL_FALSE) - { - V0(device->Backend,unlock)(); - RestoreFPUMode(&oldMode); - return ALC_INVALID_DEVICE; - } - ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE); - V(slot->EffectState,update)(device, slot); - } V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); @@ -2170,9 +2163,8 @@ static ALCvoid FreeDevice(ALCdevice *device) if(device->DefaultSlot) { - ALeffectState *state = device->DefaultSlot->EffectState; + DeinitEffectSlot(device->DefaultSlot); device->DefaultSlot = NULL; - DELETE_OBJ(state); } if(device->BufferMap.size > 0) @@ -3497,13 +3489,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } else if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR) { - ALeffectState *state = device->DefaultSlot->EffectState; + DeinitEffectSlot(device->DefaultSlot); device->DefaultSlot = NULL; - DELETE_OBJ(state); ERR("Failed to initialize the default effect\n"); } else + { aluInitEffectPanning(device->DefaultSlot); + UpdateEffectSlotProps(device->DefaultSlot); + } } { diff --git a/Alc/ALu.c b/Alc/ALu.c index 82553cc7..3b873aa5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -330,6 +330,55 @@ static ALboolean CalcListenerParams(ALCcontext *Context) return AL_TRUE; } +static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) +{ + struct ALeffectslotProps *first; + struct ALeffectslotProps *props; + + props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); + if(!props) return AL_FALSE; + + slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); + slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); + slot->Params.EffectType = ATOMIC_LOAD(&props->Type, almemory_order_relaxed); + memcpy(&slot->Params.EffectProps, &props->Props, sizeof(props->Props)); + /* If the existing state object is different from the one being set, + * exchange it so it remains in the freelist and isn't leaked. + */ + if(slot->Params.EffectState == ATOMIC_LOAD(&props->State, almemory_order_relaxed)) + slot->Params.EffectState = NULL; + slot->Params.EffectState = ATOMIC_EXCHANGE(ALeffectState*, + &props->State, slot->Params.EffectState, almemory_order_relaxed + ); + if(IsReverbEffect(slot->Params.EffectType)) + { + slot->Params.RoomRolloff = slot->Params.EffectProps.Reverb.RoomRolloffFactor; + slot->Params.DecayTime = slot->Params.EffectProps.Reverb.DecayTime; + slot->Params.AirAbsorptionGainHF = slot->Params.EffectProps.Reverb.AirAbsorptionGainHF; + } + else + { + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.AirAbsorptionGainHF = 1.0f; + } + + V(slot->Params.EffectState,update)(device, slot); + + /* WARNING: A livelock is theoretically possible if another thread keeps + * changing the freelist head without giving this a chance to actually swap + * in the old container (practically impossible with this little code, + * but...). + */ + first = ATOMIC_LOAD(&slot->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + &slot->FreeList, &first, props) == 0); + + return AL_TRUE; +} + ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { @@ -415,7 +464,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A SendSlots[i] = ALSource->Send[i].Slot; if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; - if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL) + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; voice->Send[i].OutBuffer = NULL; @@ -847,7 +896,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; - if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL) + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; RoomRolloff[i] = 0.0f; @@ -856,19 +905,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer } else if(SendSlots[i]->AuxSendAuto) { - RoomRolloff[i] = RoomRolloffBase; - if(IsReverbEffect(SendSlots[i]->EffectType)) - { - RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor; - DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime * - SPEEDOFSOUNDMETRESPERSEC; - RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF; - } - else - { - DecayDistance[i] = 0.0f; - RoomAirAbsorption[i] = 1.0f; - } + RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + RoomRolloffBase; + DecayDistance[i] = SendSlots[i]->Params.DecayTime * + SPEEDOFSOUNDMETRESPERSEC; + RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF; } else { @@ -1245,9 +1285,18 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer void UpdateContextSources(ALCcontext *ctx) { ALvoice *voice, *voice_end; + ALboolean fullupdate; ALsource *source; - if(CalcListenerParams(ctx)) + fullupdate = CalcListenerParams(ctx); +#define UPDATE_SLOT(iter) do { \ + if(CalcEffectSlotParams(*iter, ctx->Device)) \ + fullupdate = AL_TRUE; \ +} while(0) + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); +#undef UPDATE_SLOT + + if(fullupdate) { voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; @@ -1388,8 +1437,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if((slot=device->DefaultSlot) != NULL) { - if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE)) - V(slot->EffectState,update)(device, slot); + CalcEffectSlotParams(device->DefaultSlot, device); for(i = 0;i < slot->NumChannels;i++) memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); } @@ -1398,26 +1446,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(ctx) { if(!ctx->DeferUpdates) - { UpdateContextSources(ctx); -#define UPDATE_SLOT(iter) do { \ - if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ - V((*iter)->EffectState,update)(device, *iter); \ - for(i = 0;i < (*iter)->NumChannels;i++) \ - memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ -} while(0) - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); -#undef UPDATE_SLOT - } - else - { #define CLEAR_WET_BUFFER(iter) do { \ for(i = 0;i < (*iter)->NumChannels;i++) \ memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ } while(0) - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER); + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER); #undef CLEAR_WET_BUFFER - } /* source processing */ voice = ctx->Voices; @@ -1434,7 +1469,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) for(i = 0;i < c;i++) { const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i); - ALeffectState *state = slot->EffectState; + ALeffectState *state = slot->Params.EffectState; V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, state->OutChannels); } @@ -1445,7 +1480,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(device->DefaultSlot != NULL) { const ALeffectslot *slot = device->DefaultSlot; - ALeffectState *state = slot->EffectState; + ALeffectState *state = slot->Params.EffectState; V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, state->OutChannels); } diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 7c5abfb1..1e7a8e29 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -53,8 +53,9 @@ typedef struct ALautowahState { ALfilterState LowPass; } ALautowahState; -static ALvoid ALautowahState_Destruct(ALautowahState *UNUSED(state)) +static ALvoid ALautowahState_Destruct(ALautowahState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device) @@ -67,15 +68,15 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *devi { ALfloat attackTime, releaseTime; - attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency; - releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency; + attackTime = slot->Params.EffectProps.Autowah.AttackTime * state->Frequency; + releaseTime = slot->Params.EffectProps.Autowah.ReleaseTime * state->Frequency; state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime); state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime); - state->PeakGain = slot->EffectProps.Autowah.PeakGain; - state->Resonance = slot->EffectProps.Autowah.Resonance; + state->PeakGain = slot->Params.EffectProps.Autowah.PeakGain; + state->Resonance = slot->Params.EffectProps.Autowah.Resonance; - ComputeAmbientGains(device->Dry, slot->Gain, state->Gain); + ComputeAmbientGains(device->Dry, slot->Params.Gain, state->Gain); } static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 9deb2a1f..3eff95a4 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -60,6 +60,7 @@ static ALvoid ALchorusState_Destruct(ALchorusState *state) free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) @@ -98,7 +99,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device ALfloat rate; ALint phase; - switch(Slot->EffectProps.Chorus.Waveform) + switch(Slot->Params.EffectProps.Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: state->waveform = CWF_Triangle; @@ -107,18 +108,18 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device state->waveform = CWF_Sinusoid; break; } - state->depth = Slot->EffectProps.Chorus.Depth; - state->feedback = Slot->EffectProps.Chorus.Feedback; - state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); + state->depth = Slot->Params.EffectProps.Chorus.Depth; + state->feedback = Slot->Params.EffectProps.Chorus.Feedback; + state->delay = fastf2i(Slot->Params.EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); - phase = Slot->EffectProps.Chorus.Phase; - rate = Slot->EffectProps.Chorus.Rate; + phase = Slot->Params.EffectProps.Chorus.Phase; + rate = Slot->Params.EffectProps.Chorus.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index bc4955b9..c501b3ba 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -40,8 +40,9 @@ typedef struct ALcompressorState { ALfloat GainCtrl; } ALcompressorState; -static ALvoid ALcompressorState_Destruct(ALcompressorState *UNUSED(state)) +static ALvoid ALcompressorState_Destruct(ALcompressorState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device) @@ -60,7 +61,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice aluMatrixf matrix; ALuint i; - state->Enabled = slot->EffectProps.Compressor.OnOff; + state->Enabled = slot->Params.EffectProps.Compressor.OnOff; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, @@ -72,7 +73,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain, + ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain, state->Gain[i]); } diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index f510e8fe..34e5ed80 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -36,8 +36,9 @@ typedef struct ALdedicatedState { } ALdedicatedState; -static ALvoid ALdedicatedState_Destruct(ALdedicatedState *UNUSED(state)) +static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device)) @@ -53,8 +54,8 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) state->gains[i] = 0.0f; - Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain; - if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + Gain = Slot->Params.Gain * Slot->Params.EffectProps.Dedicated.Gain; + if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) @@ -64,7 +65,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * state->gains[idx] = Gain; } } - else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) + else if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) { int idx; /* Dialog goes to the front-center speaker if it exists, otherwise it diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 7a4c2f62..534a817c 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -43,8 +43,9 @@ typedef struct ALdistortionState { ALfloat edge_coeff; } ALdistortionState; -static ALvoid ALdistortionState_Destruct(ALdistortionState *UNUSED(state)) +static ALvoid ALdistortionState_Destruct(ALdistortionState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device)) @@ -60,15 +61,15 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ALfloat edge; /* Store distorted signal attenuation settings */ - state->attenuation = Slot->EffectProps.Distortion.Gain; + state->attenuation = Slot->Params.EffectProps.Distortion.Gain; /* Store waveshaper edge settings */ - edge = sinf(Slot->EffectProps.Distortion.Edge * (F_PI_2)); + edge = sinf(Slot->Params.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; + cutoff = Slot->Params.EffectProps.Distortion.LowpassCutoff; /* Bandwidth value is constant in octaves */ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, @@ -76,14 +77,14 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ); /* Bandpass filter */ - cutoff = Slot->EffectProps.Distortion.EQCenter; + cutoff = Slot->Params.EffectProps.Distortion.EQCenter; /* Convert bandwidth in Hz to octaves */ - bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f); + bandwidth = Slot->Params.EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f); ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(Device->Dry, Slot->Gain, state->Gain); + ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 8600db70..eea86f15 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -54,6 +54,7 @@ static ALvoid ALechoState_Destruct(ALechoState *state) { free(state->SampleBuffer); state->SampleBuffer = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) @@ -87,11 +88,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gain, lrpan, spread; - state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1; - state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency); + state->Tap[0].delay = fastf2u(Slot->Params.EffectProps.Echo.Delay * frequency) + 1; + state->Tap[1].delay = fastf2u(Slot->Params.EffectProps.Echo.LRDelay * frequency); state->Tap[1].delay += state->Tap[0].delay; - spread = Slot->EffectProps.Echo.Spread; + spread = Slot->Params.EffectProps.Echo.Spread; if(spread < 0.0f) lrpan = -1.0f; else lrpan = 1.0f; /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage @@ -99,14 +100,14 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co */ spread = asinf(1.0f - fabsf(spread))*4.0f; - state->FeedGain = Slot->EffectProps.Echo.Feedback; + state->FeedGain = Slot->Params.EffectProps.Echo.Feedback; - gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f); + gain = minf(1.0f - Slot->Params.EffectProps.Echo.Damping, 0.01f); ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, gain, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gain, 0.75f)); - gain = Slot->Gain; + gain = Slot->Params.Gain; /* First tap panning */ CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index e0fa010e..94ee1853 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -87,8 +87,9 @@ typedef struct ALequalizerState { ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES]; } ALequalizerState; -static ALvoid ALequalizerState_Destruct(ALequalizerState *UNUSED(state)) +static ALvoid ALequalizerState_Destruct(ALequalizerState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device)) @@ -113,15 +114,15 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Gain, + ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint * of the transition band. */ - gain = sqrtf(slot->EffectProps.Equalizer.LowGain); - freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency; + gain = sqrtf(slot->Params.EffectProps.Equalizer.LowGain); + freq_mult = slot->Params.EffectProps.Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); @@ -136,10 +137,12 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[0][i].process = state->filter[0][0].process; } - gain = slot->EffectProps.Equalizer.Mid1Gain; - freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency; + gain = slot->Params.EffectProps.Equalizer.Mid1Gain; + freq_mult = slot->Params.EffectProps.Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking, - gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width) + gain, freq_mult, calc_rcpQ_from_bandwidth( + freq_mult, slot->Params.EffectProps.Equalizer.Mid1Width + ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { @@ -151,10 +154,12 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[1][i].process = state->filter[1][0].process; } - gain = slot->EffectProps.Equalizer.Mid2Gain; - freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency; + gain = slot->Params.EffectProps.Equalizer.Mid2Gain; + freq_mult = slot->Params.EffectProps.Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking, - gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width) + gain, freq_mult, calc_rcpQ_from_bandwidth( + freq_mult, slot->Params.EffectProps.Equalizer.Mid2Width + ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { @@ -166,8 +171,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[2][i].process = state->filter[2][0].process; } - gain = sqrtf(slot->EffectProps.Equalizer.HighGain); - freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency; + gain = sqrtf(slot->Params.EffectProps.Equalizer.HighGain); + freq_mult = slot->Params.EffectProps.Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index a71eb9c2..966622e6 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -60,6 +60,7 @@ static ALvoid ALflangerState_Destruct(ALflangerState *state) free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device) @@ -98,7 +99,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi ALfloat rate; ALint phase; - switch(Slot->EffectProps.Flanger.Waveform) + switch(Slot->Params.EffectProps.Flanger.Waveform) { case AL_FLANGER_WAVEFORM_TRIANGLE: state->waveform = FWF_Triangle; @@ -107,18 +108,18 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi state->waveform = FWF_Sinusoid; break; } - state->depth = Slot->EffectProps.Flanger.Depth; - state->feedback = Slot->EffectProps.Flanger.Feedback; - state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency); + state->depth = Slot->Params.EffectProps.Flanger.Depth; + state->feedback = Slot->Params.EffectProps.Flanger.Feedback; + state->delay = fastf2i(Slot->Params.EffectProps.Flanger.Delay * frequency); /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[0]); + ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]); CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Slot->Gain, state->Gain[1]); + ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); - phase = Slot->EffectProps.Flanger.Phase; - rate = Slot->EffectProps.Flanger.Rate; + phase = Slot->Params.EffectProps.Flanger.Phase; + rate = Slot->Params.EffectProps.Flanger.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index fb75043a..5a96bb9d 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -82,8 +82,9 @@ DECL_TEMPLATE(Square) #undef DECL_TEMPLATE -static ALvoid ALmodulatorState_Destruct(ALmodulatorState *UNUSED(state)) +static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device)) @@ -97,19 +98,19 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * ALfloat cw, a; ALuint i; - if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Process = ModulateSin; - else if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + else if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->Process = ModulateSaw; - else /*if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ + else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->Process = ModulateSquare; - state->step = fastf2u(Slot->EffectProps.Modulator.Frequency*WAVEFORM_FRACONE / + state->step = fastf2u(Slot->Params.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_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency); + cw = cosf(F_TAU * Slot->Params.EffectProps.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) @@ -132,7 +133,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Gain, + ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Params.Gain, state->Gain[i]); } diff --git a/Alc/effects/null.c b/Alc/effects/null.c index 0600703d..b90f75c9 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -15,10 +15,12 @@ typedef struct ALnullState { /* This destructs (not free!) the effect state. It's called only when the - * effect slot is no longer used. + * effect slot is no longer used. Make sure to call the parent Destruct + * function before returning! */ -static ALvoid ALnullState_Destruct(ALnullState* UNUSED(state)) +static ALvoid ALnullState_Destruct(ALnullState *state) { + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } /* This updates the device-dependant effect state. This is called on diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ef3ab6c3..bd5637e9 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -169,6 +169,7 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) { free(State->SampleBuffer); State->SampleBuffer = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); } static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); @@ -894,15 +895,15 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) { - const ALeffectProps *props = &Slot->EffectProps; + const ALeffectProps *props = &Slot->Params.EffectProps; ALuint frequency = Device->Frequency; ALfloat lfscale, hfscale, hfRatio; ALfloat gain, gainlf, gainhf; ALfloat cw, x, y; - if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) + if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) State->IsEax = AL_TRUE; - else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) + else if(Slot->Params.EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) State->IsEax = AL_FALSE; // Calculate the master filters @@ -952,7 +953,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.Diffusion, props->Reverb.EchoDepth, hfRatio, cw, frequency, State); - gain = props->Reverb.Gain * Slot->Gain * ReverbBoost; + gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; // Update early and late 3D panning. if(Device->Hrtf || Device->Uhj_Encoder) UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index e521ff82..7f670a95 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -20,6 +20,8 @@ typedef struct ALeffectState { ALuint OutChannels; } ALeffectState; +void ALeffectState_Destruct(ALeffectState *state); + struct ALeffectStateVtable { void (*const Destruct)(ALeffectState *state); @@ -70,18 +72,48 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = #define MAX_EFFECT_CHANNELS (4) -typedef struct ALeffectslot { - ALenum EffectType; - ALeffectProps EffectProps; +struct ALeffectslotProps { + ATOMIC(ALfloat) Gain; + ATOMIC(ALboolean) AuxSendAuto; + + ATOMIC(ALenum) Type; + ALeffectProps Props; + + ATOMIC(ALeffectState*) State; + + ATOMIC(struct ALeffectslotProps*) next; +}; + +typedef struct ALeffectslot { volatile ALfloat Gain; volatile ALboolean AuxSendAuto; - ATOMIC(ALenum) NeedsUpdate; - ALeffectState *EffectState; + struct { + ALenum Type; + ALeffectProps Props; + + ALeffectState *State; + } Effect; RefCount ref; + ATOMIC(struct ALeffectslotProps*) Update; + ATOMIC(struct ALeffectslotProps*) FreeList; + + struct { + ALfloat Gain; + ALboolean AuxSendAuto; + + ALenum EffectType; + ALeffectProps EffectProps; + ALeffectState *EffectState; + + ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ + ALfloat DecayTime; + ALfloat AirAbsorptionGainHF; + } Params; + /* Self ID */ ALuint id; @@ -106,6 +138,8 @@ inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) { return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); } ALenum InitEffectSlot(ALeffectslot *slot); +void DeinitEffectSlot(ALeffectslot *slot); +void UpdateEffectSlotProps(ALeffectslot *slot); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 7f570ef8..1407e1b1 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -86,7 +86,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(err != AL_NO_ERROR) { FreeThunkEntry(slot->id); - DELETE_OBJ(slot->EffectState); + DELETE_OBJ(slot->Params.EffectState); al_free(slot); alDeleteAuxiliaryEffectSlots(cur, effectslots); @@ -139,7 +139,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * FreeThunkEntry(slot->id); RemoveEffectSlotArray(context, slot); - DELETE_OBJ(slot->EffectState); + DeinitEffectSlot(slot); memset(slot, 0, sizeof(*slot)); al_free(slot); @@ -175,12 +175,13 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param context = GetContextRef(); if(!context) return; - device = context->Device; + WriteLock(&context->PropLock); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) { case AL_EFFECTSLOT_EFFECT: + device = context->Device; effect = (value ? LookupEffect(device, value) : NULL); if(!(value == 0 || effect != NULL)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -193,19 +194,16 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param 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; break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - /* HACK: Force sources to update by doing a listener update */ - ReadLock(&context->PropLock); - UpdateListenerProps(context); - ReadUnlock(&context->PropLock); + UpdateEffectSlotProps(slot); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -244,6 +242,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -251,16 +250,16 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param case AL_EFFECTSLOT_GAIN: if(!(value >= 0.0f && value <= 1.0f)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - slot->Gain = value; - ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + UpdateEffectSlotProps(slot); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -451,7 +450,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); ALeffectStateFactory *factory; - if(newtype != EffectSlot->EffectType) + if(newtype != EffectSlot->Effect.Type) { ALeffectState *State; FPUCtl oldMode; @@ -467,7 +466,9 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e return AL_OUT_OF_MEMORY; SetMixerFPUMode(&oldMode); - + /* FIXME: This just needs to prevent the device from being reset during + * the state's device update, so the list lock in ALc.c should do here. + */ ALCdevice_Lock(Device); State->OutBuffer = Device->Dry.Buffer; State->OutChannels = Device->Dry.NumChannels; @@ -478,70 +479,135 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e DELETE_OBJ(State); return AL_OUT_OF_MEMORY; } - - State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State); - if(!effect) - { - memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps)); - EffectSlot->EffectType = AL_EFFECT_NULL; - } - else - { - 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. */ - ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE); - V(EffectSlot->EffectState,update)(Device, EffectSlot); ALCdevice_Unlock(Device); - RestoreFPUMode(&oldMode); - DELETE_OBJ(State); - State = NULL; + EffectSlot->Effect.State = State; + } + + if(!effect) + { + EffectSlot->Effect.Type = AL_EFFECT_NULL; + memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); } else { - if(effect) - { - ALCdevice_Lock(Device); - memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props)); - ALCdevice_Unlock(Device); - ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE); - } + EffectSlot->Effect.Type = effect->type; + memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); } return AL_NO_ERROR; } +void ALeffectState_Destruct(ALeffectState *UNUSED(state)) +{ +} + + ALenum InitEffectSlot(ALeffectslot *slot) { ALeffectStateFactory *factory; - ALuint i, c; - slot->EffectType = AL_EFFECT_NULL; + slot->Effect.Type = AL_EFFECT_NULL; factory = getFactoryByType(AL_EFFECT_NULL); - if(!(slot->EffectState=V0(factory,create)())) + if(!(slot->Effect.State=V0(factory,create)())) return AL_OUT_OF_MEMORY; slot->Gain = 1.0; slot->AuxSendAuto = AL_TRUE; - ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE); - for(c = 0;c < 1;c++) - { - for(i = 0;i < BUFFERSIZE;i++) - slot->WetBuffer[c][i] = 0.0f; - } InitRef(&slot->ref, 0); + ATOMIC_INIT(&slot->Update, NULL); + ATOMIC_INIT(&slot->FreeList, NULL); + + slot->Params.Gain = 1.0f; + slot->Params.AuxSendAuto = AL_TRUE; + slot->Params.EffectState = slot->Effect.State; + slot->Params.RoomRolloff = 0.0f; + slot->Params.DecayTime = 0.0f; + slot->Params.AirAbsorptionGainHF = 1.0f; + return AL_NO_ERROR; } +void DeinitEffectSlot(ALeffectslot *slot) +{ + struct ALeffectslotProps *props; + size_t count = 0; + + props = ATOMIC_LOAD(&slot->Update); + if(props) + { + DELETE_OBJ(props->State); + TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); + al_free(props); + } + props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); + while(props) + { + struct ALeffectslotProps *next; + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + DELETE_OBJ(props->State); + al_free(props); + props = next; + ++count; + } + TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); + + DELETE_OBJ(slot->Params.EffectState); +} + +void UpdateEffectSlotProps(ALeffectslot *slot) +{ + struct ALeffectslotProps *props; + ALeffectState *oldstate; + + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&slot->FreeList, almemory_order_acquire); + if(!props) + props = al_calloc(16, sizeof(*props)); + else + { + struct ALeffectslotProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + &slot->FreeList, &props, next, almemory_order_seq_cst, + almemory_order_consume) == 0); + } + + /* Copy in current property values. */ + ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed); + ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed); + + ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed); + memcpy(&props->Props, &slot->Effect.Props, sizeof(props->Props)); + /* Swap out any stale effect state object there may be in the container, to + * delete it. + */ + oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, + almemory_order_relaxed); + + /* Set the new container for updating internal parameters. */ + props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props, + almemory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + struct ALeffectslotProps *first = ATOMIC_LOAD(&slot->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + &slot->FreeList, &first, props) == 0); + } + + DELETE_OBJ(oldstate); +} + ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) { ALsizei pos; @@ -550,7 +616,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) ALeffectslot *temp = Context->EffectSlotMap.array[pos].value; Context->EffectSlotMap.array[pos].value = NULL; - DELETE_OBJ(temp->EffectState); + DeinitEffectSlot(temp); FreeThunkEntry(temp->id); memset(temp, 0, sizeof(ALeffectslot)); -- cgit v1.2.3 From 210e150601d9b458d446483f5f16e1e67cc6e3ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 May 2016 19:05:06 -0700 Subject: Avoid updating the effect state object if it's not changed --- Alc/ALc.c | 24 ++++++++++++------------ Alc/ALu.c | 15 +++++++-------- OpenAL32/Include/alAuxEffectSlot.h | 4 +++- OpenAL32/alAuxEffectSlot.c | 34 +++++++++++++++++++++------------- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b3d7eb38..47aa0f04 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2066,7 +2066,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - UpdateEffectSlotProps(slot); + UpdateEffectSlotProps(slot, AL_FALSE); } context = ATOMIC_LOAD(&device->ContextList); @@ -2078,17 +2078,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(pos = 0;pos < context->EffectSlotMap.size;pos++) { ALeffectslot *slot = context->EffectSlotMap.array[pos].value; + ALeffectState *state = slot->Params.EffectState; - slot->Params.EffectState->OutBuffer = device->Dry.Buffer; - slot->Params.EffectState->OutChannels = device->Dry.NumChannels; - if(V(slot->Params.EffectState,deviceUpdate)(device) == AL_FALSE) + state->OutBuffer = device->Dry.Buffer; + state->OutChannels = device->Dry.NumChannels; + if(V(state,deviceUpdate)(device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - UpdateEffectSlotProps(slot); + UpdateEffectSlotProps(slot, AL_FALSE); } UnlockUIntMapRead(&context->EffectSlotMap); @@ -3487,16 +3488,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->DefaultSlot = NULL; ERR("Failed to initialize the default effect slot\n"); } - else if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR) - { - DeinitEffectSlot(device->DefaultSlot); - device->DefaultSlot = NULL; - ERR("Failed to initialize the default effect\n"); - } else { aluInitEffectPanning(device->DefaultSlot); - UpdateEffectSlotProps(device->DefaultSlot); + if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR) + { + DeinitEffectSlot(device->DefaultSlot); + device->DefaultSlot = NULL; + ERR("Failed to initialize the default effect\n"); + } } } diff --git a/Alc/ALu.c b/Alc/ALu.c index 3b873aa5..a555b834 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -342,14 +342,6 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); slot->Params.EffectType = ATOMIC_LOAD(&props->Type, almemory_order_relaxed); memcpy(&slot->Params.EffectProps, &props->Props, sizeof(props->Props)); - /* If the existing state object is different from the one being set, - * exchange it so it remains in the freelist and isn't leaked. - */ - if(slot->Params.EffectState == ATOMIC_LOAD(&props->State, almemory_order_relaxed)) - slot->Params.EffectState = NULL; - slot->Params.EffectState = ATOMIC_EXCHANGE(ALeffectState*, - &props->State, slot->Params.EffectState, almemory_order_relaxed - ); if(IsReverbEffect(slot->Params.EffectType)) { slot->Params.RoomRolloff = slot->Params.EffectProps.Reverb.RoomRolloffFactor; @@ -362,6 +354,13 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; } + /* If the state object is changed, exchange it with the current one so it + * remains in the freelist and isn't leaked. + */ + if(ATOMIC_LOAD(&props->UpdateState, almemory_order_relaxed)) + slot->Params.EffectState = ATOMIC_EXCHANGE(ALeffectState*, + &props->State, slot->Params.EffectState, almemory_order_relaxed + ); V(slot->Params.EffectState,update)(device, slot); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 7f670a95..85827746 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -79,6 +79,8 @@ struct ALeffectslotProps { ATOMIC(ALenum) Type; ALeffectProps Props; + /* Flag indicates if State should be updated. */ + ATOMIC(ALboolean) UpdateState; ATOMIC(ALeffectState*) State; ATOMIC(struct ALeffectslotProps*) next; @@ -139,7 +141,7 @@ inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); -void UpdateEffectSlotProps(ALeffectslot *slot); +void UpdateEffectSlotProps(ALeffectslot *slot, ALboolean withstate); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 1407e1b1..368a0fb1 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -195,12 +195,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!(value == AL_TRUE || value == AL_FALSE)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); slot->AuxSendAuto = value; + UpdateEffectSlotProps(slot, AL_FALSE); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateEffectSlotProps(slot); done: WriteUnlock(&context->PropLock); @@ -256,7 +256,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateEffectSlotProps(slot); + UpdateEffectSlotProps(slot, AL_FALSE); done: WriteUnlock(&context->PropLock); @@ -482,18 +482,24 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e ALCdevice_Unlock(Device); RestoreFPUMode(&oldMode); - EffectSlot->Effect.State = State; - } + if(!effect) + { + EffectSlot->Effect.Type = AL_EFFECT_NULL; + memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); + } + else + { + EffectSlot->Effect.Type = effect->type; + memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); + } - if(!effect) - { - EffectSlot->Effect.Type = AL_EFFECT_NULL; - memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); + EffectSlot->Effect.State = State; + UpdateEffectSlotProps(EffectSlot, AL_TRUE); } - else + else if(effect) { - EffectSlot->Effect.Type = effect->type; memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); + UpdateEffectSlotProps(EffectSlot, AL_FALSE); } return AL_NO_ERROR; @@ -559,7 +565,7 @@ void DeinitEffectSlot(ALeffectslot *slot) DELETE_OBJ(slot->Params.EffectState); } -void UpdateEffectSlotProps(ALeffectslot *slot) +void UpdateEffectSlotProps(ALeffectslot *slot, ALboolean withstate) { struct ALeffectslotProps *props; ALeffectState *oldstate; @@ -587,8 +593,10 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* Swap out any stale effect state object there may be in the container, to * delete it. */ - oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, - almemory_order_relaxed); + ATOMIC_STORE(&props->UpdateState, withstate, almemory_order_relaxed); + oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, + withstate ? slot->Effect.State : NULL, almemory_order_relaxed + ); /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props, -- cgit v1.2.3 From 8d14824c657a1471d08e175c8153909627313d70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 May 2016 19:17:08 -0700 Subject: Call the effect state update method after "returning" the container object. --- Alc/ALu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index a555b834..6f4db05e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -362,8 +362,6 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) &props->State, slot->Params.EffectState, almemory_order_relaxed ); - V(slot->Params.EffectState,update)(device, slot); - /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap * in the old container (practically impossible with this little code, @@ -375,6 +373,8 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, &slot->FreeList, &first, props) == 0); + V(slot->Params.EffectState,update)(device, slot); + return AL_TRUE; } -- cgit v1.2.3 From 9e6d8342de62df83377b19577268af7106cdc088 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 May 2016 23:12:11 -0700 Subject: Hold the effect and filter maps while handling effects and filters --- Alc/effects/reverb.c | 8 -------- OpenAL32/Include/alEffect.h | 13 +++++++++++-- OpenAL32/Include/alFilter.h | 13 +++++++++++-- OpenAL32/alAuxEffectSlot.c | 8 +++++++- OpenAL32/alEffect.c | 27 +++++++++++++++++++++++++-- OpenAL32/alFilter.c | 27 +++++++++++++++++++++++++-- OpenAL32/alSource.c | 11 ++++++++++- 7 files changed, 89 insertions(+), 18 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index bd5637e9..0f851295 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1652,20 +1652,16 @@ void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum 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: @@ -1786,18 +1782,14 @@ void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum 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: diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 91ee782f..d20ef077 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -176,10 +176,19 @@ typedef struct ALeffect { ALuint id; } ALeffect; +inline void LockEffectsRead(ALCdevice *device) +{ LockUIntMapRead(&device->EffectMap); } +inline void UnlockEffectsRead(ALCdevice *device) +{ UnlockUIntMapRead(&device->EffectMap); } +inline void LockEffectsWrite(ALCdevice *device) +{ LockUIntMapWrite(&device->EffectMap); } +inline void UnlockEffectsWrite(ALCdevice *device) +{ UnlockUIntMapWrite(&device->EffectMap); } + inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ return (struct ALeffect*)LookupUIntMapKey(&device->EffectMap, id); } +{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); } inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id) -{ return (struct ALeffect*)RemoveUIntMapKey(&device->EffectMap, id); } +{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); } inline ALboolean IsReverbEffect(ALenum type) { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 6f44e3b7..855bb534 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -151,10 +151,19 @@ 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 void LockFiltersRead(ALCdevice *device) +{ LockUIntMapRead(&device->FilterMap); } +inline void UnlockFiltersRead(ALCdevice *device) +{ UnlockUIntMapRead(&device->FilterMap); } +inline void LockFiltersWrite(ALCdevice *device) +{ LockUIntMapWrite(&device->FilterMap); } +inline void UnlockFiltersWrite(ALCdevice *device) +{ UnlockUIntMapWrite(&device->FilterMap); } + inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)LookupUIntMapKey(&device->FilterMap, id); } +{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); } inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)RemoveUIntMapKey(&device->FilterMap, id); } +{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); } ALvoid ReleaseALFilters(ALCdevice *device); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 368a0fb1..70bb4e43 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -182,11 +182,17 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param { case AL_EFFECTSLOT_EFFECT: device = context->Device; + + LockEffectsRead(device); effect = (value ? LookupEffect(device, value) : NULL); if(!(value == 0 || effect != NULL)) + { + UnlockEffectsRead(device); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - + } err = InitializeEffect(device, slot, effect); + UnlockEffectsRead(device); + if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 0bfe11b9..5a036091 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -34,6 +34,10 @@ ALboolean DisabledEffects[MAX_EFFECTS]; +extern inline void LockEffectsRead(ALCdevice *device); +extern inline void UnlockEffectsRead(ALCdevice *device); +extern inline void LockEffectsWrite(ALCdevice *device); +extern inline void UnlockEffectsWrite(ALCdevice *device); extern inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id); extern inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id); extern inline ALboolean IsReverbEffect(ALenum type); @@ -95,10 +99,10 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) context = GetContextRef(); if(!context) return; + device = context->Device; + LockEffectsWrite(device); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; for(i = 0;i < n;i++) { if(effects[i] && LookupEffect(device, effects[i]) == NULL) @@ -115,6 +119,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) } done: + UnlockEffectsWrite(device); ALCcontext_DecRef(context); } @@ -126,8 +131,10 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) Context = GetContextRef(); if(!Context) return AL_FALSE; + LockEffectsRead(Context->Device); result = ((!effect || LookupEffect(Context->Device, effect)) ? AL_TRUE : AL_FALSE); + UnlockEffectsRead(Context->Device); ALCcontext_DecRef(Context); @@ -144,6 +151,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(!Context) return; Device = Context->Device; + LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -170,6 +178,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) V(ALEffect,setParami)(Context, param, value); } } + UnlockEffectsWrite(Device); ALCcontext_DecRef(Context); } @@ -191,6 +200,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v if(!Context) return; Device = Context->Device; + LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -198,6 +208,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v /* Call the appropriate handler */ V(ALEffect,setParamiv)(Context, param, values); } + UnlockEffectsWrite(Device); ALCcontext_DecRef(Context); } @@ -212,6 +223,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) if(!Context) return; Device = Context->Device; + LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -219,6 +231,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) /* Call the appropriate handler */ V(ALEffect,setParamf)(Context, param, value); } + UnlockEffectsWrite(Device); ALCcontext_DecRef(Context); } @@ -233,6 +246,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat if(!Context) return; Device = Context->Device; + LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -240,6 +254,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat /* Call the appropriate handler */ V(ALEffect,setParamfv)(Context, param, values); } + UnlockEffectsWrite(Device); ALCcontext_DecRef(Context); } @@ -254,6 +269,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value if(!Context) return; Device = Context->Device; + LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -266,6 +282,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value V(ALEffect,getParami)(Context, param, value); } } + UnlockEffectsRead(Device); ALCcontext_DecRef(Context); } @@ -287,6 +304,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu if(!Context) return; Device = Context->Device; + LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -294,6 +312,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu /* Call the appropriate handler */ V(ALEffect,getParamiv)(Context, param, values); } + UnlockEffectsRead(Device); ALCcontext_DecRef(Context); } @@ -308,6 +327,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val if(!Context) return; Device = Context->Device; + LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -315,6 +335,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val /* Call the appropriate handler */ V(ALEffect,getParamf)(Context, param, value); } + UnlockEffectsRead(Device); ALCcontext_DecRef(Context); } @@ -329,6 +350,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va if(!Context) return; Device = Context->Device; + LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -336,6 +358,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va /* Call the appropriate handler */ V(ALEffect,getParamfv)(Context, param, values); } + UnlockEffectsRead(Device); ALCcontext_DecRef(Context); } diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 8e04ec2a..7be3e339 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -29,6 +29,10 @@ #include "alError.h" +extern inline void LockFiltersRead(ALCdevice *device); +extern inline void UnlockFiltersRead(ALCdevice *device); +extern inline void LockFiltersWrite(ALCdevice *device); +extern inline void UnlockFiltersWrite(ALCdevice *device); extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); @@ -94,10 +98,10 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) context = GetContextRef(); if(!context) return; + device = context->Device; + LockFiltersWrite(device); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; for(i = 0;i < n;i++) { if(filters[i] && LookupFilter(device, filters[i]) == NULL) @@ -114,6 +118,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) } done: + UnlockFiltersWrite(device); ALCcontext_DecRef(context); } @@ -125,8 +130,10 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) Context = GetContextRef(); if(!Context) return AL_FALSE; + LockFiltersRead(Context->Device); result = ((!filter || LookupFilter(Context->Device, filter)) ? AL_TRUE : AL_FALSE); + UnlockFiltersRead(Context->Device); ALCcontext_DecRef(Context); @@ -143,6 +150,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) if(!Context) return; Device = Context->Device; + LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -161,6 +169,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) ALfilter_SetParami(ALFilter, Context, param, value); } } + UnlockFiltersWrite(Device); ALCcontext_DecRef(Context); } @@ -182,6 +191,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v if(!Context) return; Device = Context->Device; + LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -189,6 +199,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v /* Call the appropriate handler */ ALfilter_SetParamiv(ALFilter, Context, param, values); } + UnlockFiltersWrite(Device); ALCcontext_DecRef(Context); } @@ -203,6 +214,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) if(!Context) return; Device = Context->Device; + LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -210,6 +222,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) /* Call the appropriate handler */ ALfilter_SetParamf(ALFilter, Context, param, value); } + UnlockFiltersWrite(Device); ALCcontext_DecRef(Context); } @@ -224,6 +237,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat if(!Context) return; Device = Context->Device; + LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -231,6 +245,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat /* Call the appropriate handler */ ALfilter_SetParamfv(ALFilter, Context, param, values); } + UnlockFiltersWrite(Device); ALCcontext_DecRef(Context); } @@ -245,6 +260,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value if(!Context) return; Device = Context->Device; + LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -257,6 +273,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value ALfilter_GetParami(ALFilter, Context, param, value); } } + UnlockFiltersRead(Device); ALCcontext_DecRef(Context); } @@ -278,6 +295,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu if(!Context) return; Device = Context->Device; + LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -285,6 +303,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu /* Call the appropriate handler */ ALfilter_GetParamiv(ALFilter, Context, param, values); } + UnlockFiltersRead(Device); ALCcontext_DecRef(Context); } @@ -299,6 +318,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val if(!Context) return; Device = Context->Device; + LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -306,6 +326,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val /* Call the appropriate handler */ ALfilter_GetParamf(ALFilter, Context, param, value); } + UnlockFiltersRead(Device); ALCcontext_DecRef(Context); } @@ -320,6 +341,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va if(!Context) return; Device = Context->Device; + LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME); else @@ -327,6 +349,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va /* Call the appropriate handler */ ALfilter_GetParamfv(ALFilter, Context, param, values); } + UnlockFiltersRead(Device); ALCcontext_DecRef(Context); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 8cab5ab3..a62bf59e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -715,7 +715,12 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DIRECT_FILTER: - CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL); + LockFiltersRead(device); + if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) + { + UnlockFiltersRead(device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + } LockContext(Context); if(!filter) @@ -735,6 +740,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Direct.LFReference = filter->LFReference; } UnlockContext(Context); + UnlockFiltersRead(device); ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); return AL_TRUE; @@ -782,12 +788,14 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: + LockFiltersRead(device); LockContext(Context); if(!((ALuint)values[1] < device->NumAuxSends && (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) { UnlockContext(Context); + UnlockFiltersRead(device); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } @@ -814,6 +822,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].LFReference = filter->LFReference; } UnlockContext(Context); + UnlockFiltersRead(device); ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); return AL_TRUE; -- cgit v1.2.3 From 770bdcc108948d57d209878bf300c3e46346f931 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 May 2016 23:41:23 -0700 Subject: Recognize AUX0...AUX15 for decoder speaker labels --- Alc/panning.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 9ff97477..2116e739 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -437,9 +437,17 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe c = GetChannelIdxByName(device->RealOut, BackCenter); else { - ERR("AmbDec speaker label \"%s\" not recognized\n", - al_string_get_cstr(conf->Speakers[i].Name)); - return false; + const char *name = al_string_get_cstr(conf->Speakers[i].Name); + unsigned int n; + char ch; + + if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16) + c = GetChannelIdxByName(device->RealOut, Aux0+n); + else + { + ERR("AmbDec speaker label \"%s\" not recognized\n", name); + return false; + } } if(c == -1) { -- cgit v1.2.3 From 59cd6230a661d5cee69c0a44c4dde152eed9f865 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 May 2016 00:23:03 -0700 Subject: Properly load the effect state pointer from the property container --- OpenAL32/alAuxEffectSlot.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 70bb4e43..98ee9328 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -552,7 +552,9 @@ void DeinitEffectSlot(ALeffectslot *slot) props = ATOMIC_LOAD(&slot->Update); if(props) { - DELETE_OBJ(props->State); + ALeffectState *state; + state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); + DELETE_OBJ(state); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } @@ -560,8 +562,10 @@ void DeinitEffectSlot(ALeffectslot *slot) while(props) { struct ALeffectslotProps *next; + ALeffectState *state; + state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - DELETE_OBJ(props->State); + DELETE_OBJ(state); al_free(props); props = next; ++count; -- cgit v1.2.3 From d89043b88e4e055931b97aaef56d520317d8c158 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 13 May 2016 09:04:26 -0500 Subject: alsoft-config: Raise source limit to 4096 --- utils/alsoft-config/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 8f703f7f..bbe179e1 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -278,7 +278,7 @@ MainWindow::MainWindow(QWidget *parent) : mPeriodCountValidator = new QIntValidator(2, 16, this); ui->periodCountEdit->setValidator(mPeriodCountValidator); - mSourceCountValidator = new QIntValidator(0, 256, this); + mSourceCountValidator = new QIntValidator(0, 4096, this); ui->srcCountLineEdit->setValidator(mSourceCountValidator); mEffectSlotValidator = new QIntValidator(0, 16, this); ui->effectSlotLineEdit->setValidator(mEffectSlotValidator); -- cgit v1.2.3 From 93a94d177c4bb0b9c8feb85420a388d32df4cc8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 May 2016 18:28:01 -0700 Subject: Get rid of an unnecessary copy of ALeffectProps --- Alc/ALu.c | 11 +++++------ Alc/effects/autowah.c | 10 +++++----- Alc/effects/chorus.c | 14 +++++++------- Alc/effects/compressor.c | 4 ++-- Alc/effects/dedicated.c | 4 ++-- Alc/effects/distortion.c | 12 ++++++------ Alc/effects/echo.c | 12 ++++++------ Alc/effects/equalizer.c | 22 +++++++++++----------- Alc/effects/flanger.c | 14 +++++++------- Alc/effects/modulator.c | 10 +++++----- Alc/effects/null.c | 2 +- Alc/effects/reverb.c | 5 ++--- OpenAL32/Include/alAuxEffectSlot.h | 5 ++--- 13 files changed, 61 insertions(+), 64 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 6f4db05e..6ae89b89 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -341,12 +341,11 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); slot->Params.EffectType = ATOMIC_LOAD(&props->Type, almemory_order_relaxed); - memcpy(&slot->Params.EffectProps, &props->Props, sizeof(props->Props)); if(IsReverbEffect(slot->Params.EffectType)) { - slot->Params.RoomRolloff = slot->Params.EffectProps.Reverb.RoomRolloffFactor; - slot->Params.DecayTime = slot->Params.EffectProps.Reverb.DecayTime; - slot->Params.AirAbsorptionGainHF = slot->Params.EffectProps.Reverb.AirAbsorptionGainHF; + slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; + slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; } else { @@ -362,6 +361,8 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) &props->State, slot->Params.EffectState, almemory_order_relaxed ); + V(slot->Params.EffectState,update)(device, slot, &props->Props); + /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap * in the old container (practically impossible with this little code, @@ -373,8 +374,6 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, &slot->FreeList, &first, props) == 0); - V(slot->Params.EffectState,update)(device, slot); - return AL_TRUE; } diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 1e7a8e29..648afc83 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -64,17 +64,17 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d return AL_TRUE; } -static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props) { ALfloat attackTime, releaseTime; - attackTime = slot->Params.EffectProps.Autowah.AttackTime * state->Frequency; - releaseTime = slot->Params.EffectProps.Autowah.ReleaseTime * state->Frequency; + attackTime = props->Autowah.AttackTime * state->Frequency; + releaseTime = props->Autowah.ReleaseTime * state->Frequency; state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime); state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime); - state->PeakGain = slot->Params.EffectProps.Autowah.PeakGain; - state->Resonance = slot->Params.EffectProps.Autowah.Resonance; + state->PeakGain = props->Autowah.PeakGain; + state->Resonance = props->Autowah.Resonance; ComputeAmbientGains(device->Dry, slot->Params.Gain, state->Gain); } diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 3eff95a4..e1cbba2d 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -92,14 +92,14 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev return AL_TRUE; } -static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat rate; ALint phase; - switch(Slot->Params.EffectProps.Chorus.Waveform) + switch(props->Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: state->waveform = CWF_Triangle; @@ -108,9 +108,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device state->waveform = CWF_Sinusoid; break; } - state->depth = Slot->Params.EffectProps.Chorus.Depth; - state->feedback = Slot->Params.EffectProps.Chorus.Feedback; - state->delay = fastf2i(Slot->Params.EffectProps.Chorus.Delay * frequency); + state->depth = props->Chorus.Depth; + state->feedback = props->Chorus.Feedback; + state->delay = fastf2i(props->Chorus.Delay * frequency); /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); @@ -118,8 +118,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); - phase = Slot->Params.EffectProps.Chorus.Phase; - rate = Slot->Params.EffectProps.Chorus.Rate; + phase = props->Chorus.Phase; + rate = props->Chorus.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index c501b3ba..6329d3f1 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -56,12 +56,12 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev return AL_TRUE; } -static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props) { aluMatrixf matrix; ALuint i; - state->Enabled = slot->Params.EffectProps.Compressor.OnOff; + state->Enabled = props->Compressor.OnOff; aluMatrixfSet(&matrix, 1.0f, 0.0f, 0.0f, 0.0f, diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 34e5ed80..98dd560b 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -46,7 +46,7 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), return AL_TRUE; } -static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot) +static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props) { ALfloat Gain; ALuint i; @@ -54,7 +54,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) state->gains[i] = 0.0f; - Gain = Slot->Params.Gain * Slot->Params.EffectProps.Dedicated.Gain; + Gain = Slot->Params.Gain * props->Dedicated.Gain; if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 534a817c..deec6092 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -53,7 +53,7 @@ static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state) return AL_TRUE; } -static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat bandwidth; @@ -61,15 +61,15 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ALfloat edge; /* Store distorted signal attenuation settings */ - state->attenuation = Slot->Params.EffectProps.Distortion.Gain; + state->attenuation = props->Distortion.Gain; /* Store waveshaper edge settings */ - edge = sinf(Slot->Params.EffectProps.Distortion.Edge * (F_PI_2)); + edge = sinf(props->Distortion.Edge * (F_PI_2)); edge = minf(edge, 0.99f); state->edge_coeff = 2.0f * edge / (1.0f-edge); /* Lowpass filter */ - cutoff = Slot->Params.EffectProps.Distortion.LowpassCutoff; + cutoff = props->Distortion.LowpassCutoff; /* Bandwidth value is constant in octaves */ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, @@ -77,9 +77,9 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ); /* Bandpass filter */ - cutoff = Slot->Params.EffectProps.Distortion.EQCenter; + cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves */ - bandwidth = Slot->Params.EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f); + bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index eea86f15..0632a44d 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -82,17 +82,17 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) return AL_TRUE; } -static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALuint frequency = Device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gain, lrpan, spread; - state->Tap[0].delay = fastf2u(Slot->Params.EffectProps.Echo.Delay * frequency) + 1; - state->Tap[1].delay = fastf2u(Slot->Params.EffectProps.Echo.LRDelay * frequency); + state->Tap[0].delay = fastf2u(props->Echo.Delay * frequency) + 1; + state->Tap[1].delay = fastf2u(props->Echo.LRDelay * frequency); state->Tap[1].delay += state->Tap[0].delay; - spread = Slot->Params.EffectProps.Echo.Spread; + spread = props->Echo.Spread; if(spread < 0.0f) lrpan = -1.0f; else lrpan = 1.0f; /* Convert echo spread (where 0 = omni, +/-1 = directional) to coverage @@ -100,9 +100,9 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co */ spread = asinf(1.0f - fabsf(spread))*4.0f; - state->FeedGain = Slot->Params.EffectProps.Echo.Feedback; + state->FeedGain = props->Echo.Feedback; - gain = minf(1.0f - Slot->Params.EffectProps.Echo.Damping, 0.01f); + gain = minf(1.0f - props->Echo.Damping, 0.01f); ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, gain, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gain, 0.75f)); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 94ee1853..25e36724 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -97,7 +97,7 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), return AL_TRUE; } -static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot) +static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props) { ALfloat frequency = (ALfloat)device->Frequency; ALfloat gain, freq_mult; @@ -121,8 +121,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * * filters' gain is for the reference frequency, which is the centerpoint * of the transition band. */ - gain = sqrtf(slot->Params.EffectProps.Equalizer.LowGain); - freq_mult = slot->Params.EffectProps.Equalizer.LowCutoff/frequency; + gain = sqrtf(props->Equalizer.LowGain); + freq_mult = props->Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); @@ -137,11 +137,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[0][i].process = state->filter[0][0].process; } - gain = slot->Params.EffectProps.Equalizer.Mid1Gain; - freq_mult = slot->Params.EffectProps.Equalizer.Mid1Center/frequency; + gain = props->Equalizer.Mid1Gain; + freq_mult = props->Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( - freq_mult, slot->Params.EffectProps.Equalizer.Mid1Width + freq_mult, props->Equalizer.Mid1Width ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) @@ -154,11 +154,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[1][i].process = state->filter[1][0].process; } - gain = slot->Params.EffectProps.Equalizer.Mid2Gain; - freq_mult = slot->Params.EffectProps.Equalizer.Mid2Center/frequency; + gain = props->Equalizer.Mid2Gain; + freq_mult = props->Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( - freq_mult, slot->Params.EffectProps.Equalizer.Mid2Width + freq_mult, props->Equalizer.Mid2Width ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) @@ -171,8 +171,8 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[2][i].process = state->filter[2][0].process; } - gain = sqrtf(slot->Params.EffectProps.Equalizer.HighGain); - freq_mult = slot->Params.EffectProps.Equalizer.HighCutoff/frequency; + gain = sqrtf(props->Equalizer.HighGain); + freq_mult = props->Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 966622e6..7b55977e 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -92,14 +92,14 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D return AL_TRUE; } -static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALfloat frequency = (ALfloat)Device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat rate; ALint phase; - switch(Slot->Params.EffectProps.Flanger.Waveform) + switch(props->Flanger.Waveform) { case AL_FLANGER_WAVEFORM_TRIANGLE: state->waveform = FWF_Triangle; @@ -108,9 +108,9 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi state->waveform = FWF_Sinusoid; break; } - state->depth = Slot->Params.EffectProps.Flanger.Depth; - state->feedback = Slot->Params.EffectProps.Flanger.Feedback; - state->delay = fastf2i(Slot->Params.EffectProps.Flanger.Delay * frequency); + state->depth = props->Flanger.Depth; + state->feedback = props->Flanger.Feedback; + state->delay = fastf2i(props->Flanger.Delay * frequency); /* Gains for left and right sides */ CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); @@ -118,8 +118,8 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); - phase = Slot->Params.EffectProps.Flanger.Phase; - rate = Slot->Params.EffectProps.Flanger.Rate; + phase = props->Flanger.Phase; + rate = props->Flanger.Rate; if(!(rate > 0.0f)) { state->lfo_scale = 0.0f; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 5a96bb9d..0b0971b2 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -92,25 +92,25 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), return AL_TRUE; } -static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { aluMatrixf matrix; ALfloat cw, a; ALuint i; - if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Process = ModulateSin; - else if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->Process = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->Process = ModulateSquare; - state->step = fastf2u(Slot->Params.EffectProps.Modulator.Frequency*WAVEFORM_FRACONE / + state->step = fastf2u(props->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_TAU * Slot->Params.EffectProps.Modulator.HighPassCutoff / Device->Frequency); + cw = cosf(F_TAU * props->Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) diff --git a/Alc/effects/null.c b/Alc/effects/null.c index b90f75c9..a135b194 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -35,7 +35,7 @@ static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice* /* 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), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot)) +static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props)) { } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0f851295..916469a8 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -173,7 +173,7 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) } static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); -static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot); +static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); @@ -893,9 +893,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection } } -static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { - const ALeffectProps *props = &Slot->Params.EffectProps; ALuint frequency = Device->Frequency; ALfloat lfscale, hfscale, hfRatio; ALfloat gain, gainlf, gainhf; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 85827746..28c0b46f 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -26,7 +26,7 @@ struct ALeffectStateVtable { void (*const Destruct)(ALeffectState *state); ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); - void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot); + void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props); void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); void (*const Delete)(void *ptr); @@ -35,7 +35,7 @@ struct ALeffectStateVtable { #define DEFINE_ALEFFECTSTATE_VTABLE(T) \ DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ -DECLARE_THUNK2(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*) \ +DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \ DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ @@ -108,7 +108,6 @@ typedef struct ALeffectslot { ALboolean AuxSendAuto; ALenum EffectType; - ALeffectProps EffectProps; ALeffectState *EffectState; ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ -- cgit v1.2.3 From f751f5e25e2a6451dc68ecf091ea5a6d57513679 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 May 2016 20:21:20 -0700 Subject: Store the remaining context properties with the listener properties --- Alc/ALu.c | 8 ++++++-- OpenAL32/Include/alListener.h | 6 ++++++ OpenAL32/alListener.c | 4 ++++ OpenAL32/alState.c | 10 ++++------ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 6ae89b89..4a9a59cf 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -316,6 +316,10 @@ static ALboolean CalcListenerParams(ALCcontext *Context) Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) * ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed); + Listener->Params.SourceDistanceModel = ATOMIC_LOAD(&props->SourceDistanceModel, + almemory_order_relaxed); + Listener->Params.DistanceModel = ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed); + /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap * in the old container (practically impossible with this little code, @@ -960,8 +964,8 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer Attenuation = 1.0f; for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; - switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel : - ALContext->DistanceModel) + switch(Listener->Params.SourceDistanceModel ? ALSource->DistanceModel : + Listener->Params.DistanceModel) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 75a3fb46..dee66720 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -20,6 +20,9 @@ struct ALlistenerProps { ATOMIC(ALfloat) DopplerVelocity; ATOMIC(ALfloat) SpeedOfSound; + ATOMIC(ALboolean) SourceDistanceModel; + ATOMIC(enum DistanceModel) DistanceModel; + ATOMIC(struct ALlistenerProps*) next; }; @@ -49,6 +52,9 @@ typedef struct ALlistener { ALfloat DopplerFactor; ALfloat SpeedOfSound; + + ALboolean SourceDistanceModel; + enum DistanceModel DistanceModel; } Params; } ALlistener; diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index b215f678..1c40c399 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -490,6 +490,10 @@ void UpdateListenerProps(ALCcontext *context) ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed); ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed); + ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel, + almemory_order_relaxed); + ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed); + /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); if(props) diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 899dacd4..c0c2ca82 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -52,6 +52,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -61,12 +62,10 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - /* HACK: Force sources to update by doing a listener update */ - ReadLock(&context->PropLock); UpdateListenerProps(context); - ReadUnlock(&context->PropLock); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -77,6 +76,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) context = GetContextRef(); if(!context) return; + WriteLock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -86,12 +86,10 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - /* HACK: Force sources to update by doing a listener update */ - ReadLock(&context->PropLock); UpdateListenerProps(context); - ReadUnlock(&context->PropLock); done: + WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } -- cgit v1.2.3 From b3338d25f6d4fd02935ac83d0d3f227b145307d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 May 2016 23:43:40 -0700 Subject: Provide asynchronous property updates for sources This necessitates a change in how source updates are handled. Rather than just being able to update sources when a dependent object state is changed (e.g. a listener gain change), now all source updates must be proactively provided. Consequently, apps that do not utilize any deferring (AL_SOFT_defer_updates or alcSuspendContext/alcProcessContext) may utilize more CPU since it'll be filling out more update containers for the mixer thread to use. The upside is that there's less blocking between the app's calling thread and the mixer thread, particularly for vectors and other multi-value properties (filters and sends). Deferring behavior when used is also improved, since updates that shouldn't be applied yet are simply not provided. And when they are provided, the mixer doesn't have to ignore them, meaning the actual deferring of a context doesn't have to synchrnously force an update -- the process call will send any pending updates, which the mixer will apply even if another deferral occurs before the mixer runs, because it'll still be there waiting on the next mixer invocation. There is one slight bug introduced by this commit. When a listener change is made, or changes to multiple sources while updates are being deferred, it is possible for the mixer to run while the sources are prepping their updates, causing some of the source updates to be seen before the other. This will be fixed in short order. --- Alc/ALc.c | 65 ++----- Alc/ALu.c | 267 +++++++++++++------------- Alc/mixer.c | 2 +- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alSource.h | 104 +++++++--- OpenAL32/Include/alu.h | 5 +- OpenAL32/alAuxEffectSlot.c | 2 + OpenAL32/alListener.c | 36 +++- OpenAL32/alSource.c | 452 +++++++++++++++++++++++++++++++------------- OpenAL32/alState.c | 48 +++-- 10 files changed, 627 insertions(+), 356 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 47aa0f04..e5c18d8c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1558,22 +1558,7 @@ extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS */ void ALCcontext_DeferUpdates(ALCcontext *context) { - ALCdevice *device = context->Device; - FPUCtl oldMode; - - SetMixerFPUMode(&oldMode); - - V0(device->Backend,lock)(); - if(!context->DeferUpdates) - { - context->DeferUpdates = AL_TRUE; - - /* Make sure all pending updates are performed */ - UpdateContextSources(context); - } - V0(device->Backend,unlock)(); - - RestoreFPUMode(&oldMode); + ATOMIC_STORE(&context->DeferUpdates, AL_TRUE); } /* ALCcontext_ProcessUpdates @@ -1584,14 +1569,15 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) { ALCdevice *device = context->Device; - V0(device->Backend,lock)(); - if(context->DeferUpdates) + ReadLock(&context->PropLock); + if(ATOMIC_EXCHANGE(ALenum, &context->DeferUpdates, AL_FALSE)) { ALsizei pos; - context->DeferUpdates = AL_FALSE; + UpdateListenerProps(context); LockUIntMapRead(&context->SourceMap); + V0(device->Backend,lock)(); for(pos = 0;pos < context->SourceMap.size;pos++) { ALsource *Source = context->SourceMap.array[pos].value; @@ -1610,9 +1596,11 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) if(new_state) SetSourceState(Source, context, new_state); } + V0(device->Backend,unlock)(); UnlockUIntMapRead(&context->SourceMap); + UpdateAllSourceProps(context); } - V0(device->Backend,unlock)(); + ReadUnlock(&context->PropLock); } @@ -2052,7 +2040,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } SetMixerFPUMode(&oldMode); - V0(device->Backend,lock)(); if(device->DefaultSlot) { ALeffectslot *slot = device->DefaultSlot; @@ -2062,7 +2049,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) state->OutChannels = device->Dry.NumChannels; if(V(state,deviceUpdate)(device) == AL_FALSE) { - V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } @@ -2074,6 +2060,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALsizei pos; + ReadLock(&context->PropLock); LockUIntMapRead(&context->EffectSlotMap); for(pos = 0;pos < context->EffectSlotMap.size;pos++) { @@ -2085,10 +2072,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(V(state,deviceUpdate)(device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); - V0(device->Backend,unlock)(); + ReadUnlock(&context->PropLock); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } + UpdateEffectSlotProps(slot, AL_FALSE); } UnlockUIntMapRead(&context->EffectSlotMap); @@ -2105,38 +2093,19 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) source->Send[s].Slot = NULL; source->Send[s].Gain = 1.0f; source->Send[s].GainHF = 1.0f; + source->Send[s].HFReference = LOWPASSFREQREF; + source->Send[s].GainLF = 1.0f; + source->Send[s].LFReference = HIGHPASSFREQREF; s++; } - ATOMIC_STORE(&source->NeedsUpdate, AL_TRUE); } UnlockUIntMapRead(&context->SourceMap); - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = &context->Voices[pos]; - ALsource *source = voice->Source; - ALbufferlistitem *BufferListItem; - - if(!source) - continue; - - BufferListItem = ATOMIC_LOAD(&source->queue); - while(BufferListItem != NULL) - { - ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); - voice->Update(voice, source, buffer, context); - break; - } - BufferListItem = BufferListItem->next; - } - } + UpdateAllSourceProps(context); + ReadUnlock(&context->PropLock); context = context->next; } - V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); if(!(device->Flags&DEVICE_PAUSED)) @@ -2308,7 +2277,7 @@ static ALvoid InitContext(ALCcontext *Context) Context->DopplerFactor = 1.0f; Context->DopplerVelocity = 1.0f; Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; - Context->DeferUpdates = AL_FALSE; + ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); Context->ExtensionList = alExtList; } diff --git a/Alc/ALu.c b/Alc/ALu.c index 4a9a59cf..2fffdcd9 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -266,7 +266,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) } -static ALboolean CalcListenerParams(ALCcontext *Context) +static void CalcListenerParams(ALCcontext *Context) { ALlistener *Listener = Context->Listener; ALdouble N[3], V[3], U[3], P[3]; @@ -275,7 +275,7 @@ static ALboolean CalcListenerParams(ALCcontext *Context) aluVector vel; props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel); - if(!props) return AL_FALSE; + if(!props) return; /* AT then UP */ N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed); @@ -330,17 +330,15 @@ static ALboolean CalcListenerParams(ALCcontext *Context) ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, &Listener->FreeList, &first, props) == 0); - - return AL_TRUE; } -static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) +static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) { struct ALeffectslotProps *first; struct ALeffectslotProps *props; props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); - if(!props) return AL_FALSE; + if(!props) return; slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); @@ -377,11 +375,43 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, &slot->FreeList, &first, props) == 0); +} + +static void CalcSourceParams(ALvoice *voice, ALCcontext *context) +{ + ALsource *source = voice->Source; + ALbufferlistitem *BufferListItem; + struct ALsourceProps *first; + struct ALsourceProps *props; + + props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); + if(!props) return; + + BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + while(BufferListItem != NULL) + { + ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + voice->Update(voice, props, buffer, context); + break; + } + BufferListItem = BufferListItem->next; + } - return AL_TRUE; + /* WARNING: A livelock is theoretically possible if another thread keeps + * changing the freelist head without giving this a chance to actually swap + * in the old container (practically impossible with this little code, + * but...). + */ + first = ATOMIC_LOAD(&source->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, + &source->FreeList, &first, props) == 0); } -ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +ALvoid CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } @@ -448,22 +478,22 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ListenerGain = Listener->Params.Gain; /* Get source properties */ - SourceVolume = ALSource->Gain; - MinVolume = ALSource->MinGain; - MaxVolume = ALSource->MaxGain; - Pitch = ALSource->Pitch; - Relative = ALSource->HeadRelative; - DirectChannels = ALSource->DirectChannels; + SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); + MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed); + MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed); + Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed); + Relative = ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed); + DirectChannels = ATOMIC_LOAD(&props->DirectChannels, almemory_order_relaxed); /* Convert counter-clockwise to clockwise. */ - StereoMap[0].angle = -ALSource->StereoPan[0]; - StereoMap[1].angle = -ALSource->StereoPan[1]; + StereoMap[0].angle = -ATOMIC_LOAD(&props->StereoPan[0], almemory_order_relaxed); + StereoMap[1].angle = -ATOMIC_LOAD(&props->StereoPan[1], almemory_order_relaxed); voice->Direct.OutBuffer = Device->Dry.Buffer; voice->Direct.OutChannels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { - SendSlots[i] = ALSource->Send[i].Slot; + SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) @@ -489,15 +519,15 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); - DryGain *= ALSource->Direct.Gain * ListenerGain; - DryGainHF = ALSource->Direct.GainHF; - DryGainLF = ALSource->Direct.GainLF; + DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGainHF = ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); + DryGainLF = ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); - WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; - WetGainHF[i] = ALSource->Send[i].GainHF; - WetGainLF[i] = ALSource->Send[i].GainLF; + WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGainHF[i] = ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); + WetGainLF[i] = ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); } switch(ALBuffer->FmtChannels) @@ -557,13 +587,13 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A ALfloat scale; /* AT then UP */ - N[0] = ALSource->Orientation[0][0]; - N[1] = ALSource->Orientation[0][1]; - N[2] = ALSource->Orientation[0][2]; + N[0] = ATOMIC_LOAD(&props->Orientation[0][0], almemory_order_relaxed); + N[1] = ATOMIC_LOAD(&props->Orientation[0][1], almemory_order_relaxed); + N[2] = ATOMIC_LOAD(&props->Orientation[0][2], almemory_order_relaxed); aluNormalize(N); - V[0] = ALSource->Orientation[1][0]; - V[1] = ALSource->Orientation[1][1]; - V[2] = ALSource->Orientation[1][2]; + V[0] = ATOMIC_LOAD(&props->Orientation[1][0], almemory_order_relaxed); + V[1] = ATOMIC_LOAD(&props->Orientation[1][1], almemory_order_relaxed); + V[2] = ATOMIC_LOAD(&props->Orientation[1][2], almemory_order_relaxed); aluNormalize(V); if(!Relative) { @@ -779,8 +809,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } { - ALfloat hfscale = ALSource->Direct.HFReference / Frequency; - ALfloat lfscale = ALSource->Direct.LFReference / Frequency; + ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / + Frequency; + ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / + Frequency; DryGainHF = maxf(DryGainHF, 0.0001f); DryGainLF = maxf(DryGainLF, 0.0001f); for(c = 0;c < num_channels;c++) @@ -800,8 +832,10 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } for(i = 0;i < NumSends;i++) { - ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; - ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; + ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / + Frequency; + ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / + Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); for(c = 0;c < num_channels;c++) @@ -821,7 +855,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } } -ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +ALvoid CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; @@ -862,7 +896,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer } /* Get context/device properties */ - DopplerFactor = Listener->Params.DopplerFactor * ALSource->DopplerFactor; + DopplerFactor = Listener->Params.DopplerFactor; SpeedOfSound = Listener->Params.SpeedOfSound; NumSends = Device->NumAuxSends; Frequency = Device->Frequency; @@ -872,29 +906,39 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer MetersPerUnit = Listener->Params.MetersPerUnit; /* Get source properties */ - SourceVolume = ALSource->Gain; - MinVolume = ALSource->MinGain; - MaxVolume = ALSource->MaxGain; - Pitch = ALSource->Pitch; - Position = ALSource->Position; - Direction = ALSource->Direction; - Velocity = ALSource->Velocity; - MinDist = ALSource->RefDistance; - MaxDist = ALSource->MaxDistance; - Rolloff = ALSource->RollOffFactor; - InnerAngle = ALSource->InnerAngle; - OuterAngle = ALSource->OuterAngle; - AirAbsorptionFactor = ALSource->AirAbsorptionFactor; - DryGainHFAuto = ALSource->DryGainHFAuto; - WetGainAuto = ALSource->WetGainAuto; - WetGainHFAuto = ALSource->WetGainHFAuto; - RoomRolloffBase = ALSource->RoomRolloffFactor; + SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); + MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed); + MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed); + Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed); + aluVectorSet(&Position, ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed), + ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed), + ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed), + 1.0f); + aluVectorSet(&Direction, ATOMIC_LOAD(&props->Direction[0], almemory_order_relaxed), + ATOMIC_LOAD(&props->Direction[1], almemory_order_relaxed), + ATOMIC_LOAD(&props->Direction[2], almemory_order_relaxed), + 0.0f); + aluVectorSet(&Velocity, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed), + ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed), + ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed), + 0.0f); + MinDist = ATOMIC_LOAD(&props->RefDistance, almemory_order_relaxed); + MaxDist = ATOMIC_LOAD(&props->MaxDistance, almemory_order_relaxed); + Rolloff = ATOMIC_LOAD(&props->RollOffFactor, almemory_order_relaxed); + DopplerFactor *= ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed); + InnerAngle = ATOMIC_LOAD(&props->InnerAngle, almemory_order_relaxed); + OuterAngle = ATOMIC_LOAD(&props->OuterAngle, almemory_order_relaxed); + AirAbsorptionFactor = ATOMIC_LOAD(&props->AirAbsorptionFactor, almemory_order_relaxed); + DryGainHFAuto = ATOMIC_LOAD(&props->DryGainHFAuto, almemory_order_relaxed); + WetGainAuto = ATOMIC_LOAD(&props->WetGainAuto, almemory_order_relaxed); + WetGainHFAuto = ATOMIC_LOAD(&props->WetGainHFAuto, almemory_order_relaxed); + RoomRolloffBase = ATOMIC_LOAD(&props->RoomRolloffFactor, almemory_order_relaxed); voice->Direct.OutBuffer = Device->Dry.Buffer; voice->Direct.OutChannels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { - SendSlots[i] = ALSource->Send[i].Slot; + SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; @@ -905,7 +949,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = 1.0f; } - else if(SendSlots[i]->AuxSendAuto) + else if(SendSlots[i]->Params.AuxSendAuto) { RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + RoomRolloffBase; DecayDistance[i] = SendSlots[i]->Params.DecayTime * @@ -934,7 +978,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer } /* Transform source to listener space (convert to head relative) */ - if(ALSource->HeadRelative == AL_FALSE) + if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE) { const aluMatrixd *Matrix = &Listener->Params.Matrix; /* Transform source vectors */ @@ -964,8 +1008,9 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer Attenuation = 1.0f; for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; - switch(Listener->Params.SourceDistanceModel ? ALSource->DistanceModel : - Listener->Params.DistanceModel) + switch(Listener->Params.SourceDistanceModel ? + ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed) : + Listener->Params.DistanceModel) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); @@ -1059,13 +1104,15 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer if(Angle > InnerAngle && Angle <= OuterAngle) { ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); - ConeVolume = lerp(1.0f, ALSource->OuterGain, scale); - ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale); + ConeVolume = lerp(1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), + scale); + ConeHF = lerp(1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), + scale); } else if(Angle > OuterAngle) { - ConeVolume = ALSource->OuterGain; - ConeHF = ALSource->OuterGainHF; + ConeVolume = ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed); + ConeHF = ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed); } else { @@ -1093,14 +1140,14 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); /* Apply gain and frequency filters */ - DryGain *= ALSource->Direct.Gain * ListenerGain; - DryGainHF *= ALSource->Direct.GainHF; - DryGainLF *= ALSource->Direct.GainLF; + DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGainHF *= ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); + DryGainLF *= ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); for(i = 0;i < NumSends;i++) { - WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; - WetGainHF[i] *= ALSource->Send[i].GainHF; - WetGainLF[i] *= ALSource->Send[i].GainLF; + WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGainHF[i] *= ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); + WetGainLF[i] *= ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); } /* Calculate velocity-based doppler effect */ @@ -1139,7 +1186,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat ev = 0.0f, az = 0.0f; - ALfloat radius = ALSource->Radius; + ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed); ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat spread = 0.0f; @@ -1193,7 +1240,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer { /* Non-HRTF rendering. */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; - ALfloat radius = ALSource->Radius; + ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed); ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat spread = 0.0f; @@ -1247,8 +1294,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer } { - ALfloat hfscale = ALSource->Direct.HFReference / Frequency; - ALfloat lfscale = ALSource->Direct.LFReference / Frequency; + ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / + Frequency; + ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / + Frequency; DryGainHF = maxf(DryGainHF, 0.0001f); DryGainLF = maxf(DryGainLF, 0.0001f); voice->Direct.Filters[0].ActiveType = AF_None; @@ -1265,8 +1314,10 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer } for(i = 0;i < NumSends;i++) { - ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; - ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; + ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / + Frequency; + ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / + Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); voice->Send[i].Filters[0].ActiveType = AF_None; @@ -1287,69 +1338,22 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALbuffer void UpdateContextSources(ALCcontext *ctx) { ALvoice *voice, *voice_end; - ALboolean fullupdate; ALsource *source; - fullupdate = CalcListenerParams(ctx); -#define UPDATE_SLOT(iter) do { \ - if(CalcEffectSlotParams(*iter, ctx->Device)) \ - fullupdate = AL_TRUE; \ -} while(0) + CalcListenerParams(ctx); +#define UPDATE_SLOT(iter) CalcEffectSlotParams(*iter, ctx->Device) VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); #undef UPDATE_SLOT - if(fullupdate) + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) { - voice = ctx->Voices; - voice_end = voice + ctx->VoiceCount; - for(;voice != voice_end;++voice) - { - if(!(source=voice->Source)) continue; - if(source->state != AL_PLAYING && source->state != AL_PAUSED) - voice->Source = NULL; - else - { - ALbufferlistitem *BufferListItem; - BufferListItem = ATOMIC_LOAD(&source->queue); - while(BufferListItem != NULL) - { - ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); - voice->Update(voice, source, buffer, ctx); - break; - } - BufferListItem = BufferListItem->next; - } - } - } - } - else - { - voice = ctx->Voices; - voice_end = voice + ctx->VoiceCount; - for(;voice != voice_end;++voice) - { - if(!(source=voice->Source)) continue; - if(source->state != AL_PLAYING && source->state != AL_PAUSED) - voice->Source = NULL; - else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE)) - { - ALbufferlistitem *BufferListItem; - BufferListItem = ATOMIC_LOAD(&source->queue); - while(BufferListItem != NULL) - { - ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - voice->Update(voice, source, buffer, ctx); - break; - } - BufferListItem = BufferListItem->next; - } - } - } + if(!(source=voice->Source)) continue; + if(source->state != AL_PLAYING && source->state != AL_PAUSED) + voice->Source = NULL; + else + CalcSourceParams(voice, ctx); } } @@ -1447,8 +1451,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ctx = ATOMIC_LOAD(&device->ContextList); while(ctx) { - if(!ctx->DeferUpdates) - UpdateContextSources(ctx); + UpdateContextSources(ctx); #define CLEAR_WET_BUFFER(iter) do { \ for(i = 0;i < (*iter)->NumChannels;i++) \ memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ diff --git a/Alc/mixer.c b/Alc/mixer.c index 44495d72..38ec295c 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -388,9 +388,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam BufferListItem = ATOMIC_LOAD(&Source->current_buffer); DataPosInt = Source->position; DataPosFrac = Source->position_fraction; - Looping = Source->Looping; NumChannels = Source->NumChannels; SampleSize = Source->SampleSize; + Looping = voice->Looping; increment = voice->Step; IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 44ce4fe0..a624e078 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -695,7 +695,7 @@ struct ALCcontext_struct { volatile ALfloat DopplerFactor; volatile ALfloat DopplerVelocity; volatile ALfloat SpeedOfSound; - volatile ALenum DeferUpdates; + ATOMIC(ALenum) DeferUpdates; RWLock PropLock; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 187d7e07..6d915153 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -13,6 +13,7 @@ extern "C" { struct ALbuffer; struct ALsource; +struct ALsourceProps; typedef struct ALbufferlistitem { @@ -25,11 +26,13 @@ typedef struct ALvoice { struct ALsource *volatile Source; /** Method to update mixing parameters. */ - ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const struct ALbuffer *ALBuffer, const ALCcontext *context); + ALvoid (*Update)(struct ALvoice *self, const struct ALsourceProps *props, const struct ALbuffer *ALBuffer, const ALCcontext *context); /** Current target parameters used for mixing. */ ALint Step; + ALboolean Looping; + /* If not 'moving', gain/coefficients are set directly without fading. */ ALboolean Moving; @@ -46,6 +49,59 @@ typedef struct ALvoice { } ALvoice; +struct ALsourceProps { + ATOMIC(ALfloat) Pitch; + ATOMIC(ALfloat) Gain; + ATOMIC(ALfloat) OuterGain; + ATOMIC(ALfloat) MinGain; + ATOMIC(ALfloat) MaxGain; + ATOMIC(ALfloat) InnerAngle; + ATOMIC(ALfloat) OuterAngle; + ATOMIC(ALfloat) RefDistance; + ATOMIC(ALfloat) MaxDistance; + ATOMIC(ALfloat) RollOffFactor; + ATOMIC(ALfloat) Position[3]; + ATOMIC(ALfloat) Velocity[3]; + ATOMIC(ALfloat) Direction[3]; + ATOMIC(ALfloat) Orientation[2][3]; + ATOMIC(ALboolean) HeadRelative; + ATOMIC(ALboolean) Looping; + ATOMIC(enum DistanceModel) DistanceModel; + ATOMIC(ALboolean) DirectChannels; + + ATOMIC(ALboolean) DryGainHFAuto; + ATOMIC(ALboolean) WetGainAuto; + ATOMIC(ALboolean) WetGainHFAuto; + ATOMIC(ALfloat) OuterGainHF; + + ATOMIC(ALfloat) AirAbsorptionFactor; + ATOMIC(ALfloat) RoomRolloffFactor; + ATOMIC(ALfloat) DopplerFactor; + + ATOMIC(ALfloat) StereoPan[2]; + + ATOMIC(ALfloat) Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ATOMIC(ALfloat) Gain; + ATOMIC(ALfloat) GainHF; + ATOMIC(ALfloat) HFReference; + ATOMIC(ALfloat) GainLF; + ATOMIC(ALfloat) LFReference; + } Direct; + struct { + ATOMIC(struct ALeffectslot*) Slot; + ATOMIC(ALfloat) Gain; + ATOMIC(ALfloat) GainHF; + ATOMIC(ALfloat) HFReference; + ATOMIC(ALfloat) GainLF; + ATOMIC(ALfloat) LFReference; + } Send[MAX_SENDS]; + + ATOMIC(struct ALsourceProps*) next; +}; + typedef struct ALsource { /** Source properties. */ volatile ALfloat Pitch; @@ -58,9 +114,9 @@ typedef struct ALsource { volatile ALfloat RefDistance; volatile ALfloat MaxDistance; volatile ALfloat RollOffFactor; - aluVector Position; - aluVector Velocity; - aluVector Direction; + volatile ALfloat Position[3]; + volatile ALfloat Velocity[3]; + volatile ALfloat Direction[3]; volatile ALfloat Orientation[2][3]; volatile ALboolean HeadRelative; volatile ALboolean Looping; @@ -83,6 +139,23 @@ typedef struct ALsource { volatile ALfloat Radius; + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct { + struct ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Send[MAX_SENDS]; + /** * Last user-specified offset, and the offset type (bytes, samples, or * seconds). @@ -114,25 +187,8 @@ typedef struct ALsource { ALuint NumChannels; ALuint SampleSize; - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct { - struct ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[MAX_SENDS]; - - /** Source needs to update its mixing parameters. */ - ATOMIC(ALenum) NeedsUpdate; + ATOMIC(struct ALsourceProps*) Update; + ATOMIC(struct ALsourceProps*) FreeList; /** Self ID */ ALuint id; @@ -152,6 +208,8 @@ inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) { return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } +void UpdateSourceProps(ALsource *source, ALuint num_sends); +void UpdateAllSourceProps(ALCcontext *context); 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 c20c6404..8e93dc6e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -34,6 +34,7 @@ extern "C" { #endif struct ALsource; +struct ALsourceProps; struct ALvoice; struct ALeffectslot; struct ALbuffer; @@ -375,8 +376,8 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, c ALvoid UpdateContextSources(ALCcontext *context); -ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext); -ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const struct ALbuffer *buffer, const ALCcontext *ALContext); +ALvoid CalcAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); +ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 98ee9328..6d1423db 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -202,6 +202,8 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); slot->AuxSendAuto = value; UpdateEffectSlotProps(slot, AL_FALSE); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + UpdateAllSourceProps(context); break; default: diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 1c40c399..c59d644b 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -51,7 +51,11 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -88,7 +92,11 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -140,7 +148,11 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -161,7 +173,11 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -190,7 +206,11 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -235,7 +255,11 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a62bf59e..e2d6ca4f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -48,6 +48,7 @@ extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static ALvoid InitSourceParams(ALsource *Source); +static ALvoid DeinitSource(ALsource *source); static ALint64 GetSourceSampleOffset(ALsource *Source); static ALdouble GetSourceSecOffset(ALsource *Source); static ALdouble GetSourceOffset(ALsource *Source, ALenum name); @@ -123,6 +124,12 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); +static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) +{ + return (source->state == AL_PLAYING || source->state == AL_PAUSED) && + !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); +} + static ALint FloatValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) @@ -376,8 +383,14 @@ static ALint Int64ValsByProp(ALenum prop) SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \ } while(0) +#define DO_UPDATEPROPS() do { \ + if(SourceShouldUpdate(Source, Context)) \ + UpdateSourceProps(Source, device->NumAuxSends); \ +} while(0) + static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) { + ALCdevice *device = Context->Device; ALint ival; switch(prop) @@ -393,98 +406,98 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p CHECKVAL(*values >= 0.0f); Source->Pitch = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_CONE_INNER_ANGLE: CHECKVAL(*values >= 0.0f && *values <= 360.0f); Source->InnerAngle = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_CONE_OUTER_ANGLE: CHECKVAL(*values >= 0.0f && *values <= 360.0f); Source->OuterAngle = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_GAIN: CHECKVAL(*values >= 0.0f); Source->Gain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_MAX_DISTANCE: CHECKVAL(*values >= 0.0f); Source->MaxDistance = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_ROLLOFF_FACTOR: CHECKVAL(*values >= 0.0f); Source->RollOffFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_REFERENCE_DISTANCE: CHECKVAL(*values >= 0.0f); Source->RefDistance = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_MIN_GAIN: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->MinGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_MAX_GAIN: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->MaxGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_CONE_OUTER_GAIN: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->OuterGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_CONE_OUTER_GAINHF: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->OuterGainHF = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_AIR_ABSORPTION_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 10.0f); Source->AirAbsorptionFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_ROOM_ROLLOFF_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 10.0f); Source->RoomRolloffFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_DOPPLER_FACTOR: CHECKVAL(*values >= 0.0f && *values <= 1.0f); Source->DopplerFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_SEC_OFFSET: @@ -492,13 +505,13 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BYTE_OFFSET: CHECKVAL(*values >= 0.0f); - LockContext(Context); Source->OffsetType = prop; Source->Offset = *values; if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - !Context->DeferUpdates) + !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { + LockContext(Context); WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { @@ -507,68 +520,64 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } WriteUnlock(&Source->queue_lock); + UnlockContext(Context); } - UnlockContext(Context); return AL_TRUE; case AL_SOURCE_RADIUS: CHECKVAL(*values >= 0.0f && isfinite(*values)); Source->Radius = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_STEREO_ANGLES: CHECKVAL(isfinite(values[0]) && isfinite(values[1])); - LockContext(Context); Source->StereoPan[0] = values[0]; Source->StereoPan[1] = values[1]; - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_POSITION: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - LockContext(Context); - aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f); - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + DO_UPDATEPROPS(); return AL_TRUE; case AL_VELOCITY: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - LockContext(Context); - aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f); - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + DO_UPDATEPROPS(); return AL_TRUE; case AL_DIRECTION: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); - LockContext(Context); - aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f); - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + Source->Direction[0] = values[0]; + Source->Direction[1] = values[1]; + Source->Direction[2] = values[2]; + DO_UPDATEPROPS(); return AL_TRUE; case AL_ORIENTATION: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])); - LockContext(Context); Source->Orientation[0][0] = values[0]; Source->Orientation[0][1] = values[1]; Source->Orientation[0][2] = values[2]; Source->Orientation[1][0] = values[3]; Source->Orientation[1][1] = values[4]; Source->Orientation[1][2] = values[5]; - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; @@ -626,13 +635,14 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->HeadRelative = (ALboolean)*values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_LOOPING: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->Looping = (ALboolean)*values; + DO_UPDATEPROPS(); return AL_TRUE; case AL_BUFFER: @@ -695,13 +705,13 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BYTE_OFFSET: CHECKVAL(*values >= 0); - LockContext(Context); Source->OffsetType = prop; Source->Offset = *values; if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - !Context->DeferUpdates) + !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { + LockContext(Context); WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { @@ -710,8 +720,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } WriteUnlock(&Source->queue_lock); + UnlockContext(Context); } - UnlockContext(Context); return AL_TRUE; case AL_DIRECT_FILTER: @@ -722,7 +732,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } - LockContext(Context); if(!filter) { Source->Direct.Gain = 1.0f; @@ -739,37 +748,36 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Direct.GainLF = filter->GainLF; Source->Direct.LFReference = filter->LFReference; } - UnlockContext(Context); UnlockFiltersRead(device); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_DIRECT_FILTER_GAINHF_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->DryGainHFAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->WetGainAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->WetGainHFAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_DIRECT_CHANNELS_SOFT: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); Source->DirectChannels = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_DISTANCE_MODEL: @@ -783,27 +791,20 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->DistanceModel = *values; if(Context->SourceDistanceModel) - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + DO_UPDATEPROPS(); return AL_TRUE; case AL_AUXILIARY_SEND_FILTER: LockFiltersRead(device); - LockContext(Context); if(!((ALuint)values[1] < device->NumAuxSends && (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) { - UnlockContext(Context); UnlockFiltersRead(device); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); - slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); - if(slot) DecrementRef(&slot->ref); - if(!filter) { /* Disable filter */ @@ -821,9 +822,28 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].GainLF = filter->GainLF; Source->Send[values[1]].LFReference = filter->LFReference; } - UnlockContext(Context); UnlockFiltersRead(device); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + + if(slot != Source->Send[values[1]].Slot && + (Source->state == AL_PLAYING || Source->state == AL_PAUSED)) + { + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(&slot->ref); + slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); + if(slot) DecrementRef(&slot->ref); + /* We must force an update if the auxiliary slot changed on a + * playing source, in case the slot is about to be deleted. + */ + UpdateSourceProps(Source, device->NumAuxSends); + } + else + { + if(slot) IncrementRef(&slot->ref); + slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); + if(slot) DecrementRef(&slot->ref); + DO_UPDATEPROPS(); + } + return AL_TRUE; @@ -1078,10 +1098,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_STEREO_ANGLES: - LockContext(Context); values[0] = Source->StereoPan[0]; values[1] = Source->StereoPan[1]; - UnlockContext(Context); return AL_TRUE; case AL_SEC_OFFSET_LATENCY_SOFT: @@ -1093,38 +1111,30 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_POSITION: - LockContext(Context); - values[0] = Source->Position.v[0]; - values[1] = Source->Position.v[1]; - values[2] = Source->Position.v[2]; - UnlockContext(Context); + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; return AL_TRUE; case AL_VELOCITY: - LockContext(Context); - values[0] = Source->Velocity.v[0]; - values[1] = Source->Velocity.v[1]; - values[2] = Source->Velocity.v[2]; - UnlockContext(Context); + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; return AL_TRUE; case AL_DIRECTION: - LockContext(Context); - values[0] = Source->Direction.v[0]; - values[1] = Source->Direction.v[1]; - values[2] = Source->Direction.v[2]; - UnlockContext(Context); + values[0] = Source->Direction[0]; + values[1] = Source->Direction[1]; + values[2] = Source->Direction[2]; return AL_TRUE; case AL_ORIENTATION: - LockContext(Context); values[0] = Source->Orientation[0][0]; values[1] = Source->Orientation[0][1]; values[2] = Source->Orientation[0][2]; values[3] = Source->Orientation[1][0]; values[4] = Source->Orientation[1][1]; values[5] = Source->Orientation[1][2]; - UnlockContext(Context); return AL_TRUE; /* 1x int */ @@ -1522,9 +1532,8 @@ done: AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) { ALCcontext *context; - ALbufferlistitem *BufferList; ALsource *Source; - ALsizei i, j; + ALsizei i; context = GetContextRef(); if(!context) return; @@ -1559,22 +1568,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) } UnlockContext(context); - BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL); - while(BufferList != NULL) - { - ALbufferlistitem *next = BufferList->next; - if(BufferList->buffer != NULL) - DecrementRef(&BufferList->buffer->ref); - free(BufferList); - 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; - } + DeinitSource(Source); memset(Source, 0, sizeof(*Source)); al_free(Source); @@ -1612,6 +1606,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1620,6 +1615,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) else SetSourcefv(Source, Context, param, &value); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1632,6 +1628,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1643,6 +1640,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 SetSourcefv(Source, Context, param, fvals); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1655,6 +1653,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1665,6 +1664,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat else SetSourcefv(Source, Context, param, values); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1678,6 +1678,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1689,6 +1690,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va SetSourcefv(Source, Context, param, &fval); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1701,6 +1703,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1712,6 +1715,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v SetSourcefv(Source, Context, param, fvals); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1725,6 +1729,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1742,6 +1747,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo SetSourcefv(Source, Context, param, fvals); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1755,6 +1761,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1763,6 +1770,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) else SetSourceiv(Source, Context, param, &value); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1775,6 +1783,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1786,6 +1795,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL SetSourceiv(Source, Context, param, ivals); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1798,6 +1808,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1808,6 +1819,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val else SetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1821,6 +1833,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1829,6 +1842,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO else SetSourcei64v(Source, Context, param, &value); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1841,6 +1855,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1852,6 +1867,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF SetSourcei64v(Source, Context, param, i64vals); } UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1864,6 +1880,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin Context = GetContextRef(); if(!Context) return; + WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1874,6 +1891,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin else SetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); + WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1887,6 +1905,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1901,6 +1920,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val *value = (ALfloat)dval; } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1914,6 +1934,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1932,6 +1953,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va } } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1946,6 +1968,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1964,6 +1987,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va } } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1977,6 +2001,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -1987,6 +2012,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * else GetSourcedv(Source, Context, param, value); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1999,6 +2025,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2017,6 +2044,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble } } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2029,6 +2057,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2039,6 +2068,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble else GetSourcedv(Source, Context, param, values); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2052,6 +2082,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2062,6 +2093,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value else GetSourceiv(Source, Context, param, value); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2075,6 +2107,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2093,6 +2126,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 } } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2106,6 +2140,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2116,6 +2151,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values else GetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2129,6 +2165,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2139,6 +2176,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S else GetSourcei64v(Source, Context, param, value); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2151,6 +2189,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2169,6 +2208,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 } } UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2181,6 +2221,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; + ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME); @@ -2191,6 +2232,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 else GetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); + ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2241,8 +2283,10 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) 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); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + source->new_state = AL_PLAYING; + else + SetSourceState(source, context, AL_PLAYING); } UnlockContext(context); @@ -2277,8 +2321,10 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) 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); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + source->new_state = AL_PAUSED; + else + SetSourceState(source, context, AL_PAUSED); } UnlockContext(context); @@ -2594,9 +2640,15 @@ static ALvoid InitSourceParams(ALsource *Source) Source->InnerAngle = 360.0f; Source->OuterAngle = 360.0f; Source->Pitch = 1.0f; - aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f); - aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f); - aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f); + Source->Position[0] = 0.0f; + Source->Position[1] = 0.0f; + Source->Position[2] = 0.0f; + Source->Velocity[0] = 0.0f; + Source->Velocity[1] = 0.0f; + Source->Velocity[2] = 0.0f; + Source->Direction[0] = 0.0f; + Source->Direction[1] = 0.0f; + Source->Direction[2] = 0.0f; Source->Orientation[0][0] = 0.0f; Source->Orientation[0][1] = 0.0f; Source->Orientation[0][2] = -1.0f; @@ -2628,15 +2680,6 @@ static ALvoid InitSourceParams(ALsource *Source) Source->DistanceModel = DefaultDistanceModel; - Source->state = AL_INITIAL; - Source->new_state = AL_NONE; - Source->SourceType = AL_UNDETERMINED; - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - - ATOMIC_INIT(&Source->queue, NULL); - ATOMIC_INIT(&Source->current_buffer, NULL); - Source->Direct.Gain = 1.0f; Source->Direct.GainHF = 1.0f; Source->Direct.HFReference = LOWPASSFREQREF; @@ -2651,7 +2694,170 @@ static ALvoid InitSourceParams(ALsource *Source) Source->Send[i].LFReference = HIGHPASSFREQREF; } - ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE); + Source->state = AL_INITIAL; + Source->new_state = AL_NONE; + Source->SourceType = AL_UNDETERMINED; + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + + ATOMIC_INIT(&Source->queue, NULL); + ATOMIC_INIT(&Source->current_buffer, NULL); + + ATOMIC_INIT(&Source->Update, NULL); + ATOMIC_INIT(&Source->FreeList, NULL); +} + +static ALvoid DeinitSource(ALsource *source) +{ + ALbufferlistitem *BufferList; + struct ALsourceProps *props; + size_t count = 0; + size_t i; + + props = ATOMIC_LOAD(&source->Update); + if(props) al_free(props); + + props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed); + while(props) + { + struct ALsourceProps *next; + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + al_free(props); + props = next; + ++count; + } + /* This is excessively spammy if it traces every source destruction, so + * just warn if it was unexpectedly large. + */ + if(count > 3) + WARN("Freed "SZFMT" Source property objects\n", count); + + BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL); + while(BufferList != NULL) + { + ALbufferlistitem *next = BufferList->next; + if(BufferList->buffer != NULL) + DecrementRef(&BufferList->buffer->ref); + free(BufferList); + BufferList = next; + } + + for(i = 0;i < MAX_SENDS;++i) + { + if(source->Send[i].Slot) + DecrementRef(&source->Send[i].Slot->ref); + source->Send[i].Slot = NULL; + } +} + +void UpdateSourceProps(ALsource *source, ALuint num_sends) +{ + struct ALsourceProps *props; + size_t i; + + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); + if(!props) + props = al_calloc(16, sizeof(*props)); + else + { + struct ALsourceProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, + &source->FreeList, &props, next, almemory_order_seq_cst, + almemory_order_consume) == 0); + } + + /* Copy in current property values. */ + ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed); + ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed); + ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed); + ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed); + ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed); + ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed); + ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed); + ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed); + ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed); + ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed); + for(i = 0;i < 3;i++) + ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed); + for(i = 0;i < 3;i++) + ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed); + for(i = 0;i < 3;i++) + ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed); + for(i = 0;i < 2;i++) + { + size_t j; + for(j = 0;j < 3;j++) + ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j], + almemory_order_relaxed); + } + ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); + ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed); + ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed); + ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed); + + ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed); + ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed); + ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed); + ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed); + + ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed); + ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed); + ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed); + + ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed); + ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed); + + ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed); + + ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed); + ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed); + ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed); + ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed); + ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed); + + for(i = 0;i < num_sends;i++) + { + ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed); + ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed); + ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed); + ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference, + almemory_order_relaxed); + ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed); + ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference, + almemory_order_relaxed); + } + + /* Set the new container for updating internal parameters. */ + props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel); + if(props) + { + /* If there was an unused update container, put it back in the + * freelist. + */ + struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, + &source->FreeList, &first, props) == 0); + } +} + +void UpdateAllSourceProps(ALCcontext *context) +{ + ALuint num_sends = context->Device->NumAuxSends; + ALsizei pos; + for(pos = 0;pos < context->VoiceCount;pos++) + { + ALvoice *voice = &context->Voices[pos]; + ALsource *source = voice->Source; + if(source != NULL && (source->state == AL_PLAYING || + source->state == AL_PAUSED)) + UpdateSourceProps(source, num_sends); + } + } @@ -2749,11 +2955,10 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } if(BufferList->buffer->FmtChannels == FmtMono) - voice->Update = CalcSourceParams; + voice->Update = CalcAttnSourceParams; else voice->Update = CalcNonAttnSourceParams; - - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + UpdateSourceProps(Source, device->NumAuxSends); } else if(state == AL_PAUSED) { @@ -3084,30 +3289,13 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) */ ALvoid ReleaseALSources(ALCcontext *Context) { - ALbufferlistitem *item; ALsizei pos; - ALuint j; for(pos = 0;pos < Context->SourceMap.size;pos++) { ALsource *temp = Context->SourceMap.array[pos].value; Context->SourceMap.array[pos].value = NULL; - item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL); - while(item != NULL) - { - ALbufferlistitem *next = item->next; - if(item->buffer != NULL) - DecrementRef(&item->buffer->ref); - free(item); - item = next; - } - - for(j = 0;j < MAX_SENDS;++j) - { - if(temp->Send[j].Slot) - DecrementRef(&temp->Send[j].Slot->ref); - temp->Send[j].Slot = NULL; - } + DeinitSource(temp); FreeThunkEntry(temp->id); memset(temp, 0, sizeof(*temp)); diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index c0c2ca82..e8a8d391 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -62,7 +62,11 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -86,7 +90,11 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } done: WriteUnlock(&context->PropLock); @@ -148,7 +156,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = context->DeferUpdates; + value = ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); break; default: @@ -188,7 +196,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALdouble)context->DeferUpdates; + value = (ALdouble)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); break; default: @@ -228,7 +236,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALfloat)context->DeferUpdates; + value = (ALfloat)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); break; default: @@ -268,7 +276,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALint)context->DeferUpdates; + value = (ALint)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); break; default: @@ -308,7 +316,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALint64SOFT)context->DeferUpdates; + value = (ALint64SOFT)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); break; default: @@ -554,7 +562,11 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) WriteLock(&context->PropLock); context->DopplerFactor = value; - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } WriteUnlock(&context->PropLock); done: @@ -573,7 +585,11 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) WriteLock(&context->PropLock); context->DopplerVelocity = value; - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } WriteUnlock(&context->PropLock); done: @@ -592,7 +608,11 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) WriteLock(&context->PropLock); context->SpeedOfSound = value; - UpdateListenerProps(context); + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } WriteUnlock(&context->PropLock); done: @@ -615,7 +635,13 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) WriteLock(&context->PropLock); context->DistanceModel = value; if(!context->SourceDistanceModel) - UpdateListenerProps(context); + { + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + { + UpdateListenerProps(context); + UpdateAllSourceProps(context); + } + } WriteUnlock(&context->PropLock); done: -- cgit v1.2.3 From 576c1116a65bd66effce6d92d1aa7e21d1dee83a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 May 2016 01:19:05 -0700 Subject: Avoid using a flag to specify if the effect state needs to be updated This fixes a potential missed state change if an update with a new state got replaced with one that doesn't. --- Alc/ALc.c | 4 ++-- Alc/ALu.c | 12 ++++++++---- OpenAL32/Include/alAuxEffectSlot.h | 4 +--- OpenAL32/alAuxEffectSlot.c | 19 +++++++++---------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e5c18d8c..dfbb6c63 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2052,7 +2052,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - UpdateEffectSlotProps(slot, AL_FALSE); + UpdateEffectSlotProps(slot); } context = ATOMIC_LOAD(&device->ContextList); @@ -2077,7 +2077,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - UpdateEffectSlotProps(slot, AL_FALSE); + UpdateEffectSlotProps(slot); } UnlockUIntMapRead(&context->EffectSlotMap); diff --git a/Alc/ALu.c b/Alc/ALu.c index 2fffdcd9..329d01eb 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -336,6 +336,7 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) { struct ALeffectslotProps *first; struct ALeffectslotProps *props; + ALeffectState *state; props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); if(!props) return; @@ -355,13 +356,16 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; } + state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); + /* If the state object is changed, exchange it with the current one so it * remains in the freelist and isn't leaked. */ - if(ATOMIC_LOAD(&props->UpdateState, almemory_order_relaxed)) - slot->Params.EffectState = ATOMIC_EXCHANGE(ALeffectState*, - &props->State, slot->Params.EffectState, almemory_order_relaxed - ); + if(state != slot->Params.EffectState) + { + ATOMIC_STORE(&props->State, slot->Params.EffectState, almemory_order_relaxed); + slot->Params.EffectState = state; + } V(slot->Params.EffectState,update)(device, slot, &props->Props); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 28c0b46f..85d730f8 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -79,8 +79,6 @@ struct ALeffectslotProps { ATOMIC(ALenum) Type; ALeffectProps Props; - /* Flag indicates if State should be updated. */ - ATOMIC(ALboolean) UpdateState; ATOMIC(ALeffectState*) State; ATOMIC(struct ALeffectslotProps*) next; @@ -140,7 +138,7 @@ inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); -void UpdateEffectSlotProps(ALeffectslot *slot, ALboolean withstate); +void UpdateEffectSlotProps(ALeffectslot *slot); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 6d1423db..0dd6a53f 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -201,7 +201,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!(value == AL_TRUE || value == AL_FALSE)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); slot->AuxSendAuto = value; - UpdateEffectSlotProps(slot, AL_FALSE); + UpdateEffectSlotProps(slot); if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) UpdateAllSourceProps(context); break; @@ -264,7 +264,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateEffectSlotProps(slot, AL_FALSE); + UpdateEffectSlotProps(slot); done: WriteUnlock(&context->PropLock); @@ -502,12 +502,12 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e } EffectSlot->Effect.State = State; - UpdateEffectSlotProps(EffectSlot, AL_TRUE); + UpdateEffectSlotProps(EffectSlot); } else if(effect) { memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); - UpdateEffectSlotProps(EffectSlot, AL_FALSE); + UpdateEffectSlotProps(EffectSlot); } return AL_NO_ERROR; @@ -556,7 +556,8 @@ void DeinitEffectSlot(ALeffectslot *slot) { ALeffectState *state; state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); - DELETE_OBJ(state); + if(state != slot->Params.EffectState) + DELETE_OBJ(state); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } @@ -577,7 +578,7 @@ void DeinitEffectSlot(ALeffectslot *slot) DELETE_OBJ(slot->Params.EffectState); } -void UpdateEffectSlotProps(ALeffectslot *slot, ALboolean withstate) +void UpdateEffectSlotProps(ALeffectslot *slot) { struct ALeffectslotProps *props; ALeffectState *oldstate; @@ -605,10 +606,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALboolean withstate) /* Swap out any stale effect state object there may be in the container, to * delete it. */ - ATOMIC_STORE(&props->UpdateState, withstate, almemory_order_relaxed); - oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, - withstate ? slot->Effect.State : NULL, almemory_order_relaxed - ); + oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, + almemory_order_relaxed); /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props, -- cgit v1.2.3 From c522658d19f7e82748400731bddb4633847c2a40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 May 2016 13:44:32 -0700 Subject: Avoid duplicate effect state objects in the freelist If an unapplied update was superceded, it would be placed in the freelist with its effect state object intact. This would cause another update with the same effect state object to be placed into the freelist as well, or worse, cause it to get deleted while in use when the container had its effect state cleared. --- OpenAL32/alAuxEffectSlot.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 0dd6a53f..9cc86563 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -549,12 +549,12 @@ ALenum InitEffectSlot(ALeffectslot *slot) void DeinitEffectSlot(ALeffectslot *slot) { struct ALeffectslotProps *props; + ALeffectState *state; size_t count = 0; props = ATOMIC_LOAD(&slot->Update); if(props) { - ALeffectState *state; state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); if(state != slot->Params.EffectState) DELETE_OBJ(state); @@ -565,7 +565,6 @@ void DeinitEffectSlot(ALeffectslot *slot) while(props) { struct ALeffectslotProps *next; - ALeffectState *state; state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); DELETE_OBJ(state); @@ -583,18 +582,32 @@ void UpdateEffectSlotProps(ALeffectslot *slot) struct ALeffectslotProps *props; ALeffectState *oldstate; - /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&slot->FreeList, almemory_order_acquire); - if(!props) - props = al_calloc(16, sizeof(*props)); + props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL); + if(props) + { + /* If there was an unapplied update, check if its state object is the + * same as the current in-use one, or the one that will be set. If + * neither, delete it. + */ + oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); + if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State) + DELETE_OBJ(oldstate); + } else { - struct ALeffectslotProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, - &slot->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_consume) == 0); + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); + if(!props) + props = al_calloc(16, sizeof(*props)); + else + { + struct ALeffectslotProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + &slot->FreeList, &props, next, almemory_order_seq_cst, + almemory_order_consume) == 0); + } } /* Copy in current property values. */ -- cgit v1.2.3 From 63e98481eef0eb02dac14b889be80836a300eecc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 May 2016 14:12:56 -0700 Subject: Allocate context storage before starting/resetting the device In case allocation fails, we don't have to worry about the playing status of the backend. --- Alc/ALc.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dfbb6c63..0019de9e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3078,20 +3078,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ATOMIC_STORE(&device->LastError, ALC_NO_ERROR); - if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) - { - UnlockLists(); - alcSetError(device, err); - if(err == ALC_INVALID_DEVICE) - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device); - V0(device->Backend,unlock)(); - } - ALCdevice_DecRef(device); - return NULL; - } - ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)); if(ALContext) { @@ -3106,11 +3092,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } if(!ALContext || !ALContext->Voices) { - if(!ATOMIC_LOAD(&device->ContextList)) - { - V0(device->Backend,stop)(); - device->Flags &= ~DEVICE_RUNNING; - } UnlockLists(); if(ALContext) @@ -3129,6 +3110,29 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin return NULL; } + if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) + { + UnlockLists(); + + al_free(ALContext->Voices); + ALContext->Voices = NULL; + + VECTOR_DEINIT(ALContext->ActiveAuxSlots); + + al_free(ALContext); + ALContext = NULL; + + alcSetError(device, err); + if(err == ALC_INVALID_DEVICE) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device); + V0(device->Backend,unlock)(); + } + ALCdevice_DecRef(device); + return NULL; + } + ALContext->Device = device; ALCdevice_IncRef(device); InitContext(ALContext); -- cgit v1.2.3 From 945fd022d6c9d612a5fae944d8cbef68927d8a92 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 May 2016 17:14:58 -0700 Subject: Avoid separate updates to sources that should apply together --- Alc/ALc.c | 2 ++ Alc/ALu.c | 29 +++++++++++++++++------------ OpenAL32/Include/alMain.h | 6 ++++++ OpenAL32/Include/alu.h | 2 -- OpenAL32/alSource.c | 13 ++++++++++++- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0019de9e..86b8e59e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2266,6 +2266,8 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&listener->FreeList, NULL); //Validate Context + InitRef(&Context->UpdateCount, 0); + ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); RWLockInit(&Context->PropLock); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); diff --git a/Alc/ALu.c b/Alc/ALu.c index 329d01eb..34c36d5b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1339,26 +1339,31 @@ ALvoid CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, c } -void UpdateContextSources(ALCcontext *ctx) +static void UpdateContextSources(ALCcontext *ctx) { ALvoice *voice, *voice_end; ALsource *source; - CalcListenerParams(ctx); + IncrementRef(&ctx->UpdateCount); + if(!ATOMIC_LOAD(&ctx->HoldUpdates)) + { + CalcListenerParams(ctx); #define UPDATE_SLOT(iter) CalcEffectSlotParams(*iter, ctx->Device) - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); #undef UPDATE_SLOT - voice = ctx->Voices; - voice_end = voice + ctx->VoiceCount; - for(;voice != voice_end;++voice) - { - if(!(source=voice->Source)) continue; - if(source->state != AL_PLAYING && source->state != AL_PAUSED) - voice->Source = NULL; - else - CalcSourceParams(voice, ctx); + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) + { + if(!(source=voice->Source)) continue; + if(source->state != AL_PLAYING && source->state != AL_PAUSED) + voice->Source = NULL; + else + CalcSourceParams(voice, ctx); + } } + IncrementRef(&ctx->UpdateCount); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a624e078..f709e9bd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -699,6 +699,12 @@ struct ALCcontext_struct { RWLock PropLock; + /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit + * indicates if updates are currently happening). + */ + RefCount UpdateCount; + ATOMIC(ALenum) HoldUpdates; + struct ALvoice *Voices; ALsizei VoiceCount; ALsizei MaxVoices; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8e93dc6e..fc58bfb1 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -374,8 +374,6 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -ALvoid UpdateContextSources(ALCcontext *context); - ALvoid CalcAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e2d6ca4f..1124c9c3 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2848,7 +2848,15 @@ void UpdateSourceProps(ALsource *source, ALuint num_sends) void UpdateAllSourceProps(ALCcontext *context) { ALuint num_sends = context->Device->NumAuxSends; + uint updates; ALsizei pos; + + /* Tell the mixer to stop applying updates, then wait for any active + * updating to finish, before providing source updates. + */ + ATOMIC_STORE(&context->HoldUpdates, AL_TRUE); + while(((updates=ReadRef(&context->UpdateCount))&1) != 0) + althrd_yield(); for(pos = 0;pos < context->VoiceCount;pos++) { ALvoice *voice = &context->Voices[pos]; @@ -2857,7 +2865,10 @@ void UpdateAllSourceProps(ALCcontext *context) source->state == AL_PAUSED)) UpdateSourceProps(source, num_sends); } - + /* Now with all updates declared, let the mixer continue applying them so + * they all happen at once. + */ + ATOMIC_STORE(&context->HoldUpdates, AL_FALSE); } -- cgit v1.2.3 From 56c6b3f56cfd300ce62b6dc932a241ac619cb086 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 May 2016 14:46:06 -0700 Subject: Don't store the source's update method with the voice --- Alc/ALu.c | 80 ++++++++++++++++++++++++--------------------- OpenAL32/Include/alSource.h | 3 -- OpenAL32/Include/alu.h | 3 -- OpenAL32/alSource.c | 4 --- 4 files changed, 42 insertions(+), 48 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 34c36d5b..4fb9d8e5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -129,7 +129,7 @@ static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; } -static inline ALfloat aluNormalize(ALfloat *vec) +static ALfloat aluNormalize(ALfloat *vec) { ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); if(length > 0.0f) @@ -163,7 +163,7 @@ static inline ALdouble aluNormalized(ALdouble *vec) return length; } -static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx) +static void aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx) { ALdouble v[4] = { vec[0], vec[1], vec[2], w }; @@ -181,7 +181,7 @@ static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatri vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; } -static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec) +static aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec) { aluVector v; v.v[0] = (ALfloat)(vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]); @@ -381,41 +381,8 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) &slot->FreeList, &first, props) == 0); } -static void CalcSourceParams(ALvoice *voice, ALCcontext *context) -{ - ALsource *source = voice->Source; - ALbufferlistitem *BufferListItem; - struct ALsourceProps *first; - struct ALsourceProps *props; - - props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); - if(!props) return; - BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); - while(BufferListItem != NULL) - { - ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - voice->Update(voice, props, buffer, context); - break; - } - BufferListItem = BufferListItem->next; - } - - /* WARNING: A livelock is theoretically possible if another thread keeps - * changing the freelist head without giving this a chance to actually swap - * in the old container (practically impossible with this little code, - * but...). - */ - first = ATOMIC_LOAD(&source->FreeList); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props) == 0); -} - -ALvoid CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } @@ -859,7 +826,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props } } -ALvoid CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; @@ -1338,6 +1305,43 @@ ALvoid CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, c } } +static void CalcSourceParams(ALvoice *voice, ALCcontext *context) +{ + ALsource *source = voice->Source; + ALbufferlistitem *BufferListItem; + struct ALsourceProps *first; + struct ALsourceProps *props; + + props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); + if(!props) return; + + BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + while(BufferListItem != NULL) + { + ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + if(buffer->FmtChannels == FmtMono) + CalcAttnSourceParams(voice, props, buffer, context); + else + CalcNonAttnSourceParams(voice, props, buffer, context); + break; + } + BufferListItem = BufferListItem->next; + } + + /* WARNING: A livelock is theoretically possible if another thread keeps + * changing the freelist head without giving this a chance to actually swap + * in the old container (practically impossible with this little code, + * but...). + */ + first = ATOMIC_LOAD(&source->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, + &source->FreeList, &first, props) == 0); +} + static void UpdateContextSources(ALCcontext *ctx) { diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 6d915153..4a15cea1 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -25,9 +25,6 @@ typedef struct ALbufferlistitem { typedef struct ALvoice { struct ALsource *volatile Source; - /** Method to update mixing parameters. */ - ALvoid (*Update)(struct ALvoice *self, const struct ALsourceProps *props, const struct ALbuffer *ALBuffer, const ALCcontext *context); - /** Current target parameters used for mixing. */ ALint Step; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index fc58bfb1..c70c8cff 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -374,9 +374,6 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -ALvoid CalcAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); -ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsourceProps *props, const struct ALbuffer *buffer, const ALCcontext *ALContext); - ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo); ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1124c9c3..090b4659 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2965,10 +2965,6 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } - if(BufferList->buffer->FmtChannels == FmtMono) - voice->Update = CalcAttnSourceParams; - else - voice->Update = CalcNonAttnSourceParams; UpdateSourceProps(Source, device->NumAuxSends); } else if(state == AL_PAUSED) -- cgit v1.2.3 From aea7c85daab8d0907f11293690cd47af7adece03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 May 2016 18:28:46 -0700 Subject: Use floats for the listener transforms --- Alc/ALc.c | 10 +++--- Alc/ALu.c | 84 ++++++++++++------------------------------- OpenAL32/Include/alListener.h | 2 +- OpenAL32/Include/alu.h | 25 ------------- 4 files changed, 29 insertions(+), 92 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 86b8e59e..fa9f50d9 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2250,11 +2250,11 @@ static ALvoid InitContext(ALCcontext *Context) listener->Up[1] = 1.0f; listener->Up[2] = 0.0f; - aluMatrixdSet(&listener->Params.Matrix, - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 + aluMatrixfSet(&listener->Params.Matrix, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); listener->Params.Gain = 1.0f; diff --git a/Alc/ALu.c b/Alc/ALu.c index 4fb9d8e5..8594afb8 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -93,14 +93,6 @@ extern inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); -extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row, - ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3); -extern inline void aluMatrixdSet(aluMatrixd *matrix, - ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03, - ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13, - ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23, - ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33); - static inline HrtfMixerFunc SelectHrtfMixer(void) { @@ -142,52 +134,22 @@ static ALfloat aluNormalize(ALfloat *vec) return length; } - -static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *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 ALdouble aluNormalized(ALdouble *vec) -{ - ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - if(length > 0.0) - { - ALdouble inv_length = 1.0/length; - vec[0] *= inv_length; - vec[1] *= inv_length; - vec[2] *= inv_length; - } - return length; -} - -static void aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx) -{ - ALdouble v[4] = { vec[0], vec[1], vec[2], w }; - - vec[0] = (ALfloat)(v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]); - vec[1] = (ALfloat)(v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]); - vec[2] = (ALfloat)(v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]); -} - -static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx) +static void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) { - ALdouble v[4] = { vec[0], vec[1], vec[2], w }; + ALfloat v[4] = { vec[0], vec[1], vec[2], w }; vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; } -static aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec) +static aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec) { aluVector v; - v.v[0] = (ALfloat)(vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]); - v.v[1] = (ALfloat)(vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]); - v.v[2] = (ALfloat)(vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]); - v.v[3] = (ALfloat)(vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]); + v.v[0] = vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]; + v.v[1] = vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]; + v.v[2] = vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]; + v.v[3] = vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]; return v; } @@ -269,7 +231,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) static void CalcListenerParams(ALCcontext *Context) { ALlistener *Listener = Context->Listener; - ALdouble N[3], V[3], U[3], P[3]; + ALfloat N[3], V[3], U[3], P[3]; struct ALlistenerProps *first; struct ALlistenerProps *props; aluVector vel; @@ -281,16 +243,16 @@ static void CalcListenerParams(ALCcontext *Context) N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed); N[1] = ATOMIC_LOAD(&props->Forward[1], almemory_order_relaxed); N[2] = ATOMIC_LOAD(&props->Forward[2], almemory_order_relaxed); - aluNormalized(N); + aluNormalize(N); V[0] = ATOMIC_LOAD(&props->Up[0], almemory_order_relaxed); V[1] = ATOMIC_LOAD(&props->Up[1], almemory_order_relaxed); V[2] = ATOMIC_LOAD(&props->Up[2], almemory_order_relaxed); - aluNormalized(V); + aluNormalize(V); /* Build and normalize right-vector */ - aluCrossproductd(N, V, U); - aluNormalized(U); + aluCrossproduct(N, V, U); + aluNormalize(U); - aluMatrixdSet(&Listener->Params.Matrix, + aluMatrixfSet(&Listener->Params.Matrix, U[0], V[0], -N[0], 0.0, U[1], V[1], -N[1], 0.0, U[2], V[2], -N[2], 0.0, @@ -300,14 +262,14 @@ static void CalcListenerParams(ALCcontext *Context) P[0] = ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed); P[1] = ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed); P[2] = ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed); - aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix); - aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); + aluMatrixfFloat3(P, 1.0, &Listener->Params.Matrix); + aluMatrixfSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); aluVectorSet(&vel, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed), ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed), ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed), 0.0f); - Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &vel); + Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); Listener->Params.MetersPerUnit = ATOMIC_LOAD(&props->MetersPerUnit, almemory_order_relaxed); @@ -568,9 +530,9 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * aluNormalize(V); if(!Relative) { - const aluMatrixd *lmatrix = &Listener->Params.Matrix; - aluMatrixdFloat3(N, 0.0f, lmatrix); - aluMatrixdFloat3(V, 0.0f, lmatrix); + const aluMatrixf *lmatrix = &Listener->Params.Matrix; + aluMatrixfFloat3(N, 0.0f, lmatrix); + aluMatrixfFloat3(V, 0.0f, lmatrix); } /* Build and normalize right-vector */ aluCrossproduct(N, V, U); @@ -951,11 +913,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Transform source to listener space (convert to head relative) */ if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE) { - const aluMatrixd *Matrix = &Listener->Params.Matrix; + const aluMatrixf *Matrix = &Listener->Params.Matrix; /* Transform source vectors */ - Position = aluMatrixdVector(Matrix, &Position); - Velocity = aluMatrixdVector(Matrix, &Velocity); - Direction = aluMatrixdVector(Matrix, &Direction); + Position = aluMatrixfVector(Matrix, &Position); + Velocity = aluMatrixfVector(Matrix, &Velocity); + Direction = aluMatrixfVector(Matrix, &Direction); } else { diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index dee66720..3008f7bc 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -44,7 +44,7 @@ typedef struct ALlistener { ATOMIC(struct ALlistenerProps*) FreeList; struct { - aluMatrixd Matrix; + aluMatrixf Matrix; aluVector Velocity; ALfloat Gain; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c70c8cff..eb8fb65e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -101,31 +101,6 @@ inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat } -typedef union aluMatrixd { - alignas(16) ALdouble m[4][4]; -} aluMatrixd; - -inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row, - ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3) -{ - matrix->m[row][0] = m0; - matrix->m[row][1] = m1; - matrix->m[row][2] = m2; - matrix->m[row][3] = m3; -} - -inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03, - ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13, - ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23, - ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33) -{ - aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03); - aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13); - aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23); - aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33); -} - - enum ActiveFilters { AF_None = 0, AF_LowPass = 1, -- cgit v1.2.3 From 51e4aa7fc6399cd9eb5864e17ef1a9d49c8b4b24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 May 2016 22:42:41 -0700 Subject: Ignore the listening angle for the wet path sound cones Since the wet path is essentially the room response to a sound, the direction of the sound to the listener doesn't change the amount of energy the room receives. Instead, the surface area defined by the cones dictate the volume the room gets for the sound. --- Alc/ALu.c | 83 +++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8594afb8..4c7000d7 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -793,9 +793,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; aluVector Position, Velocity, Direction, SourceToListener; - ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; + ALfloat InnerAngle,OuterAngle,Distance,ClampedDist; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; - ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; + ALfloat SourceVolume,ListenerGain; ALfloat DopplerFactor, SpeedOfSound; ALfloat AirAbsorptionFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; @@ -1033,38 +1033,57 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } /* Calculate directional soundcones */ - Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; - if(Angle > InnerAngle && Angle <= OuterAngle) + if(InnerAngle < 360.0f) { - ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); - ConeVolume = lerp(1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), - scale); - ConeHF = lerp(1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), - scale); - } - else if(Angle > OuterAngle) - { - ConeVolume = ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed); - ConeHF = ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed); - } - else - { - ConeVolume = 1.0f; - ConeHF = 1.0f; - } + ALfloat ConeVolume; + ALfloat ConeHF; + ALfloat Angle; + ALfloat scale; - DryGain *= ConeVolume; - if(WetGainAuto) - { - for(i = 0;i < NumSends;i++) - WetGain[i] *= ConeVolume; - } - if(DryGainHFAuto) - DryGainHF *= ConeHF; - if(WetGainHFAuto) - { - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= ConeHF; + Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; + if(Angle > InnerAngle) + { + if(Angle < OuterAngle) + { + scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); + ConeVolume = lerp( + 1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), scale + ); + ConeHF = lerp( + 1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), scale + ); + } + else + { + ConeVolume = ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed); + ConeHF = ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed); + } + DryGain *= ConeVolume; + if(DryGainHFAuto) + DryGainHF *= ConeHF; + } + + /* Wet path uses the total area of the cone emitter (the room will + * receive the same amount of sound regardless of its direction). + */ + scale = (asinf(maxf((OuterAngle-InnerAngle)/360.0f, 0.0f)) / F_PI) + + (InnerAngle/360.0f); + if(WetGainAuto) + { + ConeVolume = lerp( + 1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), scale + ); + for(i = 0;i < NumSends;i++) + WetGain[i] *= ConeVolume; + } + if(WetGainHFAuto) + { + ConeHF = lerp( + 1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), scale + ); + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= ConeHF; + } } /* Clamp to Min/Max Gain */ -- cgit v1.2.3 From 2172f974e70d12ee70d088620a49fd2614668f8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 May 2016 14:28:30 -0700 Subject: Improve reverb panning gains for "3D" output. --- Alc/effects/reverb.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 916469a8..f9c19325 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -826,11 +826,11 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection ALfloat length; ALuint i; - /* 0.5 would be the gain scaling when the panning vector is 0. This also - * equals sqrt(1/4), a nice gain scaling for the four virtual points + /* sqrt(0.5) would be the gain scaling when the panning vector is 0. This + * also equals sqrt(2/4), a nice gain scaling for the four virtual points * producing an "ambient" response. */ - gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; + gain[0] = gain[1] = gain[2] = gain[3] = 0.707106781f; length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); if(length > 1.0f) { @@ -842,7 +842,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; + gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); } } else if(length > FLT_EPSILON) @@ -851,7 +851,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection { ALfloat dotp = ReflectionsPan[0]*PanDirs[i][0] + ReflectionsPan[1]*PanDirs[i][1] + -ReflectionsPan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; + gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); } } for(i = 0;i < 4;i++) @@ -861,7 +861,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection State->Early.PanGain[i]); } - gain[0] = gain[1] = gain[2] = gain[3] = 0.5f; + gain[0] = gain[1] = gain[2] = gain[3] = 0.707106781f; length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); if(length > 1.0f) { @@ -873,7 +873,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection for(i = 0;i < 4;i++) { ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; + gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); } } else if(length > FLT_EPSILON) @@ -882,7 +882,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection { ALfloat dotp = LateReverbPan[0]*PanDirs[i][0] + LateReverbPan[1]*PanDirs[i][1] + -LateReverbPan[2]*PanDirs[i][2]; - gain[i] = dotp*0.5f + 0.5f; + gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); } } for(i = 0;i < 4;i++) -- cgit v1.2.3 From 82720c47593a9d849b10d72a7d21451cc1b98d51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 May 2016 15:03:56 -0700 Subject: Don't assume the "real" output buffer follows the dry buffer --- Alc/effects/reverb.c | 59 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f9c19325..3f22b787 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -48,7 +48,10 @@ typedef struct ALreverbState { DERIVE_FROM_TYPE(ALeffectState); ALboolean IsEax; - ALuint ExtraChannels; // For HRTF + + // For HRTF and UHJ + ALfloat (*ExtraOut)[BUFFERSIZE]; + ALuint ExtraChannels; // All delay lines are allocated as a single buffer to reduce memory // fragmentation and management code. @@ -385,13 +388,17 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; - /* WARNING: This assumes the real output follows the virtual output in the - * device's DryBuffer. - */ + /* HRTF and UHJ will mix to the real output for ambient output. */ if(Device->Hrtf || Device->Uhj_Encoder) - State->ExtraChannels = ChannelsFromDevFmt(Device->FmtChans); + { + State->ExtraOut = Device->RealOut.Buffer; + State->ExtraChannels = Device->RealOut.NumChannels; + } else + { + State->ExtraOut = NULL; State->ExtraChannels = 0; + } // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the @@ -696,9 +703,6 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect /* With HRTF or UHJ, the normal output provides a panned reverb channel * when a non-0-length vector is specified, while the real stereo output * provides two other "direct" non-panned reverb channels. - * - * WARNING: This assumes the real output follows the virtual output in the - * device's DryBuffer. */ memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); @@ -710,8 +714,8 @@ static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *Reflect else { /* Note that EAX Reverb's panning vectors are using right-handed - * coordinates, rather that the OpenAL's left-handed coordinates. - * Negate Z to fix this. + * coordinates, rather than OpenAL's left-handed coordinates. Negate Z + * to fix this. */ ALfloat pan[3] = { ReflectionsPan[0] / length, @@ -773,10 +777,6 @@ static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *Reflec } else { - /* Note that EAX Reverb's panning vectors are using right-handed - * coordinates, rather that the OpenAL's left-handed coordinates. - * Negate Z to fix this. - */ ALfloat pan[3] = { ReflectionsPan[0] / length, ReflectionsPan[1] / length, @@ -1335,6 +1335,21 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples SamplesOut[c][index+i] += gain*late[i][l]; } } + for(c = 0;c < State->ExtraChannels;c++) + { + gain = State->Early.PanGain[l][NumChannels+c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + State->ExtraOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][NumChannels+c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + State->ExtraOut[c][index+i] += gain*late[i][l]; + } + } } index += todo; @@ -1372,6 +1387,21 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, SamplesOut[c][index+i] += gain*late[i][l]; } } + for(c = 0;c < State->ExtraChannels;c++) + { + gain = State->Early.PanGain[l][NumChannels+c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + State->ExtraOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][NumChannels+c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + State->ExtraOut[c][index+i] += gain*late[i][l]; + } + } } index += todo; @@ -1380,7 +1410,6 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - NumChannels += State->ExtraChannels; if(State->IsEax) ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); else -- cgit v1.2.3 From 82675c018dab303ce39665512f0ae847d01289da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 May 2016 18:23:41 -0700 Subject: Update the right effect state when the device is reset --- Alc/ALc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fa9f50d9..c61a58f3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2043,7 +2043,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->DefaultSlot) { ALeffectslot *slot = device->DefaultSlot; - ALeffectState *state = slot->Params.EffectState; + ALeffectState *state = slot->Effect.State; state->OutBuffer = device->Dry.Buffer; state->OutChannels = device->Dry.NumChannels; @@ -2065,7 +2065,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(pos = 0;pos < context->EffectSlotMap.size;pos++) { ALeffectslot *slot = context->EffectSlotMap.array[pos].value; - ALeffectState *state = slot->Params.EffectState; + ALeffectState *state = slot->Effect.State; state->OutBuffer = device->Dry.Buffer; state->OutChannels = device->Dry.NumChannels; -- cgit v1.2.3 From aff725cba3f64cb668acf64b8f547a128a8976d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 May 2016 20:02:46 -0700 Subject: Avoid redundantly storing distance model settings --- Alc/ALu.c | 8 +------- OpenAL32/Include/alListener.h | 6 ------ OpenAL32/Include/alSource.h | 2 +- OpenAL32/alListener.c | 4 ---- OpenAL32/alSource.c | 15 +++++++++------ OpenAL32/alState.c | 9 --------- 6 files changed, 11 insertions(+), 33 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 4c7000d7..8be22e66 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -278,10 +278,6 @@ static void CalcListenerParams(ALCcontext *Context) Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) * ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed); - Listener->Params.SourceDistanceModel = ATOMIC_LOAD(&props->SourceDistanceModel, - almemory_order_relaxed); - Listener->Params.DistanceModel = ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed); - /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap * in the old container (practically impossible with this little code, @@ -941,9 +937,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Attenuation = 1.0f; for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; - switch(Listener->Params.SourceDistanceModel ? - ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed) : - Listener->Params.DistanceModel) + switch(ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed)) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index 3008f7bc..a10d6728 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -20,9 +20,6 @@ struct ALlistenerProps { ATOMIC(ALfloat) DopplerVelocity; ATOMIC(ALfloat) SpeedOfSound; - ATOMIC(ALboolean) SourceDistanceModel; - ATOMIC(enum DistanceModel) DistanceModel; - ATOMIC(struct ALlistenerProps*) next; }; @@ -52,9 +49,6 @@ typedef struct ALlistener { ALfloat DopplerFactor; ALfloat SpeedOfSound; - - ALboolean SourceDistanceModel; - enum DistanceModel DistanceModel; } Params; } ALlistener; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 4a15cea1..fbd63ce2 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -205,7 +205,7 @@ inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) { return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } -void UpdateSourceProps(ALsource *source, ALuint num_sends); +void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context); void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index c59d644b..c7f4955a 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -514,10 +514,6 @@ void UpdateListenerProps(ALCcontext *context) ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed); ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed); - ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel, - almemory_order_relaxed); - ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed); - /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); if(props) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 090b4659..780e9061 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -385,7 +385,7 @@ static ALint Int64ValsByProp(ALenum prop) #define DO_UPDATEPROPS() do { \ if(SourceShouldUpdate(Source, Context)) \ - UpdateSourceProps(Source, device->NumAuxSends); \ + UpdateSourceProps(Source, device->NumAuxSends, Context); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -834,7 +834,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p /* We must force an update if the auxiliary slot changed on a * playing source, in case the slot is about to be deleted. */ - UpdateSourceProps(Source, device->NumAuxSends); + UpdateSourceProps(Source, device->NumAuxSends, Context); } else { @@ -2750,7 +2750,7 @@ static ALvoid DeinitSource(ALsource *source) } } -void UpdateSourceProps(ALsource *source, ALuint num_sends) +void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context) { struct ALsourceProps *props; size_t i; @@ -2795,7 +2795,10 @@ void UpdateSourceProps(ALsource *source, ALuint num_sends) } ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed); - ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed); + ATOMIC_STORE(&props->DistanceModel, + context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel, + almemory_order_relaxed + ); ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed); ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed); @@ -2863,7 +2866,7 @@ void UpdateAllSourceProps(ALCcontext *context) ALsource *source = voice->Source; if(source != NULL && (source->state == AL_PLAYING || source->state == AL_PAUSED)) - UpdateSourceProps(source, num_sends); + UpdateSourceProps(source, num_sends, context); } /* Now with all updates declared, let the mixer continue applying them so * they all happen at once. @@ -2965,7 +2968,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } - UpdateSourceProps(Source, device->NumAuxSends); + UpdateSourceProps(Source, device->NumAuxSends, Context); } else if(state == AL_PAUSED) { diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index e8a8d391..443ab884 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -63,10 +63,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { - UpdateListenerProps(context); UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -91,10 +88,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { - UpdateListenerProps(context); UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -637,10 +631,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) if(!context->SourceDistanceModel) { if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { - UpdateListenerProps(context); UpdateAllSourceProps(context); - } } WriteUnlock(&context->PropLock); -- cgit v1.2.3 From d80f00173f0ef623f69a9cc307457b198186ded8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 May 2016 12:15:19 -0700 Subject: Copy the source's Looping property into the voice --- Alc/ALu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8be22e66..44361979 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -437,6 +437,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->Send[i].OutChannels = SendSlots[i]->NumChannels; } } + voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); /* Calculate the stepping value */ Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; @@ -905,6 +906,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro voice->Send[i].OutChannels = SendSlots[i]->NumChannels; } } + voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); /* Transform source to listener space (convert to head relative) */ if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE) -- cgit v1.2.3 From 7bf64eaee0788b7eb64c7410384a9ee66f75c4ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 May 2016 20:50:55 -0700 Subject: Make the source position calues atomic --- Alc/ALu.c | 4 ++-- Alc/mixer.c | 14 +++++++------- OpenAL32/Include/alSource.h | 4 ++-- OpenAL32/alSource.c | 39 ++++++++++++++++++++------------------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 44361979..ec0dd011 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1619,8 +1619,8 @@ ALvoid aluHandleDisconnect(ALCdevice *device) { source->state = AL_STOPPED; ATOMIC_STORE(&source->current_buffer, NULL); - source->position = 0; - source->position_fraction = 0; + ATOMIC_STORE(&source->position, 0); + ATOMIC_STORE(&source->position_fraction, 0); } voice++; diff --git a/Alc/mixer.c b/Alc/mixer.c index 38ec295c..1ee422be 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -384,10 +384,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALuint chan, j; /* Get source info */ - State = Source->state; + State = AL_PLAYING; /* Only called while playing. */ BufferListItem = ATOMIC_LOAD(&Source->current_buffer); - DataPosInt = Source->position; - DataPosFrac = Source->position_fraction; + DataPosInt = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); + DataPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); NumChannels = Source->NumChannels; SampleSize = Source->SampleSize; Looping = voice->Looping; @@ -752,8 +752,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam voice->Moving = AL_TRUE; /* Update source info */ - Source->state = State; - ATOMIC_STORE(&Source->current_buffer, BufferListItem); - Source->position = DataPosInt; - Source->position_fraction = DataPosFrac; + Source->state = State; + ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed); + ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, DataPosFrac); } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index fbd63ce2..bb1e6434 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -172,8 +172,8 @@ typedef struct ALsource { * the whole queue, and the fractional (fixed-point) offset to the next * sample. */ - ALuint position; - ALuint position_fraction; + ATOMIC(ALuint) position; + ATOMIC(ALuint) position_fraction; /** Source Buffer Queue info. */ ATOMIC(ALbufferlistitem*) queue; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 780e9061..a0e40c1d 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2904,8 +2904,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_PAUSED) { Source->state = AL_PLAYING; - Source->position = 0; - Source->position_fraction = 0; + ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_relaxed); ATOMIC_STORE(&Source->current_buffer, BufferList); discontinuity = AL_TRUE; } @@ -2991,8 +2991,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_INITIAL) { Source->state = AL_INITIAL; - Source->position = 0; - Source->position_fraction = 0; + ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_relaxed); ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue)); } Source->OffsetType = AL_NONE; @@ -3022,10 +3022,11 @@ ALint64 GetSourceSampleOffset(ALsource *Source) /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ - readPos = (ALuint64)Source->position << 32; - readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS); - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); + readPos = (ALuint64)ATOMIC_LOAD(&Source->position) << 32; + readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << + (32-FRACTIONBITS); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); while(BufferList && BufferList != Current) { if(BufferList->buffer) @@ -3058,10 +3059,10 @@ static ALdouble GetSourceSecOffset(ALsource *Source) /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ - readPos = (ALuint64)Source->position << FRACTIONBITS; - readPos |= (ALuint64)Source->position_fraction; - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); + readPos = (ALuint64)ATOMIC_LOAD(&Source->position) << FRACTIONBITS; + readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); while(BufferList && BufferList != Current) { const ALbuffer *buffer = BufferList->buffer; @@ -3110,10 +3111,10 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name) /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ totalBufferLen = 0; - readPos = Source->position; - readPosFrac = Source->position_fraction; - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); + readPos = ATOMIC_LOAD(&Source->position); + readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); while(BufferList != NULL) { const ALbuffer *buffer; @@ -3205,10 +3206,10 @@ ALboolean ApplyOffset(ALsource *Source) if(bufferLen > offset-totalBufferLen) { /* Offset is in this buffer */ - ATOMIC_STORE(&Source->current_buffer, BufferList); + ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - Source->position = offset - totalBufferLen; - Source->position_fraction = frac; + ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, frac); return AL_TRUE; } -- cgit v1.2.3 From 2e7ec3979aec71f11c45b737b77d58978cbee7e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 May 2016 03:27:51 -0700 Subject: Avoid using realloc in a number of places --- Alc/effects/chorus.c | 8 ++++---- Alc/effects/echo.c | 8 ++++---- Alc/effects/flanger.c | 8 ++++---- Alc/effects/reverb.c | 12 +++++++----- Alc/helpers.c | 5 ++++- Alc/vector.h | 4 +++- OpenAL32/Include/alBuffer.h | 1 + OpenAL32/alBuffer.c | 35 +++++++++++++++++++++++------------ OpenAL32/alSource.c | 4 +++- 9 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index e1cbba2d..7877ff6f 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -57,7 +57,7 @@ typedef struct ALchorusState { static ALvoid ALchorusState_Destruct(ALchorusState *state) { - free(state->SampleBuffer[0]); + al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -73,10 +73,10 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev if(maxlen != state->BufferLength) { - void *temp; - - temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2); + void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2); if(!temp) return AL_FALSE; + + al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = temp; state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen; diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 0632a44d..163b6ecb 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -52,7 +52,7 @@ typedef struct ALechoState { static ALvoid ALechoState_Destruct(ALechoState *state) { - free(state->SampleBuffer); + al_free(state->SampleBuffer); state->SampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } @@ -69,10 +69,10 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) if(maxlen != state->BufferLength) { - void *temp; - - temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); + void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); if(!temp) return AL_FALSE; + + al_free(state->SampleBuffer); state->SampleBuffer = temp; state->BufferLength = maxlen; } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 7b55977e..f18b2b0f 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -57,7 +57,7 @@ typedef struct ALflangerState { static ALvoid ALflangerState_Destruct(ALflangerState *state) { - free(state->SampleBuffer[0]); + al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -73,10 +73,10 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D if(maxlen != state->BufferLength) { - void *temp; - - temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2); + void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2); if(!temp) return AL_FALSE; + + al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = temp; state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 3f22b787..f8680d24 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -170,7 +170,7 @@ typedef struct ALreverbState { static ALvoid ALreverbState_Destruct(ALreverbState *State) { - free(State->SampleBuffer); + al_free(State->SampleBuffer); State->SampleBuffer = NULL; ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); } @@ -295,7 +295,6 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) { ALuint totalSamples, index; ALfloat length; - ALfloat *newBuffer = NULL; // All delay line lengths are calculated to accomodate the full range of // lengths given their respective paramters. @@ -352,10 +351,13 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) if(totalSamples != State->TotalSamples) { + ALfloat *newBuffer; + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); - newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); - if(newBuffer == NULL) - return AL_FALSE; + newBuffer = al_calloc(16, sizeof(ALfloat) * totalSamples); + if(!newBuffer) return AL_FALSE; + + al_free(State->SampleBuffer); State->SampleBuffer = newBuffer; State->TotalSamples = totalSamples; } diff --git a/Alc/helpers.c b/Alc/helpers.c index 950a67bf..38a34939 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -759,9 +759,12 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t ob /* Need to be explicit with the caller type's base size, because it * could have extra padding before the start of the array (that is, * sizeof(*vector_) may not equal base_size). */ - temp = realloc(*vecptr, base_size + obj_size*obj_count); + temp = al_calloc(16, base_size + obj_size*obj_count); if(temp == NULL) return AL_FALSE; + memcpy(((ALubyte*)temp)+base_size, ((ALubyte*)*vecptr)+base_size, + obj_size*old_size); + al_free(*vecptr); *vecptr = temp; (*vecptr)->Capacity = obj_count; (*vecptr)->Size = old_size; diff --git a/Alc/vector.h b/Alc/vector.h index cb64b5a9..5a0219c0 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -5,6 +5,8 @@ #include +#include "almalloc.h" + /* "Base" vector type, designed to alias with the actual vector types. */ typedef struct vector__s { size_t Capacity; @@ -27,7 +29,7 @@ typedef const _##N* const_##N; #define VECTOR_INIT(_x) do { (_x) = NULL; } while(0) #define VECTOR_INIT_STATIC() NULL -#define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0) +#define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = NULL; } while(0) /* Helper to increase a vector's reserve. Do not call directly. */ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact); diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 4807dd16..351c81bc 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -80,6 +80,7 @@ typedef struct ALbuffer { enum FmtChannels FmtChannels; enum FmtType FmtType; + ALuint BytesAlloc; enum UserFmtChannels OriginalChannels; enum UserFmtType OriginalType; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 8e2c5cf2..193ab44f 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -985,7 +985,6 @@ ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum FmtChannels DstChannels; enum FmtType DstType; ALuint64 newsize; - ALvoid *temp; if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE || (long)SrcChannels != (long)DstChannels) @@ -1007,13 +1006,25 @@ ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, return AL_INVALID_OPERATION; } - temp = realloc(ALBuf->data, (size_t)newsize); - if(!temp && newsize) + /* Round up to the next 16-byte multiple. This could reallocate only when + * increasing or the new size is less than half the current, but then the + * buffer's AL_SIZE would not be very reliable for accounting buffer memory + * usage, and reporting the real size could cause problems for apps that + * use AL_SIZE to try to get the buffer's play length. + */ + newsize = (newsize+15) & ~0xf; + if(newsize != ALBuf->BytesAlloc) { - WriteUnlock(&ALBuf->lock); - return AL_OUT_OF_MEMORY; + void *temp = al_calloc(16, (size_t)newsize); + if(!temp && newsize) + { + WriteUnlock(&ALBuf->lock); + return AL_OUT_OF_MEMORY; + } + al_free(ALBuf->data); + ALBuf->data = temp; + ALBuf->BytesAlloc = (ALuint)newsize; } - ALBuf->data = temp; if(data != NULL) ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align); @@ -1349,7 +1360,7 @@ ALbuffer *NewBuffer(ALCcontext *context) ALbuffer *buffer; ALenum err; - buffer = calloc(1, sizeof(ALbuffer)); + buffer = al_calloc(16, sizeof(ALbuffer)); if(!buffer) SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL); RWLockInit(&buffer->lock); @@ -1361,7 +1372,7 @@ ALbuffer *NewBuffer(ALCcontext *context) { FreeThunkEntry(buffer->id); memset(buffer, 0, sizeof(ALbuffer)); - free(buffer); + al_free(buffer); SET_ERROR_AND_RETURN_VALUE(context, err, NULL); } @@ -1374,10 +1385,10 @@ void DeleteBuffer(ALCdevice *device, ALbuffer *buffer) RemoveBuffer(device, buffer->id); FreeThunkEntry(buffer->id); - free(buffer->data); + al_free(buffer->data); memset(buffer, 0, sizeof(*buffer)); - free(buffer); + al_free(buffer); } @@ -1394,10 +1405,10 @@ ALvoid ReleaseALBuffers(ALCdevice *device) ALbuffer *temp = device->BufferMap.array[i].value; device->BufferMap.array[i].value = NULL; - free(temp->data); + al_free(temp->data); FreeThunkEntry(temp->id); memset(temp, 0, sizeof(ALbuffer)); - free(temp); + al_free(temp); } } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a0e40c1d..22774fa4 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2268,14 +2268,16 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) newcount = context->MaxVoices << 1; if(newcount > 0) - temp = realloc(context->Voices, newcount * sizeof(context->Voices[0])); + temp = al_malloc(16, newcount * sizeof(context->Voices[0])); if(!temp) { UnlockContext(context); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } + memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0])); memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0])); + al_free(context->Voices); context->Voices = temp; context->MaxVoices = newcount; } -- cgit v1.2.3 From ea3fa06bc5f28d346e89600639caab1e199821da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 May 2016 20:42:00 -0700 Subject: Improve locking for device attribute queries Avoids the backend device lock, instead using the list lock to prevent the device from changing while being queried, and adds some missing locks. --- Alc/ALc.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c61a58f3..3a2ac287 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2744,6 +2744,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC } i = 0; + LockLists(); values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -2778,6 +2779,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->Hrtf_Status; + UnlockLists(); values[i++] = 0; return i; @@ -2792,7 +2794,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } + LockLists(); values[0] = device->Frequency / device->UpdateSize; + UnlockLists(); return 1; case ALC_SYNC: @@ -2847,9 +2851,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: + LockLists(); FreeHrtfList(&device->Hrtf_List); device->Hrtf_List = EnumerateHrtf(device->DeviceName); values[0] = (ALCint)VECTOR_SIZE(device->Hrtf_List); + UnlockLists(); return 1; default: @@ -2891,6 +2897,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, } else /* render device */ { + ALuint64 basecount; + ALuint samplecount; + ALuint refcount; + switch(pname) { case ALC_ATTRIBUTES_SIZE: @@ -2904,7 +2914,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, { int i = 0; - V0(device->Backend,lock)(); + LockLists(); values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -2941,19 +2951,29 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = device->Hrtf_Status; values[i++] = ALC_DEVICE_CLOCK_SOFT; - values[i++] = device->ClockBase + - (device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency); + do { + while(((refcount=ReadRef(&device->MixCount))&1) != 0) + althrd_yield(); + basecount = device->ClockBase; + samplecount = device->SamplesDone; + } while(refcount != ReadRef(&device->MixCount)); + values[i++] = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + UnlockLists(); values[i++] = 0; - V0(device->Backend,unlock)(); } break; case ALC_DEVICE_CLOCK_SOFT: - V0(device->Backend,lock)(); - *values = device->ClockBase + - (device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency); - V0(device->Backend,unlock)(); + LockLists(); + do { + while(((refcount=ReadRef(&device->MixCount))&1) != 0) + althrd_yield(); + basecount = device->ClockBase; + samplecount = device->SamplesDone; + } while(refcount != ReadRef(&device->MixCount)); + *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + UnlockLists(); break; default: -- cgit v1.2.3 From e8b274d34993010462cba1086871015b3db1ccfb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 May 2016 21:03:16 -0700 Subject: Properly pluralize some messages --- Alc/ALc.c | 15 ++++++++++----- Alc/backends/mmdevapi.c | 7 ++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3a2ac287..1e501aec 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2139,21 +2139,24 @@ static ALCvoid FreeDevice(ALCdevice *device) if(device->BufferMap.size > 0) { - WARN("(%p) Deleting %d Buffer(s)\n", device, device->BufferMap.size); + WARN("(%p) Deleting %d Buffer%s\n", device, device->BufferMap.size, + (device->BufferMap.size==1)?"":"s"); ReleaseALBuffers(device); } ResetUIntMap(&device->BufferMap); if(device->EffectMap.size > 0) { - WARN("(%p) Deleting %d Effect(s)\n", device, device->EffectMap.size); + WARN("(%p) Deleting %d Effect%s\n", device, device->EffectMap.size, + (device->EffectMap.size==1)?"":"s"); ReleaseALEffects(device); } ResetUIntMap(&device->EffectMap); if(device->FilterMap.size > 0) { - WARN("(%p) Deleting %d Filter(s)\n", device, device->FilterMap.size); + WARN("(%p) Deleting %d Filter%s\n", device, device->FilterMap.size, + (device->FilterMap.size==1)?"":"s"); ReleaseALFilters(device); } ResetUIntMap(&device->FilterMap); @@ -2300,14 +2303,16 @@ static void FreeContext(ALCcontext *context) if(context->SourceMap.size > 0) { - WARN("(%p) Deleting %d Source(s)\n", context, context->SourceMap.size); + WARN("(%p) Deleting %d Source%s\n", context, context->SourceMap.size, + (context->SourceMap.size==1)?"":"s"); ReleaseALSources(context); } ResetUIntMap(&context->SourceMap); if(context->EffectSlotMap.size > 0) { - WARN("(%p) Deleting %d AuxiliaryEffectSlot(s)\n", context, context->EffectSlotMap.size); + WARN("(%p) Deleting %d AuxiliaryEffectSlot%s\n", context, context->EffectSlotMap.size, + (context->EffectSlotMap.size==1)?"":"s"); ReleaseALAuxiliaryEffectSlots(context); } ResetUIntMap(&context->EffectSlotMap); diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 8851678b..938488ac 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1574,9 +1574,10 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) wfx->nChannels != OutputType.Format.nChannels || wfx->nBlockAlign != OutputType.Format.nBlockAlign) { - ERR("Did not get matching format, wanted: %s %s %uhz, got: %d channel(s) %d-bit %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, - wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec); + ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + wfx->nSamplesPerSec); CoTaskMemFree(wfx); return E_FAIL; } -- cgit v1.2.3 From ea83c959caddca82affb5e87bf3d50b7511199d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 23 May 2016 01:03:37 -0700 Subject: Increment the device's mix count closer to the mixing loops --- Alc/ALu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index ec0dd011..b64cbf49 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1418,8 +1418,6 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { - IncrementRef(&device->MixCount); - SamplesToDo = minu(size, BUFFERSIZE); for(c = 0;c < device->VirtOut.NumChannels;c++) memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); @@ -1429,6 +1427,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) for(c = 0;c < device->FOAOut.NumChannels;c++) memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + IncrementRef(&device->MixCount); V0(device->Backend,lock)(); if((slot=device->DefaultSlot) != NULL) @@ -1488,6 +1487,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; device->SamplesDone %= device->Frequency; V0(device->Backend,unlock)(); + IncrementRef(&device->MixCount); if(device->Hrtf) { @@ -1590,7 +1590,6 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } size -= SamplesToDo; - IncrementRef(&device->MixCount); } RestoreFPUMode(&oldMode); -- cgit v1.2.3 From 01f3e33df95c83efeb46a8f51670c99251d0cfdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 May 2016 06:45:56 -0700 Subject: Remove a couple unneeded functions --- OpenAL32/alSource.c | 11 +++++++---- common/atomic.c | 3 --- include/atomic.h | 17 ----------------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 22774fa4..ec32ac8d 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -829,8 +829,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); - slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); - if(slot) DecrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; + /* We must force an update if the auxiliary slot changed on a * playing source, in case the slot is about to be deleted. */ @@ -839,8 +841,9 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p else { if(slot) IncrementRef(&slot->ref); - slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); - if(slot) DecrementRef(&slot->ref); + if(Source->Send[values[1]].Slot) + DecrementRef(&Source->Send[values[1]].Slot->ref); + Source->Send[values[1]].Slot = slot; DO_UPDATEPROPS(); } diff --git a/common/atomic.c b/common/atomic.c index 3cdb77f4..7a8fe6d8 100644 --- a/common/atomic.c +++ b/common/atomic.c @@ -8,6 +8,3 @@ extern inline void InitRef(RefCount *ptr, uint value); extern inline uint ReadRef(RefCount *ptr); extern inline uint IncrementRef(RefCount *ptr); extern inline uint DecrementRef(RefCount *ptr); - -extern inline int ExchangeInt(volatile int *ptr, int newval); -extern inline void *ExchangePtr(XchgPtr *ptr, void *newval); diff --git a/include/atomic.h b/include/atomic.h index 8eb6820b..2a996625 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -305,23 +305,6 @@ inline uint DecrementRef(RefCount *ptr) { return ATOMIC_SUB(uint, ptr, 1)-1; } -/* NOTE: Not atomic! */ -inline int ExchangeInt(volatile int *ptr, int newval) -{ - int old = *ptr; - *ptr = newval; - return old; -} - -typedef void *volatile XchgPtr; -/* NOTE: Not atomic! */ -inline void *ExchangePtr(XchgPtr *ptr, void *newval) -{ - void *old = *ptr; - *ptr = newval; - return old; -} - /* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non- * atomic variables. */ #define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false)) -- cgit v1.2.3 From c837484015e186076165515882beec389f02a987 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 May 2016 19:23:39 -0700 Subject: Use a specific lock for the backend's stop/reset/play calls This helps protect against the device changing unexpectedly from multiple threads, instead of using the global list/library lock. --- Alc/ALc.c | 74 ++++++++++++++++++++++++++++------------------- OpenAL32/Include/alMain.h | 2 ++ 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1e501aec..e8e5c3ee 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2131,6 +2131,8 @@ static ALCvoid FreeDevice(ALCdevice *device) DELETE_OBJ(device->Backend); device->Backend = NULL; + almtx_destroy(&device->BackendLock); + if(device->DefaultSlot) { DeinitEffectSlot(device->DefaultSlot); @@ -2638,9 +2640,9 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para alcSetError(NULL, ALC_INVALID_DEVICE); else { - LockLists(); + almtx_lock(&Device->BackendLock); value = (Device->Hrtf ? al_string_get_cstr(Device->Hrtf_Name) : ""); - UnlockLists(); + almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } break; @@ -2702,9 +2704,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC switch(param) { case ALC_CAPTURE_SAMPLES: - V0(device->Backend,lock)(); + almtx_lock(&device->BackendLock); values[0] = V0(device->Backend,availableSamples)(); - V0(device->Backend,unlock)(); + almtx_unlock(&device->BackendLock); return 1; case ALC_CONNECTED: @@ -2749,7 +2751,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC } i = 0; - LockLists(); + almtx_lock(&device->BackendLock); values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -2784,7 +2786,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->Hrtf_Status; - UnlockLists(); + almtx_unlock(&device->BackendLock); values[i++] = 0; return i; @@ -2799,9 +2801,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - LockLists(); + almtx_lock(&device->BackendLock); values[0] = device->Frequency / device->UpdateSize; - UnlockLists(); + almtx_unlock(&device->BackendLock); return 1; case ALC_SYNC: @@ -2856,11 +2858,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: - LockLists(); + almtx_lock(&device->BackendLock); FreeHrtfList(&device->Hrtf_List); device->Hrtf_List = EnumerateHrtf(device->DeviceName); values[0] = (ALCint)VECTOR_SIZE(device->Hrtf_List); - UnlockLists(); + almtx_unlock(&device->BackendLock); return 1; default: @@ -2919,7 +2921,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, { int i = 0; - LockLists(); + almtx_lock(&device->BackendLock); values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -2963,14 +2965,14 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, samplecount = device->SamplesDone; } while(refcount != ReadRef(&device->MixCount)); values[i++] = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); - UnlockLists(); + almtx_unlock(&device->BackendLock); values[i++] = 0; } break; case ALC_DEVICE_CLOCK_SOFT: - LockLists(); + almtx_lock(&device->BackendLock); do { while(((refcount=ReadRef(&device->MixCount))&1) != 0) althrd_yield(); @@ -2978,7 +2980,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, samplecount = device->SamplesDone; } while(refcount != ReadRef(&device->MixCount)); *values = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); - UnlockLists(); + almtx_unlock(&device->BackendLock); break; default: @@ -3102,6 +3104,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(device) ALCdevice_DecRef(device); return NULL; } + almtx_lock(&device->BackendLock); + UnlockLists(); ATOMIC_STORE(&device->LastError, ALC_NO_ERROR); @@ -3119,7 +3123,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin } if(!ALContext || !ALContext->Voices) { - UnlockLists(); + almtx_unlock(&device->BackendLock); if(ALContext) { @@ -3139,7 +3143,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { - UnlockLists(); + almtx_unlock(&device->BackendLock); al_free(ALContext->Voices); ALContext->Voices = NULL; @@ -3170,7 +3174,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALContext->next = head; } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCcontext*, &device->ContextList, &head, ALContext)); } - UnlockLists(); + almtx_unlock(&device->BackendLock); ALCdevice_DecRef(device); @@ -3191,12 +3195,14 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) Device = alcGetContextsDevice(context); if(Device) { + almtx_lock(&Device->BackendLock); ReleaseContext(context, Device); if(!ATOMIC_LOAD(&Device->ContextList)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; } + almtx_unlock(&Device->BackendLock); } UnlockLists(); } @@ -3479,6 +3485,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) alcSetError(NULL, err); return NULL; } + almtx_init(&device->BackendLock, almtx_plain); if(DefaultEffect.type != AL_EFFECT_NULL) { @@ -3532,6 +3539,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) UnlockLists(); return ALC_FALSE; } + almtx_lock(&device->BackendLock); origdev = device; nextdev = device->next; @@ -3555,6 +3563,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; + almtx_unlock(&device->BackendLock); ALCdevice_DecRef(device); @@ -3650,6 +3659,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, alcSetError(NULL, err); return NULL; } + almtx_init(&device->BackendLock, almtx_plain); { ALCdevice *head = ATOMIC_LOAD(&DeviceList); @@ -3701,7 +3711,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - V0(device->Backend,lock)(); + almtx_lock(&device->BackendLock); if(!device->Connected) alcSetError(device, ALC_INVALID_DEVICE); else if(!(device->Flags&DEVICE_RUNNING)) @@ -3714,7 +3724,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); } } - V0(device->Backend,unlock)(); + almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); @@ -3726,11 +3736,11 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - V0(device->Backend,lock)(); + almtx_lock(&device->BackendLock); if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; - V0(device->Backend,unlock)(); + almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); @@ -3744,10 +3754,10 @@ ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, { ALCenum err = ALC_INVALID_VALUE; - V0(device->Backend,lock)(); + almtx_lock(&device->BackendLock); if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) err = V(device->Backend,captureSamples)(buffer, samples); - V0(device->Backend,unlock)(); + almtx_unlock(&device->BackendLock); if(err != ALC_NO_ERROR) alcSetError(device, err); @@ -3826,6 +3836,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN alcSetError(NULL, ALC_OUT_OF_MEMORY); return NULL; } + almtx_init(&device->BackendLock, almtx_plain); //Set output format device->NumUpdates = 0; @@ -3917,12 +3928,12 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - LockLists(); + almtx_lock(&device->BackendLock); if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; device->Flags |= DEVICE_PAUSED; - UnlockLists(); + almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); } @@ -3937,7 +3948,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) alcSetError(device, ALC_INVALID_DEVICE); else { - LockLists(); + almtx_lock(&device->BackendLock); if((device->Flags&DEVICE_PAUSED)) { device->Flags &= ~DEVICE_PAUSED; @@ -3954,7 +3965,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) } } } - UnlockLists(); + almtx_unlock(&device->BackendLock); } if(device) ALCdevice_DecRef(device); } @@ -4008,10 +4019,14 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi if(device) ALCdevice_DecRef(device); return ALC_FALSE; } + almtx_lock(&device->BackendLock); + UnlockLists(); - if((err=UpdateDeviceParams(device, attribs)) != ALC_NO_ERROR) + err = UpdateDeviceParams(device, attribs); + almtx_unlock(&device->BackendLock); + + if(err != ALC_NO_ERROR) { - UnlockLists(); alcSetError(device, err); if(err == ALC_INVALID_DEVICE) { @@ -4022,7 +4037,6 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi ALCdevice_DecRef(device); return ALC_FALSE; } - UnlockLists(); ALCdevice_DecRef(device); return ALC_TRUE; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f709e9bd..50162b0e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -37,6 +37,7 @@ #include "vector.h" #include "alstring.h" #include "almalloc.h" +#include "threads.h" #include "hrtf.h" @@ -644,6 +645,7 @@ struct ALCdevice_struct // Contexts created on this device ATOMIC(ALCcontext*) ContextList; + almtx_t BackendLock; struct ALCbackend *Backend; void *ExtraData; // For the backend's use -- cgit v1.2.3 From 800e38bac68315d372ca1f865c7c448356309f70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 May 2016 19:40:54 -0700 Subject: Use the backend lock for the effectstate's deviceUpdate call --- OpenAL32/alAuxEffectSlot.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 9cc86563..c37ecd58 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -470,24 +470,20 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e return AL_INVALID_ENUM; } State = V0(factory,create)(); - if(!State) - return AL_OUT_OF_MEMORY; + if(!State) return AL_OUT_OF_MEMORY; SetMixerFPUMode(&oldMode); - /* FIXME: This just needs to prevent the device from being reset during - * the state's device update, so the list lock in ALc.c should do here. - */ - ALCdevice_Lock(Device); + almtx_lock(&Device->BackendLock); State->OutBuffer = Device->Dry.Buffer; State->OutChannels = Device->Dry.NumChannels; if(V(State,deviceUpdate)(Device) == AL_FALSE) { - ALCdevice_Unlock(Device); + almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); DELETE_OBJ(State); return AL_OUT_OF_MEMORY; } - ALCdevice_Unlock(Device); + almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); if(!effect) -- cgit v1.2.3 From 6d4380a48c28f21d271d4eb5e668443bc8a0f50e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 May 2016 00:43:14 -0700 Subject: Change the backend getLatency method to return the clock time too This will also allow backends to better synchronize the tracked clock time with the device output latency, without necessarily needing to lock if the backend API can allow for it. --- Alc/backends/alsa.c | 30 ++++++++++++++++++++++-------- Alc/backends/base.c | 19 +++++++++++++++---- Alc/backends/base.h | 23 +++++++++++++++++++---- Alc/backends/dsound.c | 4 ++-- Alc/backends/jack.c | 12 +++++++----- Alc/backends/loopback.c | 2 +- Alc/backends/mmdevapi.c | 15 +++++++++++---- Alc/backends/null.c | 2 +- Alc/backends/oss.c | 4 ++-- Alc/backends/portaudio.c | 4 ++-- Alc/backends/pulseaudio.c | 38 +++++++++++++++++++++++++------------- Alc/backends/solaris.c | 2 +- Alc/backends/wave.c | 2 +- Alc/backends/winmm.c | 4 ++-- OpenAL32/alSource.c | 11 ++++++++--- 15 files changed, 119 insertions(+), 53 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 7d23ecc3..280f5019 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -410,7 +410,7 @@ 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 ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self); +static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self); static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock) static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa) @@ -891,18 +891,25 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) self->buffer = NULL; } -static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self) +static ClockLatency ALCplaybackAlsa_getClockLatency(ALCplaybackAlsa *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t delay = 0; + ClockLatency ret; int err; + ALCplaybackAlsa_lock(self); + ret.ClockTime = GetDeviceClockTime(device); if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - return 0; + delay = 0; } - return maxi64((ALint64)delay*1000000000/device->Frequency, 0); + if(delay < 0) delay = 0; + ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ALCplaybackAlsa_unlock(self); + + return ret; } @@ -929,7 +936,7 @@ 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 ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self); +static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self); static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock) static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa) @@ -1277,18 +1284,25 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) return ll_ringbuffer_read_space(self->ring); } -static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self) +static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t delay = 0; + ClockLatency ret; int err; + ALCcaptureAlsa_lock(self); + ret.ClockTime = GetDeviceClockTime(device); if((err=snd_pcm_delay(self->pcmHandle, &delay)) < 0) { ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); - return 0; + delay = 0; } - return maxi64((ALint64)delay*1000000000/device->Frequency, 0); + if(delay < 0) delay = 0; + ret.Latency = delay * DEVICE_CLOCK_RES / device->Frequency; + ALCcaptureAlsa_unlock(self); + + return ret; } diff --git a/Alc/backends/base.c b/Alc/backends/base.c index ebeb31bf..07c33ba1 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -8,6 +8,8 @@ #include "backends/base.h" +extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); + /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) { @@ -37,9 +39,18 @@ ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) return 0; } -ALint64 ALCbackend_getLatency(ALCbackend* UNUSED(self)) +ClockLatency ALCbackend_getClockLatency(ALCbackend *self) { - return 0; + ALCdevice *device = self->mDevice; + ClockLatency ret; + + almtx_lock(&self->mMutex); + ret.ClockTime = GetDeviceClockTime(device); + // TODO: Perhaps should be NumUpdates-1 worth of UpdateSize? + ret.Latency = 0; + almtx_unlock(&self->mMutex); + + return ret; } void ALCbackend_lock(ALCbackend *self) @@ -77,7 +88,7 @@ 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 DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) @@ -137,7 +148,7 @@ 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 DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) diff --git a/Alc/backends/base.h b/Alc/backends/base.h index f6b4b80a..04795b36 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -5,6 +5,21 @@ #include "threads.h" +typedef struct ClockLatency { + ALint64 ClockTime; + ALint64 Latency; +} ClockLatency; + +/* Helper to get the current clock time from the device's ClockBase, and + * SamplesDone converted from the sample rate. + */ +inline ALuint64 GetDeviceClockTime(ALCdevice *device) +{ + return device->ClockBase + (device->SamplesDone * DEVICE_CLOCK_RES / + device->Frequency); +} + + struct ALCbackendVtable; typedef struct ALCbackend { @@ -20,7 +35,7 @@ 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); +ClockLatency ALCbackend_getClockLatency(ALCbackend *self); void ALCbackend_lock(ALCbackend *self); void ALCbackend_unlock(ALCbackend *self); @@ -37,7 +52,7 @@ struct ALCbackendVtable { ALCenum (*const captureSamples)(ALCbackend*, void*, ALCuint); ALCuint (*const availableSamples)(ALCbackend*); - ALint64 (*const getLatency)(ALCbackend*); + ClockLatency (*const getClockLatency)(ALCbackend*); void (*const lock)(ALCbackend*); void (*const unlock)(ALCbackend*); @@ -54,7 +69,7 @@ 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, ClockLatency, getClockLatency) \ DECLARE_THUNK(T, ALCbackend, void, lock) \ DECLARE_THUNK(T, ALCbackend, void, unlock) \ static void T##_ALCbackend_Delete(void *ptr) \ @@ -70,7 +85,7 @@ static const struct ALCbackendVtable T##_ALCbackend_vtable = { \ T##_ALCbackend_stop, \ T##_ALCbackend_captureSamples, \ T##_ALCbackend_availableSamples, \ - T##_ALCbackend_getLatency, \ + T##_ALCbackend_getClockLatency, \ T##_ALCbackend_lock, \ T##_ALCbackend_unlock, \ \ diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 454f7fa0..1ff99352 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -199,7 +199,7 @@ static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self); static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self); static DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback) @@ -666,7 +666,7 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self); static void ALCdsoundCapture_stop(ALCdsoundCapture *self); static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples); static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self); -static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock) static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 69d1277a..cfdc62e8 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -148,7 +148,7 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); static void ALCjackPlayback_stop(ALCjackPlayback *self); static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) -static ALint64 ALCjackPlayback_getLatency(ALCjackPlayback *self); +static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); static void ALCjackPlayback_lock(ALCjackPlayback *self); static void ALCjackPlayback_unlock(ALCjackPlayback *self); DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) @@ -506,16 +506,18 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) } -static ALint64 ALCjackPlayback_getLatency(ALCjackPlayback *self) +static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALint64 latency; + ClockLatency ret; ALCjackPlayback_lock(self); - latency = ll_ringbuffer_read_space(self->Ring); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ll_ringbuffer_read_space(self->Ring) * DEVICE_CLOCK_RES / + device->Frequency; ALCjackPlayback_unlock(self); - return latency * 1000000000 / device->Frequency; + return ret; } diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c index 3e577f78..0164bc5a 100644 --- a/Alc/backends/loopback.c +++ b/Alc/backends/loopback.c @@ -41,7 +41,7 @@ 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, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCloopback) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 938488ac..f102e385 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -508,7 +508,7 @@ static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self); static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self); static DECLARE_FORWARD2(ALCmmdevPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, ALCuint, availableSamples) -static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self); +static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self); static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCmmdevPlayback) @@ -1139,10 +1139,17 @@ static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self) } -static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self) +static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return (ALint64)self->Padding * 1000000000 / device->Frequency; + ClockLatency ret; + + ALCmmdevPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = self->Padding * DEVICE_CLOCK_RES / device->Frequency; + ALCmmdevPlayback_unlock(self); + + return ret; } @@ -1181,7 +1188,7 @@ static void ALCmmdevCapture_stop(ALCmmdevCapture *self); static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self); static ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples); static ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self); -static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock) static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture) diff --git a/Alc/backends/null.c b/Alc/backends/null.c index 99729c0a..5b153cd9 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -51,7 +51,7 @@ 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, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock) static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index a61b4859..432c75f2 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -257,7 +257,7 @@ 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, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock) static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS) @@ -502,7 +502,7 @@ 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, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock) static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS) diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index f45833c6..1dbca941 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -145,7 +145,7 @@ static ALCboolean ALCportPlayback_start(ALCportPlayback *self); static void ALCportPlayback_stop(ALCportPlayback *self); static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) @@ -340,7 +340,7 @@ static ALCboolean ALCportCapture_start(ALCportCapture *self); static void ALCportCapture_stop(ALCportCapture *self); static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); static ALCuint ALCportCapture_availableSamples(ALCportCapture *self); -static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index ccce2e00..d317b576 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -489,7 +489,7 @@ 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 ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self); +static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self); static void ALCpulsePlayback_lock(ALCpulsePlayback *self); static void ALCpulsePlayback_unlock(ALCpulsePlayback *self); DECLARE_DEFAULT_ALLOCATORS(ALCpulsePlayback) @@ -1136,11 +1136,14 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self) } -static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self) +static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) { pa_usec_t latency = 0; + ClockLatency ret; int neg, err; + pa_threaded_mainloop_lock(self->loop); + ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0) { /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon @@ -1149,11 +1152,14 @@ static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self) * dummy value? Either way, it shouldn't be 0. */ if(err != -PA_ERR_NODATA) ERR("Failed to get stream latency: 0x%x\n", err); - return 0; + latency = 0; + neg = 0; } - if(neg) latency = 0; - return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000; + pa_threaded_mainloop_unlock(self->loop); + + return ret; } @@ -1209,7 +1215,7 @@ 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 ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self); +static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self); static void ALCpulseCapture_lock(ALCpulseCapture *self); static void ALCpulseCapture_unlock(ALCpulseCapture *self); DECLARE_DEFAULT_ALLOCATORS(ALCpulseCapture) @@ -1639,19 +1645,25 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) } -static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self) +static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self) { pa_usec_t latency = 0; - int neg; + ClockLatency ret; + int neg, err; - if(pa_stream_get_latency(self->stream, &latency, &neg) != 0) + pa_threaded_mainloop_lock(self->loop); + ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); + if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0) { - ERR("Failed to get stream latency!\n"); - return 0; + ERR("Failed to get stream latency: 0x%x\n", err); + latency = 0; + neg = 0; } - if(neg) latency = 0; - return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; + ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000; + pa_threaded_mainloop_unlock(self->loop); + + return ret; } diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 6eaf1ee5..01472e6a 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -65,7 +65,7 @@ static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); static void ALCsolarisBackend_stop(ALCsolarisBackend *self); static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock) static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend) diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 3b87d645..af996233 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -91,7 +91,7 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); static void ALCwaveBackend_stop(ALCwaveBackend *self); static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 664b3dfe..180f764b 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -164,7 +164,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) @@ -451,7 +451,7 @@ static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); static void ALCwinmmCapture_stop(ALCwinmmCapture *self); static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); -static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ClockLatency, getClockLatency) static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index ec32ac8d..e04199b3 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1006,6 +1006,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; + ClockLatency clocktime; ALint ivals[3]; ALboolean err; @@ -1107,9 +1108,10 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET_LATENCY_SOFT: LockContext(Context); + clocktime = V0(device->Backend,getClockLatency)(); + values[0] = GetSourceSecOffset(Source); - values[1] = (ALdouble)(V0(device->Backend,getLatency)()) / - 1000000000.0; + values[1] = (ALdouble)clocktime.Latency / 1000000000.0; UnlockContext(Context); return AL_TRUE; @@ -1382,6 +1384,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) { ALCdevice *device = Context->Device; + ClockLatency clocktime; ALdouble dvals[6]; ALint ivals[3]; ALboolean err; @@ -1390,8 +1393,10 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp { case AL_SAMPLE_OFFSET_LATENCY_SOFT: LockContext(Context); + clocktime = V0(device->Backend,getClockLatency)(); + values[0] = GetSourceSampleOffset(Source); - values[1] = V0(device->Backend,getLatency)(); + values[1] = clocktime.Latency; UnlockContext(Context); return AL_TRUE; -- cgit v1.2.3 From 9025e42afd9f5c518d6e30167bcb4b1d6a6beee8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 May 2016 04:11:57 -0700 Subject: Avoid an explicit mixer lock for getting the source offset and latency The only mixer locking involved is with the backend, as determined by it's ability to get the device clock and latency atomically. --- OpenAL32/alSource.c | 99 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 27 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e04199b3..8a07cf13 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -49,8 +49,8 @@ extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static ALvoid InitSourceParams(ALsource *Source); static ALvoid DeinitSource(ALsource *source); -static ALint64 GetSourceSampleOffset(ALsource *Source); -static ALdouble GetSourceSecOffset(ALsource *Source); +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); +static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); @@ -1007,6 +1007,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; ClockLatency clocktime; + ALuint64 srcclock; ALint ivals[3]; ALboolean err; @@ -1107,12 +1108,23 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_SEC_OFFSET_LATENCY_SOFT: - LockContext(Context); + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSecOffset(Source, device, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); - - values[0] = GetSourceSecOffset(Source); - values[1] = (ALdouble)clocktime.Latency / 1000000000.0; - UnlockContext(Context); + if(srcclock == (ALuint64)clocktime.ClockTime) + values[1] = (ALdouble)clocktime.Latency / 1000000000.0; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + ALuint64 diff = clocktime.ClockTime - srcclock; + values[1] = (ALdouble)(clocktime.Latency - minu64(clocktime.Latency, diff)) / + 1000000000.0; + } return AL_TRUE; case AL_POSITION: @@ -1385,6 +1397,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp { ALCdevice *device = Context->Device; ClockLatency clocktime; + ALuint64 srcclock; ALdouble dvals[6]; ALint ivals[3]; ALboolean err; @@ -1392,12 +1405,22 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp switch(prop) { case AL_SAMPLE_OFFSET_LATENCY_SOFT: - LockContext(Context); + /* Get the source offset with the clock time first. Then get the + * clock time with the device latency. Order is important. + */ + values[0] = GetSourceSampleOffset(Source, device, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); - - values[0] = GetSourceSampleOffset(Source); - values[1] = clocktime.Latency; - UnlockContext(Context); + if(srcclock == (ALuint64)clocktime.ClockTime) + values[1] = clocktime.Latency; + else + { + /* If the clock time incremented, reduce the latency by that + * much since it's that much closer to the source offset it got + * earlier. + */ + ALuint64 diff = clocktime.ClockTime - srcclock; + values[1] = clocktime.Latency - minu64(clocktime.Latency, diff); + } return AL_TRUE; /* 1x float/double */ @@ -3017,26 +3040,37 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -ALint64 GetSourceSampleOffset(ALsource *Source) +ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; + ALuint refcount; ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) { ReadUnlock(&Source->queue_lock); + do { + while(((refcount=ReadRef(&device->MixCount))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + } while(refcount != ReadRef(&device->MixCount)); return 0; } - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = (ALuint64)ATOMIC_LOAD(&Source->position) << 32; - readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << - (32-FRACTIONBITS); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + do { + while(((refcount=ReadRef(&device->MixCount))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; + readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << + (32-FRACTIONBITS); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + } while(refcount != ReadRef(&device->MixCount)); while(BufferList && BufferList != Current) { if(BufferList->buffer) @@ -3053,26 +3087,37 @@ ALint64 GetSourceSampleOffset(ALsource *Source) * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -static ALdouble GetSourceSecOffset(ALsource *Source) +static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; ALuint64 readPos; + ALuint refcount; ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) { ReadUnlock(&Source->queue_lock); + do { + while(((refcount=ReadRef(&device->MixCount))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + } while(refcount != ReadRef(&device->MixCount)); return 0.0; } - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = (ALuint64)ATOMIC_LOAD(&Source->position) << FRACTIONBITS; - readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + do { + while(((refcount=ReadRef(&device->MixCount))&1)) + althrd_yield(); + *clocktime = GetDeviceClockTime(device); + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << FRACTIONBITS; + readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + } while(refcount != ReadRef(&device->MixCount)); while(BufferList && BufferList != Current) { const ALbuffer *buffer = BufferList->buffer; -- cgit v1.2.3 From 4b8aa9caf11b35d0b670bdba05132357e580a71c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 May 2016 06:23:55 -0700 Subject: Avoid the mixer lock when getting the plain source offset i.e. without the latency --- OpenAL32/alSource.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 8a07cf13..a15b169f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -51,7 +51,7 @@ static ALvoid InitSourceParams(ALsource *Source); static ALvoid DeinitSource(ALsource *source); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); -static ALdouble GetSourceOffset(ALsource *Source, ALenum name); +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); typedef enum SourceProp { @@ -1056,9 +1056,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - LockContext(Context); - *values = GetSourceOffset(Source, prop); - UnlockContext(Context); + *values = GetSourceOffset(Source, prop, device); return AL_TRUE; case AL_CONE_OUTER_GAINHF: @@ -3146,7 +3144,7 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 * (Bytes, Samples or Seconds). The offset is relative to the start of the * queue (not the start of the current buffer). */ -static ALdouble GetSourceOffset(ALsource *Source, ALenum name) +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; @@ -3155,6 +3153,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name) ALuint readPos, readPosFrac; ALuint totalBufferLen; ALdouble offset = 0.0; + ALuint refcount; ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) @@ -3163,13 +3162,18 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name) return 0.0; } - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ totalBufferLen = 0; - readPos = ATOMIC_LOAD(&Source->position); - readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + do { + while(((refcount=ReadRef(&device->MixCount))&1)) + althrd_yield(); + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); + readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + } while(refcount != ReadRef(&device->MixCount)); + while(BufferList != NULL) { const ALbuffer *buffer; -- cgit v1.2.3 From 8aa4a74a7b213f2a8a3e0126a248357e587d34a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 May 2016 01:40:16 -0700 Subject: Use a linked list for active effect slots --- Alc/ALc.c | 8 +---- Alc/ALu.c | 40 ++++++++++++++--------- OpenAL32/Include/alAuxEffectSlot.h | 2 ++ OpenAL32/Include/alMain.h | 2 +- OpenAL32/alAuxEffectSlot.c | 67 ++++++++++++++++++-------------------- 5 files changed, 59 insertions(+), 60 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e8e5c3ee..b4582b0e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2324,8 +2324,6 @@ static void FreeContext(ALCcontext *context) context->VoiceCount = 0; context->MaxVoices = 0; - VECTOR_DEINIT(context->ActiveAuxSlots); - if((lprops=ATOMIC_LOAD(&listener->Update, almemory_order_acquire)) != NULL) { TRACE("Freed unapplied listener update %p\n", lprops); @@ -3115,7 +3113,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin InitRef(&ALContext->ref, 1); ALContext->Listener = (ALlistener*)ALContext->_listener_mem; - VECTOR_INIT(ALContext->ActiveAuxSlots); + ATOMIC_INIT(&ALContext->ActiveAuxSlotList, NULL); ALContext->VoiceCount = 0; ALContext->MaxVoices = 256; @@ -3130,8 +3128,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin al_free(ALContext->Voices); ALContext->Voices = NULL; - VECTOR_DEINIT(ALContext->ActiveAuxSlots); - al_free(ALContext); ALContext = NULL; } @@ -3148,8 +3144,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin al_free(ALContext->Voices); ALContext->Voices = NULL; - VECTOR_DEINIT(ALContext->ActiveAuxSlots); - al_free(ALContext); ALContext = NULL; diff --git a/Alc/ALu.c b/Alc/ALu.c index b64cbf49..3ba068a2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1320,7 +1320,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context) } -static void UpdateContextSources(ALCcontext *ctx) +static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) { ALvoice *voice, *voice_end; ALsource *source; @@ -1329,9 +1329,11 @@ static void UpdateContextSources(ALCcontext *ctx) if(!ATOMIC_LOAD(&ctx->HoldUpdates)) { CalcListenerParams(ctx); -#define UPDATE_SLOT(iter) CalcEffectSlotParams(*iter, ctx->Device) - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); -#undef UPDATE_SLOT + while(slot) + { + CalcEffectSlotParams(slot, ctx->Device); + slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); + } voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; @@ -1440,13 +1442,18 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ctx = ATOMIC_LOAD(&device->ContextList); while(ctx) { - UpdateContextSources(ctx); -#define CLEAR_WET_BUFFER(iter) do { \ - for(i = 0;i < (*iter)->NumChannels;i++) \ - memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \ -} while(0) - VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER); -#undef CLEAR_WET_BUFFER + ALeffectslot *slotroot; + + slotroot = ATOMIC_LOAD(&ctx->ActiveAuxSlotList); + UpdateContextSources(ctx, slotroot); + + slot = slotroot; + while(slot) + { + for(i = 0;i < slot->NumChannels;i++) + memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); + slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); + } /* source processing */ voice = ctx->Voices; @@ -1459,13 +1466,14 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } /* effect slot processing */ - c = VECTOR_SIZE(ctx->ActiveAuxSlots); - for(i = 0;i < c;i++) + slot = slotroot; + while(slot) { - const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i); - ALeffectState *state = slot->Params.EffectState; - V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, + const ALeffectslot *cslot = slot; + ALeffectState *state = cslot->Params.EffectState; + V(state,process)(SamplesToDo, cslot->WetBuffer, state->OutBuffer, state->OutChannels); + slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } ctx = ctx->next; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 85d730f8..a9b50387 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -129,6 +129,8 @@ typedef struct ALeffectslot { * first-order device output (FOAOut). */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; + + ATOMIC(struct ALeffectslot*) next; } ALeffectslot; inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 50162b0e..d7b54310 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -711,7 +711,7 @@ struct ALCcontext_struct { ALsizei VoiceCount; ALsizei MaxVoices; - VECTOR(struct ALeffectslot*) ActiveAuxSlots; + ATOMIC(struct ALeffectslot*) ActiveAuxSlotList; ALCdevice *Device; const ALCchar *ExtensionList; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index c37ecd58..8da7aeb2 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -38,8 +38,8 @@ extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); -static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count); -static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot); +static void AddEffectSlotList(ALCcontext *Context, ALeffectslot *first, ALeffectslot *last); +static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot); static UIntMap EffectStateFactoryMap; @@ -55,20 +55,17 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { ALCcontext *context; - VECTOR(ALeffectslot*) slotvec; + ALeffectslot *first, *last; ALsizei cur; ALenum err; context = GetContextRef(); if(!context) return; - VECTOR_INIT(slotvec); - if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if(!VECTOR_RESERVE(slotvec, n)) - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); + first = last = NULL; for(cur = 0;cur < n;cur++) { ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot)); @@ -95,20 +92,15 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo aluInitEffectPanning(slot); - VECTOR_PUSH_BACK(slotvec, slot); + if(!first) first = slot; + if(last) ATOMIC_STORE(&last->next, slot); + last = slot; effectslots[cur] = slot->id; } - err = AddEffectSlotArray(context, VECTOR_BEGIN(slotvec), n); - if(err != AL_NO_ERROR) - { - alDeleteAuxiliaryEffectSlots(cur, effectslots); - SET_ERROR_AND_GOTO(context, err, done); - } + AddEffectSlotList(context, first, last); done: - VECTOR_DEINIT(slotvec); - ALCcontext_DecRef(context); } @@ -138,7 +130,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * continue; FreeThunkEntry(slot->id); - RemoveEffectSlotArray(context, slot); + RemoveEffectSlotList(context, slot); DeinitEffectSlot(slot); memset(slot, 0, sizeof(*slot)); @@ -399,32 +391,33 @@ done: } -static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count) +static void AddEffectSlotList(ALCcontext *context, ALeffectslot *start, ALeffectslot *last) { - ALenum err = AL_NO_ERROR; - - LockContext(context); - if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_END(context->ActiveAuxSlots), start, start+count)) - err = AL_OUT_OF_MEMORY; - UnlockContext(context); - - return err; + ALeffectslot *root = ATOMIC_LOAD(&context->ActiveAuxSlotList); + do { + ATOMIC_STORE(&last->next, root, almemory_order_relaxed); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot*, &context->ActiveAuxSlotList, + &root, start)); } -static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot) +static void RemoveEffectSlotList(ALCcontext *context, const ALeffectslot *slot) { - ALeffectslot **iter; + ALCdevice *device = context->Device; + const ALeffectslot *root, *next; - LockContext(context); -#define MATCH_SLOT(_i) (slot == *(_i)) - VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT); - if(iter != VECTOR_END(context->ActiveAuxSlots)) + root = slot; + next = ATOMIC_LOAD(&slot->next); + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &context->ActiveAuxSlotList, &root, next)) { - *iter = VECTOR_BACK(context->ActiveAuxSlots); - VECTOR_POP_BACK(context->ActiveAuxSlots); + const ALeffectslot *cur; + do { + cur = root; + root = slot; + } while(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &cur->next, &root, next)); } -#undef MATCH_SLOT - UnlockContext(context); + /* Wait for any mix that may be using these effect slots to finish. */ + while((ReadRef(&device->MixCount)&1) != 0) + althrd_yield(); } @@ -539,6 +532,8 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; + ATOMIC_INIT(&slot->next, NULL); + return AL_NO_ERROR; } -- cgit v1.2.3 From 4802465f1a6365051604f38dae9c20c93c0f0a7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 May 2016 02:47:54 -0700 Subject: Hold the effectslot map lock while handling it --- OpenAL32/Include/alAuxEffectSlot.h | 13 +++++++++++-- OpenAL32/alAuxEffectSlot.c | 24 ++++++++++++++++++++++++ OpenAL32/alSource.c | 3 +++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index a9b50387..8d2fc3d7 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -133,10 +133,19 @@ typedef struct ALeffectslot { ATOMIC(struct ALeffectslot*) next; } ALeffectslot; +inline void LockEffectSlotsRead(ALCcontext *context) +{ LockUIntMapRead(&context->EffectSlotMap); } +inline void UnlockEffectSlotsRead(ALCcontext *context) +{ UnlockUIntMapRead(&context->EffectSlotMap); } +inline void LockEffectSlotsWrite(ALCcontext *context) +{ LockUIntMapWrite(&context->EffectSlotMap); } +inline void UnlockEffectSlotsWrite(ALCcontext *context) +{ UnlockUIntMapWrite(&context->EffectSlotMap); } + inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ return (struct ALeffectslot*)LookupUIntMapKey(&context->EffectSlotMap, id); } +{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); } inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) -{ return (struct ALeffectslot*)RemoveUIntMapKey(&context->EffectSlotMap, id); } +{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); } ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 8da7aeb2..b0fd3385 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -35,6 +35,10 @@ #include "almalloc.h" +extern inline void LockEffectSlotsRead(ALCcontext *context); +extern inline void UnlockEffectSlotsRead(ALCcontext *context); +extern inline void LockEffectSlotsWrite(ALCcontext *context); +extern inline void UnlockEffectSlotsWrite(ALCcontext *context); extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); @@ -113,6 +117,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * context = GetContextRef(); if(!context) return; + LockEffectSlotsWrite(context); if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); for(i = 0;i < n;i++) @@ -138,6 +143,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * } done: + UnlockEffectSlotsWrite(context); ALCcontext_DecRef(context); } @@ -149,7 +155,9 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) context = GetContextRef(); if(!context) return AL_FALSE; + LockEffectSlotsRead(context); ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE); + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); @@ -168,6 +176,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!context) return; WriteLock(&context->PropLock); + LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -203,6 +212,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param } done: + UnlockEffectSlotsRead(context); WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -222,6 +232,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -231,6 +242,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } @@ -243,6 +255,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param if(!context) return; WriteLock(&context->PropLock); + LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -259,6 +272,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param UpdateEffectSlotProps(slot); done: + UnlockEffectSlotsRead(context); WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -277,6 +291,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -286,6 +301,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } @@ -297,6 +313,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -310,6 +327,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } @@ -328,6 +346,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -337,6 +356,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } @@ -348,6 +368,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -361,6 +382,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } @@ -378,6 +400,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p context = GetContextRef(); if(!context) return; + LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); switch(param) @@ -387,6 +410,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p } done: + UnlockEffectSlotsRead(context); ALCcontext_DecRef(context); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a15b169f..c1824d5b 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -796,12 +796,14 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: + LockEffectSlotsRead(Context); LockFiltersRead(device); if(!((ALuint)values[1] < device->NumAuxSends && (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) { UnlockFiltersRead(device); + UnlockEffectSlotsRead(Context); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } @@ -846,6 +848,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].Slot = slot; DO_UPDATEPROPS(); } + UnlockEffectSlotsRead(Context); return AL_TRUE; -- cgit v1.2.3 From 70a105c22ca79baccbf6e9ba6a64b7c31eebe3df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 May 2016 00:05:10 -0700 Subject: Remove unnecessary VECTOR_INSERT --- Alc/helpers.c | 69 ++++++++++++++++++++++++++--------------------------------- Alc/vector.h | 15 ------------- 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 38a34939..e1cd6be1 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -784,35 +784,6 @@ ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj return AL_TRUE; } -ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend) -{ - vector_ *vecptr = (vector_*)ptr; - if(datstart != datend) - { - ptrdiff_t ins_elem = (*vecptr ? ((char*)ins_pos - ((char*)(*vecptr) + base_size)) : - ((char*)ins_pos - (char*)NULL)) / - obj_size; - ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size; - - assert(numins > 0); - if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins || - !vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE)) - return AL_FALSE; - - /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */ - if((size_t)ins_elem < (*vecptr)->Size) - { - memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size), - (char*)(*vecptr) + base_size + ((ins_elem )*obj_size), - ((*vecptr)->Size-ins_elem)*obj_size); - } - memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size), - datstart, numins*obj_size); - (*vecptr)->Size += numins; - } - return AL_TRUE; -} - extern inline void al_string_deinit(al_string *str); extern inline size_t al_string_length(const_al_string str); @@ -859,27 +830,36 @@ int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2) void al_string_copy(al_string *str, const_al_string from) { size_t len = al_string_length(from); + size_t i; + VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_END(*str), VECTOR_BEGIN(from), VECTOR_BEGIN(from)+len); + VECTOR_RESIZE(*str, len); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); *VECTOR_END(*str) = 0; } void al_string_copy_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); + size_t i; + VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_END(*str), from, from+len); + VECTOR_RESIZE(*str, len); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; *VECTOR_END(*str) = 0; } void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { size_t len = to - from; + size_t i; + VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_END(*str), from, to); + VECTOR_RESIZE(*str, len); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, i) = from[i]; *VECTOR_END(*str) = 0; } @@ -895,8 +875,13 @@ void al_string_append_cstr(al_string *str, const al_string_char_type *from) size_t len = strlen(from); if(len != 0) { - VECTOR_RESERVE(*str, al_string_length(*str)+len+1); - VECTOR_INSERT(*str, VECTOR_END(*str), from, from+len); + size_t base = al_string_length(*str); + size_t i; + + VECTOR_RESERVE(*str, base+len+1); + VECTOR_RESIZE(*str, base+len); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; *VECTOR_END(*str) = 0; } } @@ -905,8 +890,14 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con { if(to != from) { - VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1); - VECTOR_INSERT(*str, VECTOR_END(*str), from, to); + size_t base = al_string_length(*str); + size_t len = to - from; + size_t i; + + VECTOR_RESERVE(*str, base+len+1); + VECTOR_RESIZE(*str, base+len); + for(i = 0;i < len;i++) + VECTOR_ELEM(*str, base+i) = from[i]; *VECTOR_END(*str) = 0; } } diff --git a/Alc/vector.h b/Alc/vector.h index 5a0219c0..12de74f5 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -44,21 +44,6 @@ ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj #define VECTOR_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) #define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) -ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend); -#ifdef __GNUC__ -#define TYPE_CHECK(T1, T2) __builtin_types_compatible_p(T1, T2) -#define VECTOR_INSERT(_x, _i, _s, _e) __extension__({ \ - ALboolean _r; \ - static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_i))), "Incompatible insertion iterator"); \ - static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_s))), "Incompatible insertion source type"); \ - static_assert(TYPE_CHECK(__typeof(*(_s)), __typeof(*(_e))), "Incompatible iterator sources"); \ - _r = vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)); \ - _r; \ -}) -#else -#define VECTOR_INSERT(_x, _i, _s, _e) (vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e))) -#endif - #define VECTOR_PUSH_BACK(_x, _obj) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), VECTOR_SIZE(_x)+1, AL_FALSE) && \ (((_x)->Data[(_x)->Size++] = (_obj)),AL_TRUE)) #define VECTOR_POP_BACK(_x) ((void)((_x)->Size--)) -- cgit v1.2.3 From 612b24fa9186776cf77b095f723aea5b4b1fc4ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 May 2016 02:10:06 -0700 Subject: Clean up a couple variable names and declarations --- Alc/ALc.c | 8 ++++---- Alc/backends/base.c | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b4582b0e..d41aa0d4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -782,13 +782,13 @@ static ATOMIC(ALCdevice*) DeviceList = ATOMIC_INIT_STATIC(NULL); static almtx_t ListLock; static inline void LockLists(void) { - int lockret = almtx_lock(&ListLock); - assert(lockret == althrd_success); + int ret = almtx_lock(&ListLock); + assert(ret == althrd_success); } static inline void UnlockLists(void) { - int unlockret = almtx_unlock(&ListLock); - assert(unlockret == althrd_success); + int ret = almtx_unlock(&ListLock); + assert(ret == althrd_success); } /************************************************ diff --git a/Alc/backends/base.c b/Alc/backends/base.c index 07c33ba1..ff808f53 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -13,10 +13,9 @@ extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) { - int ret; - self->mDevice = device; - ret = almtx_init(&self->mMutex, almtx_recursive); + int ret = almtx_init(&self->mMutex, almtx_recursive); assert(ret == althrd_success); + self->mDevice = device; } void ALCbackend_Destruct(ALCbackend *self) -- cgit v1.2.3 From d1c4fb6364ce974bd0a4769604b9bba19481e17f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 30 May 2016 05:04:49 -0700 Subject: Don't try to emulate almtx_timedlock --- common/threads.c | 55 ++++++++++++------------------------------------------- 1 file changed, 12 insertions(+), 43 deletions(-) diff --git a/common/threads.c b/common/threads.c index 5a177a2c..1e528b5b 100644 --- a/common/threads.c +++ b/common/threads.c @@ -194,7 +194,8 @@ int althrd_sleep(const struct timespec *ts, struct timespec* UNUSED(rem)) int almtx_init(almtx_t *mtx, int type) { if(!mtx) return althrd_error; - type &= ~(almtx_recursive|almtx_timed); + + type &= ~almtx_recursive; if(type != almtx_plain) return althrd_error; @@ -207,27 +208,10 @@ void almtx_destroy(almtx_t *mtx) DeleteCriticalSection(mtx); } -int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) +int almtx_timedlock(almtx_t* UNUSED(mtx), const struct timespec* UNUSED(ts)) { - int ret; - - if(!mtx || !ts) - return althrd_error; - - while((ret=almtx_trylock(mtx)) == althrd_busy) - { - struct timespec now; - - if(ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000 || - altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - return althrd_error; - if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && now.tv_nsec >= ts->tv_nsec)) - return althrd_timedout; - - althrd_yield(); - } - - return ret; + /* Windows CRITICAL_SECTIONs don't seem to have a timedlock method. */ + return althrd_error; } #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 @@ -600,8 +584,13 @@ int almtx_init(almtx_t *mtx, int type) int ret; if(!mtx) return althrd_error; +#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK if((type&~(almtx_recursive|almtx_timed)) != 0) return althrd_error; +#else + if((type&~almtx_recursive) != 0) + return althrd_error; +#endif type &= ~almtx_timed; if(type == almtx_plain) @@ -637,36 +626,16 @@ void almtx_destroy(almtx_t *mtx) int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) { - int ret; - #ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK - ret = pthread_mutex_timedlock(mtx, ts); + int ret = pthread_mutex_timedlock(mtx, ts); switch(ret) { case 0: return althrd_success; case ETIMEDOUT: return althrd_timedout; case EBUSY: return althrd_busy; } - return althrd_error; -#else - if(!mtx || !ts) - return althrd_error; - - while((ret=almtx_trylock(mtx)) == althrd_busy) - { - struct timespec now; - - if(ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000 || - altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - return althrd_error; - if(now.tv_sec > ts->tv_sec || (now.tv_sec == ts->tv_sec && now.tv_nsec >= ts->tv_nsec)) - return althrd_timedout; - - althrd_yield(); - } - - return ret; #endif + return althrd_error; } int alcnd_init(alcnd_t *cond) -- cgit v1.2.3 From 72d2febccbc670843669494fe5bc052839f54294 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 31 May 2016 07:50:23 -0700 Subject: Don't access the band splitter fields in the processing loops perf shows a 5% drop in relative execution time on the alffplay example with an audio-only file (20% to 15%). Kinda figured the optimizer would handle it better, but I guess not. --- Alc/bformatdec.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index e32053c8..49052cb8 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -34,35 +34,42 @@ static void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, A const ALfloat *input, ALuint count) { ALfloat coeff, d, x; + ALfloat z1, z2; ALuint i; coeff = splitter->coeff*0.5f + 0.5f; + z1 = splitter->lp_z1; + z2 = splitter->lp_z2; for(i = 0;i < count;i++) { x = input[i]; - d = (x - splitter->lp_z1) * coeff; - x = splitter->lp_z1 + d; - splitter->lp_z1 = x + d; + d = (x - z1) * coeff; + x = z1 + d; + z1 = x + d; - d = (x - splitter->lp_z2) * coeff; - x = splitter->lp_z2 + d; - splitter->lp_z2 = x + d; + d = (x - z2) * coeff; + x = z2 + d; + z2 = x + d; lpout[i] = x; } + splitter->lp_z1 = z1; + splitter->lp_z2 = z2; coeff = splitter->coeff; + z1 = splitter->hp_z1; for(i = 0;i < count;i++) { x = input[i]; - d = x - coeff*splitter->hp_z1; - x = splitter->hp_z1 + coeff*d; - splitter->hp_z1 = d; + d = x - coeff*z1; + x = z1 + coeff*d; + z1 = d; hpout[i] = x - lpout[i]; } + splitter->hp_z1 = z1; } -- cgit v1.2.3 From 5e64882be9ad3e3a1552e41befef5a6216f4ecfe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 31 May 2016 10:18:34 -0700 Subject: Use SSE for applying the HQ B-Format decoder matrices --- Alc/bformatdec.c | 56 ++++++++++++++++++++++++++------------------------ Alc/mixer_c.c | 21 +++++++++++++++++++ Alc/mixer_defs.h | 4 ++++ Alc/mixer_sse.c | 25 ++++++++++++++++++++++ OpenAL32/Include/alu.h | 3 +++ 5 files changed, 82 insertions(+), 27 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 49052cb8..a871fb09 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -3,6 +3,7 @@ #include "bformatdec.h" #include "ambdec.h" +#include "mixer_defs.h" #include "alu.h" #include "threads.h" @@ -151,12 +152,27 @@ static const ALfloat CubeMatrixLF[8][MAX_AMBI_COEFFS] = { }; static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; -static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT; -static void init_encoder(void) +static inline MatrixMixerFunc SelectMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_SSE; +#endif + return MixRow_C; +} + +static MatrixMixerFunc MixMatrixRow = MixRow_C; + + +static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT; + +static void init_bformatdec(void) { ALuint i, j; + MixMatrixRow = SelectMixer(); + CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[0]); CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[1]); CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[2]); @@ -226,7 +242,7 @@ typedef struct BFormatDec { BFormatDec *bformatdec_alloc() { - alcall_once(&encoder_inited, init_encoder); + alcall_once(&bformatdec_inited, init_bformatdec); return al_calloc(16, sizeof(BFormatDec)); } @@ -435,20 +451,6 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, } -static void apply_row(ALfloat *out, const ALfloat *mtx, ALfloat (*restrict in)[BUFFERSIZE], ALuint inchans, ALuint todo) -{ - ALuint c, i; - - for(c = 0;c < inchans;c++) - { - ALfloat gain = mtx[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(i = 0;i < todo;i++) - out[i] += in[c][i] * gain; - } -} - void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { ALuint chan, i; @@ -465,10 +467,10 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - apply_row(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF, - dec->NumChannels, SamplesToDo); - apply_row(dec->ChannelMix, dec->MatrixLF[chan], dec->SamplesLF, - dec->NumChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF, + dec->NumChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->MatrixLF[chan], dec->SamplesLF, + dec->NumChannels, SamplesToDo); if(dec->Delay[chan].Length > 0) { @@ -504,8 +506,8 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - apply_row(dec->ChannelMix, dec->MatrixHF[chan], InSamples, - dec->NumChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->MatrixHF[chan], InSamples, + dec->NumChannels, SamplesToDo); if(dec->Delay[chan].Length > 0) { @@ -556,10 +558,10 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B for(k = 0;k < dec->UpSampler.NumChannels;k++) { memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - apply_row(dec->ChannelMix, dec->UpSampler.MatrixHF[k], dec->SamplesHF, - InChannels, SamplesToDo); - apply_row(dec->ChannelMix, dec->UpSampler.MatrixLF[k], dec->SamplesLF, - InChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->UpSampler.MatrixHF[k], dec->SamplesHF, + InChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->UpSampler.MatrixLF[k], dec->SamplesLF, + InChannels, SamplesToDo); for(j = 0;j < dec->NumChannels;j++) { diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index e9d26140..7952ec93 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -167,3 +167,24 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B OutBuffer[c][OutPos+pos] += data[pos]*gain; } } + +/* Basically the inverse of the above. Rather than one input going to multiple + * outputs (each with its own gain), it's multiple inputs (each with its own + * gain) going to one output. This applies one row (vs one column) of a matrix + * transform. And as the matrices are more or less static once set up, no + * stepping is necessary. + */ +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +{ + ALuint c, i; + + for(c = 0;c < InChans;c++) + { + ALfloat gain = Mtx[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < BufferSize;i++) + OutBuffer[i] += data[c][i] * gain; + } +} diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 5db804b1..8d208b9c 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -27,6 +27,8 @@ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ri struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], + ALuint InChans, ALuint BufferSize); /* SSE mixers */ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, @@ -35,6 +37,8 @@ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], + ALuint InChans, ALuint BufferSize); /* SSE resamplers */ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size) diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 942e0453..120ac4a0 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -260,3 +260,28 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) OutBuffer[c][OutPos+pos] += data[pos]*gain; } } + +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +{ + __m128 gain4; + ALuint c; + + for(c = 0;c < InChans;c++) + { + ALuint pos = 0; + ALfloat gain = Mtx[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + gain4 = _mm_set1_ps(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const __m128 val4 = _mm_load_ps(&data[c][pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][pos]*gain; + } +} diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index eb8fb65e..fca60b15 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -170,6 +170,9 @@ typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); +typedef void (*MatrixMixerFunc)(ALfloat *OutBuffer, const ALfloat *Mtx, + ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint BufferSize); typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const MixHrtfParams *hrtfparams, -- cgit v1.2.3 From c63d468d4cc738ead65ff7ebc9cf6afcad400ee1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Jun 2016 05:30:06 -0700 Subject: Use a macro to specify the ambisonic periphonic channel mask --- Alc/bformatdec.c | 2 +- Alc/panning.c | 4 ++-- OpenAL32/Include/alMain.h | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index a871fb09..7da50692 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -310,7 +310,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ratio = 400.0f / (ALfloat)srate; for(i = 0;i < 4;i++) bandsplit_init(&dec->UpSampler.XOver[i], ratio); - if((conf->ChanMask & ~0x831b)) + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { dec->UpSampler.MatrixHF = CubeMatrixHF; dec->UpSampler.MatrixLF = CubeMatrixLF; diff --git a/Alc/panning.c b/Alc/panning.c index 2116e739..6949c565 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -673,7 +673,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) decflags |= BFDF_DistanceComp; - if((conf->ChanMask & ~0x831b)) + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { count = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; @@ -701,7 +701,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin TRACE("Enabling %s-band %s-order%s ambisonic decoder\n", (conf->FreqBands == 1) ? "single" : "dual", (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", - (conf->ChanMask & ~0x831b) ? " periphonic" : "" + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap, decflags); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d7b54310..18aa4df3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -483,10 +483,19 @@ enum RenderMode { /* The maximum number of Ambisonics coefficients. For a given order (o), the * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, - * second-order has 9, and third-order has 16. */ + * second-order has 9, third-order has 16, and fourth-order has 25. */ #define MAX_AMBI_ORDER 3 #define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) +/* A bitmask of ambisonic channels with height information. If none of these + * channels are used/needed, there's no height (e.g. with most surround sound + * speaker setups). This only specifies up to 4th order, which is the highest + * order a 32-bit mask value can specify (a 64-bit mask could handle up to 7th + * order). This is ACN ordering, with bit 0 being ACN 0, etc. + */ +#define AMBI_PERIPHONIC_MASK (0xfe7ce4) + + typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; typedef struct BFChannelConfig { ALfloat Scale; -- cgit v1.2.3 From a16d0b192e9833ae0abd6e1e7ef2305c34705497 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Jun 2016 10:21:16 -0700 Subject: Make a function static --- OpenAL32/Include/alSource.h | 1 - OpenAL32/alSource.c | 13 +++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index bb1e6434..a3e84e0e 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -205,7 +205,6 @@ inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) { return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } -void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context); void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c1824d5b..5cc6c34b 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -47,8 +47,9 @@ extern inline void UnlockSourcesWrite(ALCcontext *context); extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); -static ALvoid InitSourceParams(ALsource *Source); -static ALvoid DeinitSource(ALsource *source); +static void InitSourceParams(ALsource *Source); +static void DeinitSource(ALsource *source); +static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); @@ -2665,7 +2666,7 @@ done: } -static ALvoid InitSourceParams(ALsource *Source) +static void InitSourceParams(ALsource *Source) { ALuint i; @@ -2741,7 +2742,7 @@ static ALvoid InitSourceParams(ALsource *Source) ATOMIC_INIT(&Source->FreeList, NULL); } -static ALvoid DeinitSource(ALsource *source) +static void DeinitSource(ALsource *source) { ALbufferlistitem *BufferList; struct ALsourceProps *props; @@ -2784,7 +2785,7 @@ static ALvoid DeinitSource(ALsource *source) } } -void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context) +static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context) { struct ALsourceProps *props; size_t i; @@ -2825,7 +2826,7 @@ void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context) size_t j; for(j = 0;j < 3;j++) ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j], - almemory_order_relaxed); + almemory_order_relaxed); } ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed); -- cgit v1.2.3 From b7da69510c85b776ba119d69c4c74aa38d412594 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Jun 2016 23:39:13 -0700 Subject: Implement a Neon-enhanced MixRow --- Alc/bformatdec.c | 4 ++++ Alc/mixer_defs.h | 2 ++ Alc/mixer_neon.c | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 7da50692..9ebaba27 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -158,6 +158,10 @@ static inline MatrixMixerFunc SelectMixer(void) #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) return MixRow_SSE; +#endif +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_Neon; #endif return MixRow_C; } diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 8d208b9c..8b934c58 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -80,5 +80,7 @@ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], + ALuint InChans, ALuint BufferSize); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 96936ef5..073f62c8 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -118,3 +118,28 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer OutBuffer[c][OutPos+pos] += data[pos]*gain; } } + +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +{ + float32x4_t gain4; + ALuint c; + + for(c = 0;c < InChans;c++) + { + ALuint pos = 0; + ALfloat gain = Mtx[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + gain4 = vdupq_n_f32(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const float32x4_t val4 = vld1q_f32(&data[c][pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][pos]*gain; + } +} -- cgit v1.2.3 From ce676ab70a6b4c46869e4fa13e14b4da7ba6c008 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Jun 2016 05:46:29 -0700 Subject: Remove some unnecessary volatile keywords --- OpenAL32/Include/alAuxEffectSlot.h | 4 +-- OpenAL32/Include/alSource.h | 62 +++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 8d2fc3d7..034ac217 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -86,8 +86,8 @@ struct ALeffectslotProps { typedef struct ALeffectslot { - volatile ALfloat Gain; - volatile ALboolean AuxSendAuto; + ALfloat Gain; + ALboolean AuxSendAuto; struct { ALenum Type; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index a3e84e0e..49bda7e4 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -101,40 +101,40 @@ struct ALsourceProps { typedef struct ALsource { /** Source properties. */ - volatile ALfloat Pitch; - volatile ALfloat Gain; - volatile ALfloat OuterGain; - volatile ALfloat MinGain; - volatile ALfloat MaxGain; - volatile ALfloat InnerAngle; - volatile ALfloat OuterAngle; - volatile ALfloat RefDistance; - volatile ALfloat MaxDistance; - volatile ALfloat RollOffFactor; - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; - volatile ALfloat Direction[3]; - volatile ALfloat Orientation[2][3]; - volatile ALboolean HeadRelative; - volatile ALboolean Looping; - volatile enum DistanceModel DistanceModel; - volatile ALboolean DirectChannels; - - volatile ALboolean DryGainHFAuto; - volatile ALboolean WetGainAuto; - volatile ALboolean WetGainHFAuto; - volatile ALfloat OuterGainHF; - - volatile ALfloat AirAbsorptionFactor; - volatile ALfloat RoomRolloffFactor; - volatile ALfloat DopplerFactor; + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RollOffFactor; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Direction[3]; + ALfloat Orientation[2][3]; + ALboolean HeadRelative; + ALboolean Looping; + enum DistanceModel DistanceModel; + ALboolean DirectChannels; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; /* NOTE: Stereo pan angles are specified in radians, counter-clockwise * rather than clockwise. */ - volatile ALfloat StereoPan[2]; + ALfloat StereoPan[2]; - volatile ALfloat Radius; + ALfloat Radius; /** Direct filter and auxiliary send info. */ struct { @@ -161,10 +161,10 @@ typedef struct ALsource { ALenum OffsetType; /** Source type (static, streaming, or undetermined) */ - volatile ALint SourceType; + ALint SourceType; /** Source state (initial, playing, paused, or stopped) */ - volatile ALenum state; + ALenum state; ALenum new_state; /** -- cgit v1.2.3 From e38a81c5b62a350e448f31fd482d92c61fd84c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Jun 2016 06:55:54 -0700 Subject: Improve the filter processing function --- Alc/mixer_c.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 7952ec93..f741e28f 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -96,8 +96,41 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, A void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples) { ALuint i; - for(i = 0;i < numsamples;i++) - *(dst++) = ALfilterState_processSingle(filter, *(src++)); + if(numsamples > 1) + { + dst[0] = filter->input_gain * src[0] + + filter->b1 * filter->x[0] + + filter->b2 * filter->x[1] - + filter->a1 * filter->y[0] - + filter->a2 * filter->y[1]; + dst[1] = filter->input_gain * src[1] + + filter->b1 * src[0] + + filter->b2 * filter->x[0] - + filter->a1 * dst[0] - + filter->a2 * filter->y[0]; + for(i = 2;i < numsamples;i++) + dst[i] = filter->input_gain * src[i] + + filter->b1 * src[i-1] + + filter->b2 * src[i-2] - + filter->a1 * dst[i-1] - + filter->a2 * dst[i-2]; + filter->x[0] = src[i-1]; + filter->x[1] = src[i-2]; + filter->y[0] = dst[i-1]; + filter->y[1] = dst[i-2]; + } + else if(numsamples == 1) + { + dst[0] = filter->input_gain * src[0] + + filter->b1 * filter->x[0] + + filter->b2 * filter->x[1] - + filter->a1 * filter->y[0] - + filter->a2 * filter->y[1]; + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = dst[0]; + } } -- cgit v1.2.3 From 2c402e1ab524532020b36426375098c39df0e9d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Jun 2016 09:40:30 -0700 Subject: Add property queries to get the device latency with the clock --- Alc/ALc.c | 43 ++++++++++++++++++++++++++++++++----------- OpenAL32/Include/alMain.h | 2 ++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d41aa0d4..7f42cb72 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2902,6 +2902,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, } else /* render device */ { + ClockLatency clock; ALuint64 basecount; ALuint samplecount; ALuint refcount; @@ -2909,16 +2910,15 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, switch(pname) { case ALC_ATTRIBUTES_SIZE: - *values = 19; + *values = 21; break; case ALC_ALL_ATTRIBUTES: - if(size < 19) + if(size < 21) alcSetError(device, ALC_INVALID_VALUE); else { - int i = 0; - + i = 0; almtx_lock(&device->BackendLock); values[i++] = ALC_FREQUENCY; values[i++] = device->Frequency; @@ -2955,14 +2955,12 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->Hrtf_Status; + clock = V0(device->Backend,getClockLatency)(); values[i++] = ALC_DEVICE_CLOCK_SOFT; - do { - while(((refcount=ReadRef(&device->MixCount))&1) != 0) - althrd_yield(); - basecount = device->ClockBase; - samplecount = device->SamplesDone; - } while(refcount != ReadRef(&device->MixCount)); - values[i++] = basecount + (samplecount*DEVICE_CLOCK_RES/device->Frequency); + values[i++] = clock.ClockTime; + + values[i++] = ALC_DEVICE_LATENCY_SOFT; + values[i++] = clock.Latency; almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -2981,6 +2979,29 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, almtx_unlock(&device->BackendLock); break; + case ALC_DEVICE_LATENCY_SOFT: + { + almtx_lock(&device->BackendLock); + clock = V0(device->Backend,getClockLatency)(); + almtx_unlock(&device->BackendLock); + *values = clock.Latency; + } + break; + + case ALC_DEVICE_CLOCK_LATENCY_SOFT: + if(size < 2) + alcSetError(device, ALC_INVALID_VALUE); + else + { + ClockLatency clock; + almtx_lock(&device->BackendLock); + clock = V0(device->Backend,getClockLatency)(); + almtx_unlock(&device->BackendLock); + values[0] = clock.ClockTime; + values[1] = clock.Latency; + } + break; + default: ivals = malloc(size * sizeof(ALCint)); size = GetIntegerv(device, pname, size, ivals); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 18aa4df3..ed4e56f2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -46,6 +46,8 @@ typedef int64_t ALCint64SOFT; typedef uint64_t ALCuint64SOFT; #define ALC_DEVICE_CLOCK_SOFT 0x1600 +#define ALC_DEVICE_LATENCY_SOFT 0x1601 +#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); #ifdef AL_ALEXT_PROTOTYPES ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -- cgit v1.2.3 From b2041a5ddfec78bbde1c63c8674614455ee31f93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Jun 2016 08:40:06 -0700 Subject: Only define 8 HRTF filter states and params for the device It will only be used with a cube channel setup, so there's no need to have one for every possible output channel. --- OpenAL32/Include/alMain.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ed4e56f2..cce2a17d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -570,8 +570,8 @@ struct ALCdevice_struct ALCenum Hrtf_Status; /* HRTF filter state for dry buffer content */ - HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS]; - HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS]; + HrtfState Hrtf_State[8]; + HrtfParams Hrtf_Params[8]; ALuint Hrtf_Offset; /* UHJ encoder state */ -- cgit v1.2.3 From 0477d6159974837ee01bbc7c74a65a3be5794cdd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Jun 2016 10:45:44 -0700 Subject: Look in the executable's dir for another config file On Windows it'll look for alsoft.ini, and elsewhere is alsoft.conf. This applies after the user-local settings and before ALSOFT_CONF. --- Alc/alcConfig.c | 32 +++++++++++++++++++ Alc/compat.h | 4 +++ Alc/helpers.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c index 6fc9db33..f83ffd94 100644 --- a/Alc/alcConfig.c +++ b/Alc/alcConfig.c @@ -313,6 +313,7 @@ void ReadALConfig(void) { WCHAR buffer[PATH_MAX]; const WCHAR *str; + al_string ppath; FILE *f; if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) @@ -331,6 +332,19 @@ void ReadALConfig(void) al_string_deinit(&filepath); } + ppath = GetProcPath(); + if(!al_string_empty(ppath)) + { + al_string_append_cstr(&ppath, "\\alsoft.ini"); + TRACE("Loading config %s...\n", al_string_get_cstr(ppath)); + f = al_fopen(al_string_get_cstr(ppath), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) { al_string filepath = AL_STRING_INIT_STATIC(); @@ -345,12 +359,15 @@ void ReadALConfig(void) } al_string_deinit(&filepath); } + + al_string_deinit(&ppath); } #else void ReadALConfig(void) { char buffer[PATH_MAX]; const char *str; + al_string ppath; FILE *f; str = "/etc/openal/alsoft.conf"; @@ -430,6 +447,19 @@ void ReadALConfig(void) } } + ppath = GetProcPath(); + if(!al_string_empty(ppath)) + { + al_string_append_cstr(&ppath, "/alsoft.conf"); + TRACE("Loading config %s...\n", al_string_get_cstr(ppath)); + f = al_fopen(al_string_get_cstr(ppath), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + if((str=getenv("ALSOFT_CONF")) != NULL && *str) { TRACE("Loading config %s...\n", str); @@ -440,6 +470,8 @@ void ReadALConfig(void) fclose(f); } } + + al_string_deinit(&ppath); } #endif diff --git a/Alc/compat.h b/Alc/compat.h index f54ef9ce..0443692a 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -1,6 +1,8 @@ #ifndef AL_COMPAT_H #define AL_COMPAT_H +#include "alstring.h" + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -23,6 +25,8 @@ FILE *al_fopen(const char *fname, const char *mode); #endif +al_string GetProcPath(void); + #ifdef HAVE_DYNLOAD void *LoadLib(const char *name); void CloseLib(void *handle); diff --git a/Alc/helpers.c b/Alc/helpers.c index e1cd6be1..bd345b6a 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -321,6 +321,57 @@ static int StringSortCompare(const void *str1, const void *str2) #ifdef _WIN32 +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *ret = NULL; + while(*str) + { + if(*str == ch) + ret = str; + ++str; + } + return ret; +} + +al_string GetProcPath(void) +{ + al_string ret = AL_STRING_INIT_STATIC(); + WCHAR *pathname, *sep; + DWORD pathlen; + DWORD len; + + pathlen = 256; + pathname = malloc(pathlen * sizeof(pathname[0])); + while(pathlen > 0 && (len=GetModuleFileNameW(NULL, pathname, pathlen)) == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = malloc(pathlen * sizeof(pathname[0])); + } + if(len == 0) + { + free(pathname); + ERR("Failed to get process name: error %lu\n", GetLastError()); + return ret; + } + + pathname[len] = 0; + if((sep = strrchrW(pathname, '\\'))) + { + WCHAR *sep2 = strrchrW(pathname, '/'); + if(sep2) *sep2 = 0; + else *sep = 0; + } + else if((sep = strrchrW(pathname, '/'))) + *sep = 0; + al_string_copy_wcstr(&ret, pathname); + free(pathname); + + TRACE("Got: %s\n", al_string_get_cstr(ret)); + return ret; +} + + static WCHAR *FromUTF8(const char *str) { WCHAR *out = NULL; @@ -549,6 +600,52 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) #else +al_string GetProcPath(void) +{ + al_string ret = AL_STRING_INIT_STATIC(); + const char *fname; + char *pathname, *sep; + size_t pathlen; + ssize_t len; + + pathlen = 256; + pathname = malloc(pathlen); + + fname = "/proc/self/exe"; + len = readlink(fname, pathname, pathlen); + if(len == -1 && errno == ENOENT) + { + fname = "/proc/self/file"; + len = readlink(fname, pathname, pathlen); + } + + while(len > 0 && (size_t)len == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = malloc(pathlen); + len = readlink(fname, pathname, pathlen); + } + if(len <= 0) + { + free(pathname); + ERR("Failed to link %s: %s\n", fname, strerror(errno)); + return ret; + } + + pathname[len] = 0; + sep = strrchr(pathname, '/'); + if(sep) + al_string_copy_range(&ret, pathname, sep); + else + al_string_copy_cstr(&ret, pathname); + free(pathname); + + TRACE("Got: %s\n", al_string_get_cstr(ret)); + return ret; +} + + #ifdef HAVE_DLFCN_H void *LoadLib(const char *name) -- cgit v1.2.3 From a49db89d7ac60e2f184bf5696024f5b0dde08328 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Jun 2016 16:11:50 -0700 Subject: Remove an IN_IDE_PARSER hack Not all IDE parsers necessarily choke on restrict, and even those that do can probably have their own configuration to define macros that can hide the parsing errors caused by it. --- config.h.in | 6 ------ 1 file changed, 6 deletions(-) diff --git a/config.h.in b/config.h.in index b59226ee..41fa3b61 100644 --- a/config.h.in +++ b/config.h.in @@ -5,12 +5,6 @@ /* 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} -- cgit v1.2.3 From 697ee19f71183d7da87e58ca89d67830b30f9eb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Jun 2016 11:19:33 -0700 Subject: Rename MaxNoOfSources for consistency --- Alc/ALc.c | 30 +++++++++++++++--------------- OpenAL32/Include/alMain.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7f42cb72..ca73bd57 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1721,10 +1721,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - if(numStereo > device->MaxNoOfSources) - numStereo = device->MaxNoOfSources; + if(numStereo > device->SourcesMax) + numStereo = device->SourcesMax; - numMono = device->MaxNoOfSources - numStereo; + numMono = device->SourcesMax - numStereo; } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) @@ -1806,10 +1806,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - if(numStereo > device->MaxNoOfSources) - numStereo = device->MaxNoOfSources; + if(numStereo > device->SourcesMax) + numStereo = device->SourcesMax; - numMono = device->MaxNoOfSources - numStereo; + numMono = device->SourcesMax - numStereo; } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) @@ -2275,7 +2275,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); RWLockInit(&Context->PropLock); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); + InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); //Set globals @@ -3375,7 +3375,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->ClockBase = 0; device->SamplesDone = 0; - device->MaxNoOfSources = 256; + device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 4; device->NumAuxSends = MAX_SENDS; @@ -3480,8 +3480,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) device->UpdateSize = (device->UpdateSize+3)&~3; - ConfigValueUInt(deviceName, NULL, "sources", &device->MaxNoOfSources); - if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; + ConfigValueUInt(deviceName, NULL, "sources", &device->SourcesMax); + if(device->SourcesMax == 0) device->SourcesMax = 256; ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; @@ -3490,7 +3490,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; device->NumStereoSources = 1; - device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; // Find a playback device to open if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) @@ -3835,7 +3835,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->ClockBase = 0; device->SamplesDone = 0; - device->MaxNoOfSources = 256; + device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 4; device->NumAuxSends = MAX_SENDS; @@ -3862,8 +3862,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FmtType = DevFmtTypeDefault; device->IsHeadphones = AL_FALSE; - ConfigValueUInt(NULL, NULL, "sources", &device->MaxNoOfSources); - if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; + ConfigValueUInt(NULL, NULL, "sources", &device->SourcesMax); + if(device->SourcesMax == 0) device->SourcesMax = 256; ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; @@ -3872,7 +3872,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; device->NumStereoSources = 1; - device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; + device->NumMonoSources = device->SourcesMax - device->NumStereoSources; // Open the "backend" V(device->Backend,open)("Loopback"); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index cce2a17d..99407fa8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -546,7 +546,7 @@ struct ALCdevice_struct ATOMIC(ALCenum) LastError; // Maximum number of sources that can be created - ALuint MaxNoOfSources; + ALuint SourcesMax; // Maximum number of slots that can be created ALuint AuxiliaryEffectSlotMax; -- cgit v1.2.3 From 80da138d7f78ddb5a91b5644001d2aa1da4f7a61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 16 Jun 2016 18:22:01 -0700 Subject: Ensure voices has been updated once before mixing them Sometimes the mixer is temporarily prevented from applying updates, when multiple sources need to be updated simultaneously for example, but does not prevent mixing. If the mixer runs during that time and a voice was just started, it would've mixed the voice without any internal properties being set for it. --- Alc/ALu.c | 3 ++- OpenAL32/alSource.c | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3ba068a2..77852805 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1460,8 +1460,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { + ALboolean IsVoiceInit = (voice->Step > 0); source = voice->Source; - if(source && source->state == AL_PLAYING) + if(source && source->state == AL_PLAYING && IsVoiceInit) MixSource(voice, source, device, SamplesToDo); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 5cc6c34b..e79f0fc3 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2986,10 +2986,17 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Source = Source; } - /* Clear previous samples if playback is discontinuous. */ if(discontinuity) + { + /* Clear previous samples if playback is discontinuous. */ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + /* Clear the stepping value so the mixer knows not to mix this + * until the update gets applied. + */ + voice->Step = 0; + } + voice->Moving = AL_FALSE; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { -- cgit v1.2.3 From f0cbcdc928b6a0615199dde56f3b7f0ac31cc6cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Jul 2016 09:18:49 -0700 Subject: Use al_malloc/al_free for the UIntMap array --- common/uintmap.c | 24 ++++++++++++++++-------- include/uintmap.h | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/common/uintmap.c b/common/uintmap.c index d5e7c9ae..041f46c1 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -6,6 +6,8 @@ #include #include +#include "almalloc.h" + extern inline void LockUIntMapRead(UIntMap *map); extern inline void UnlockUIntMapRead(UIntMap *map); @@ -17,7 +19,7 @@ void InitUIntMap(UIntMap *map, ALsizei limit) { map->array = NULL; map->size = 0; - map->maxsize = 0; + map->capacity = 0; map->limit = limit; RWLockInit(&map->lock); } @@ -25,10 +27,10 @@ void InitUIntMap(UIntMap *map, ALsizei limit) void ResetUIntMap(UIntMap *map) { WriteLock(&map->lock); - free(map->array); + al_free(map->array); map->array = NULL; map->size = 0; - map->maxsize = 0; + map->capacity = 0; WriteUnlock(&map->lock); } @@ -62,21 +64,27 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) return AL_OUT_OF_MEMORY; } - if(map->size == map->maxsize) + if(map->size == map->capacity) { ALvoid *temp = NULL; ALsizei newsize; - newsize = (map->maxsize ? (map->maxsize<<1) : 4); - if(newsize >= map->maxsize) - temp = realloc(map->array, newsize*sizeof(map->array[0])); + newsize = (map->capacity ? (map->capacity<<1) : 4); + if(map->limit > 0 && newsize > map->limit) + newsize = map->limit; + if(newsize > map->capacity) + temp = al_malloc(16, newsize * sizeof(map->array[0])); if(!temp) { WriteUnlock(&map->lock); return AL_OUT_OF_MEMORY; } + + if(map->array) + memcpy(temp, map->array, map->size*sizeof(map->array[0])); + al_free(map->array); map->array = temp; - map->maxsize = newsize; + map->capacity = newsize; } if(pos < map->size) diff --git a/include/uintmap.h b/include/uintmap.h index c41c20ad..e7c3f93d 100644 --- a/include/uintmap.h +++ b/include/uintmap.h @@ -14,7 +14,7 @@ typedef struct UIntMap { ALvoid *value; } *array; ALsizei size; - ALsizei maxsize; + ALsizei capacity; ALsizei limit; RWLock lock; } UIntMap; -- cgit v1.2.3 From 8f4d6c48ce6621e2e2b79ada781b9e3dfc9ed38c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Jul 2016 20:35:32 -0700 Subject: Use separate arrays for UIntMap keys and values --- Alc/ALc.c | 6 +-- OpenAL32/alAuxEffectSlot.c | 4 +- OpenAL32/alBuffer.c | 4 +- OpenAL32/alEffect.c | 4 +- OpenAL32/alFilter.c | 4 +- OpenAL32/alSource.c | 4 +- common/uintmap.c | 109 ++++++++++++++++++++++++++++----------------- include/uintmap.h | 10 ++--- 8 files changed, 87 insertions(+), 58 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ca73bd57..83cd59f5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1580,7 +1580,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) V0(device->Backend,lock)(); for(pos = 0;pos < context->SourceMap.size;pos++) { - ALsource *Source = context->SourceMap.array[pos].value; + ALsource *Source = context->SourceMap.values[pos]; ALenum new_state; if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && @@ -2064,7 +2064,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) LockUIntMapRead(&context->EffectSlotMap); for(pos = 0;pos < context->EffectSlotMap.size;pos++) { - ALeffectslot *slot = context->EffectSlotMap.array[pos].value; + ALeffectslot *slot = context->EffectSlotMap.values[pos]; ALeffectState *state = slot->Effect.State; state->OutBuffer = device->Dry.Buffer; @@ -2084,7 +2084,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) LockUIntMapRead(&context->SourceMap); for(pos = 0;pos < context->SourceMap.size;pos++) { - ALsource *source = context->SourceMap.array[pos].value; + ALsource *source = context->SourceMap.values[pos]; ALuint s = device->NumAuxSends; while(s < MAX_SENDS) { diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index b0fd3385..bbaf0668 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -660,8 +660,8 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) ALsizei pos; for(pos = 0;pos < Context->EffectSlotMap.size;pos++) { - ALeffectslot *temp = Context->EffectSlotMap.array[pos].value; - Context->EffectSlotMap.array[pos].value = NULL; + ALeffectslot *temp = Context->EffectSlotMap.values[pos]; + Context->EffectSlotMap.values[pos] = NULL; DeinitEffectSlot(temp); diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 193ab44f..c52924a9 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1402,8 +1402,8 @@ ALvoid ReleaseALBuffers(ALCdevice *device) ALsizei i; for(i = 0;i < device->BufferMap.size;i++) { - ALbuffer *temp = device->BufferMap.array[i].value; - device->BufferMap.array[i].value = NULL; + ALbuffer *temp = device->BufferMap.values[i]; + device->BufferMap.values[i] = NULL; al_free(temp->data); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 5a036091..1057f3c1 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -375,8 +375,8 @@ ALvoid ReleaseALEffects(ALCdevice *device) ALsizei i; for(i = 0;i < device->EffectMap.size;i++) { - ALeffect *temp = device->EffectMap.array[i].value; - device->EffectMap.array[i].value = NULL; + ALeffect *temp = device->EffectMap.values[i]; + device->EffectMap.values[i] = NULL; // Release effect structure FreeThunkEntry(temp->id); diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 7be3e339..7b96263a 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -636,8 +636,8 @@ ALvoid ReleaseALFilters(ALCdevice *device) ALsizei i; for(i = 0;i < device->FilterMap.size;i++) { - ALfilter *temp = device->FilterMap.array[i].value; - device->FilterMap.array[i].value = NULL; + ALfilter *temp = device->FilterMap.values[i]; + device->FilterMap.values[i] = NULL; // Release filter structure FreeThunkEntry(temp->id); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e79f0fc3..7d34f368 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3373,8 +3373,8 @@ ALvoid ReleaseALSources(ALCcontext *Context) ALsizei pos; for(pos = 0;pos < Context->SourceMap.size;pos++) { - ALsource *temp = Context->SourceMap.array[pos].value; - Context->SourceMap.array[pos].value = NULL; + ALsource *temp = Context->SourceMap.values[pos]; + Context->SourceMap.values[pos] = NULL; DeinitSource(temp); diff --git a/common/uintmap.c b/common/uintmap.c index 041f46c1..d3b51923 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -17,7 +17,8 @@ extern inline void UnlockUIntMapWrite(UIntMap *map); void InitUIntMap(UIntMap *map, ALsizei limit) { - map->array = NULL; + map->keys = NULL; + map->values = NULL; map->size = 0; map->capacity = 0; map->limit = limit; @@ -27,8 +28,9 @@ void InitUIntMap(UIntMap *map, ALsizei limit) void ResetUIntMap(UIntMap *map) { WriteLock(&map->lock); - al_free(map->array); - map->array = NULL; + al_free(map->keys); + map->keys = NULL; + map->values = NULL; map->size = 0; map->capacity = 0; WriteUnlock(&map->lock); @@ -46,17 +48,17 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) while(low < high) { ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) + if(map->keys[mid] < key) low = mid + 1; else high = mid; } - if(map->array[low].key < key) + if(map->keys[low] < key) low++; pos = low; } - if(pos == map->size || map->array[pos].key != key) + if(pos == map->size || map->keys[pos] != key) { if(map->size == map->limit) { @@ -66,34 +68,53 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) if(map->size == map->capacity) { - ALvoid *temp = NULL; - ALsizei newsize; - - newsize = (map->capacity ? (map->capacity<<1) : 4); - if(map->limit > 0 && newsize > map->limit) - newsize = map->limit; - if(newsize > map->capacity) - temp = al_malloc(16, newsize * sizeof(map->array[0])); - if(!temp) + ALuint *keys = NULL; + ALvoid **values; + ALsizei newcap, keylen; + + newcap = (map->capacity ? (map->capacity<<1) : 4); + if(map->limit > 0 && newcap > map->limit) + newcap = map->limit; + if(newcap > map->capacity) + { + /* Round the memory size for keys up to a multiple of the + * pointer size. + */ + keylen = newcap * sizeof(map->keys[0]); + keylen += sizeof(map->values[0]) - 1; + keylen -= keylen%sizeof(map->values[0]); + + keys = al_malloc(16, keylen + newcap*sizeof(map->values[0])); + } + if(!keys) { WriteUnlock(&map->lock); return AL_OUT_OF_MEMORY; } + values = (ALvoid**)((ALbyte*)keys + keylen); - if(map->array) - memcpy(temp, map->array, map->size*sizeof(map->array[0])); - al_free(map->array); - map->array = temp; - map->capacity = newsize; + if(map->keys) + { + memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); + memcpy(values, map->values, map->size*sizeof(map->values[0])); + } + al_free(map->keys); + map->keys = keys; + map->values = values; + map->capacity = newcap; } if(pos < map->size) - memmove(&map->array[pos+1], &map->array[pos], - (map->size-pos)*sizeof(map->array[0])); + { + memmove(&map->keys[pos+1], &map->keys[pos], + (map->size-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos+1], &map->values[pos], + (map->size-pos)*sizeof(map->values[0])); + } map->size++; } - map->array[pos].key = key; - map->array[pos].value = value; + map->keys[pos] = key; + map->values[pos] = value; WriteUnlock(&map->lock); return AL_NO_ERROR; @@ -110,17 +131,21 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) while(low < high) { ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) + if(map->keys[mid] < key) low = mid + 1; else high = mid; } - if(map->array[low].key == key) + if(map->keys[low] == key) { - ptr = map->array[low].value; + ptr = map->values[low]; if(low < map->size-1) - memmove(&map->array[low], &map->array[low+1], - (map->size-1-low)*sizeof(map->array[0])); + { + memmove(&map->keys[low], &map->keys[low+1], + (map->size-1-low)*sizeof(map->keys[0])); + memmove(&map->values[low], &map->values[low+1], + (map->size-1-low)*sizeof(map->values[0])); + } map->size--; } } @@ -137,17 +162,21 @@ ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key) while(low < high) { ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) + if(map->keys[mid] < key) low = mid + 1; else high = mid; } - if(map->array[low].key == key) + if(map->keys[low] == key) { - ALvoid *ptr = map->array[low].value; + ALvoid *ptr = map->values[low]; if(low < map->size-1) - memmove(&map->array[low], &map->array[low+1], - (map->size-1-low)*sizeof(map->array[0])); + { + memmove(&map->keys[low], &map->keys[low+1], + (map->size-1-low)*sizeof(map->keys[0])); + memmove(&map->values[low], &map->values[low+1], + (map->size-1-low)*sizeof(map->values[0])); + } map->size--; return ptr; } @@ -166,13 +195,13 @@ ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) while(low < high) { ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) + if(map->keys[mid] < key) low = mid + 1; else high = mid; } - if(map->array[low].key == key) - ptr = map->array[low].value; + if(map->keys[low] == key) + ptr = map->values[low]; } ReadUnlock(&map->lock); return ptr; @@ -187,13 +216,13 @@ ALvoid *LookupUIntMapKeyNoLock(UIntMap *map, ALuint key) while(low < high) { ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) + if(map->keys[mid] < key) low = mid + 1; else high = mid; } - if(map->array[low].key == key) - return map->array[low].value; + if(map->keys[low] == key) + return map->values[low]; } return NULL; } diff --git a/include/uintmap.h b/include/uintmap.h index e7c3f93d..acb2749a 100644 --- a/include/uintmap.h +++ b/include/uintmap.h @@ -9,16 +9,16 @@ extern "C" { #endif typedef struct UIntMap { - struct { - ALuint key; - ALvoid *value; - } *array; + ALuint *keys; + /* Shares memory with keys. */ + ALvoid **values; + ALsizei size; ALsizei capacity; ALsizei limit; RWLock lock; } UIntMap; -#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } +#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } #define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(~0) void InitUIntMap(UIntMap *map, ALsizei limit); -- cgit v1.2.3 From d340d50d49287725802eae02771f2776f49f16e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Jul 2016 14:18:17 -0700 Subject: Remove the VirtOut buffer alias --- Alc/ALc.c | 24 ++++++++++-------------- Alc/ALu.c | 21 +++++++++++---------- OpenAL32/Include/alMain.h | 9 +++------ 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 83cd59f5..c50f0b25 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1871,8 +1871,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Dry.Buffer); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; @@ -2012,15 +2012,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) { - device->VirtOut.Buffer = device->Dry.Buffer; - device->VirtOut.NumChannels = device->Dry.NumChannels; device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); } else { - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; device->RealOut.Buffer = device->Dry.Buffer; device->RealOut.NumChannels = device->Dry.NumChannels; } @@ -2180,8 +2176,8 @@ static ALCvoid FreeDevice(ALCdevice *device) al_free(device->Dry.Buffer); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; @@ -3365,8 +3361,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; @@ -3629,8 +3625,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; @@ -3825,8 +3821,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; - device->VirtOut.Buffer = NULL; - device->VirtOut.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; diff --git a/Alc/ALu.c b/Alc/ALu.c index 77852805..ac9057b7 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1421,10 +1421,11 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { SamplesToDo = minu(size, BUFFERSIZE); - for(c = 0;c < device->VirtOut.NumChannels;c++) - memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - for(c = 0;c < device->RealOut.NumChannels;c++) - memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + for(c = 0;c < device->Dry.NumChannels;c++) + memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Dry.Buffer != device->RealOut.Buffer) + for(c = 0;c < device->RealOut.NumChannels;c++) + memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); if(device->Dry.Buffer != device->FOAOut.Buffer) for(c = 0;c < device->FOAOut.NumChannels;c++) memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); @@ -1508,12 +1509,12 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALuint irsize = GetHrtfIrSize(device->Hrtf); MixHrtfParams hrtfparams; memset(&hrtfparams, 0, sizeof(hrtfparams)); - for(c = 0;c < device->VirtOut.NumChannels;c++) + for(c = 0;c < device->Dry.NumChannels;c++) { hrtfparams.Current = &device->Hrtf_Params[c]; hrtfparams.Target = &device->Hrtf_Params[c]; HrtfMix(device->RealOut.Buffer, lidx, ridx, - device->VirtOut.Buffer[c], 0, device->Hrtf_Offset, 0, + device->Dry.Buffer[c], 0, device->Hrtf_Offset, 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo ); } @@ -1522,14 +1523,14 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } else if(device->AmbiDecoder) { - if(device->VirtOut.Buffer != device->FOAOut.Buffer) + if(device->Dry.Buffer != device->FOAOut.Buffer) bformatdec_upSample(device->AmbiDecoder, - device->VirtOut.Buffer, device->FOAOut.Buffer, + device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, SamplesToDo ); bformatdec_process(device->AmbiDecoder, device->RealOut.Buffer, device->RealOut.NumChannels, - device->VirtOut.Buffer, SamplesToDo + device->Dry.Buffer, SamplesToDo ); } else @@ -1543,7 +1544,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) /* Encode to stereo-compatible 2-channel UHJ output. */ EncodeUhj2(device->Uhj_Encoder, device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->VirtOut.Buffer, SamplesToDo + device->Dry.Buffer, SamplesToDo ); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 99407fa8..532f7947 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -630,12 +630,9 @@ struct ALCdevice_struct ALuint NumChannels; } FOAOut; - /* Virtual output, to be post-processed to the real output. */ - struct { - ALfloat (*Buffer)[BUFFERSIZE]; - ALuint NumChannels; - } VirtOut; - /* "Real" output, which will be written to the device buffer. */ + /* "Real" output, which will be written to the device buffer. May alias the + * dry buffer. + */ struct { enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; -- cgit v1.2.3 From d096e183a8d1e20ed2a71d502897394a14bf8404 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Jul 2016 09:52:42 -0700 Subject: Remove a slightly outdated comment --- OpenAL32/Include/alMain.h | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 532f7947..e1411b83 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -612,7 +612,6 @@ struct ALCdevice_struct */ ALuint CoeffCount; - /* Dry buffer will be aliased by the virtual or real output. */ ALfloat (*Buffer)[BUFFERSIZE]; ALuint NumChannels; } Dry; -- cgit v1.2.3 From b495d80f5624328569bd0d8b9478927c0fc32100 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Jul 2016 13:33:40 -0700 Subject: Avoid using memcpy to copy a single struct --- Alc/panning.c | 8 ++++---- OpenAL32/Include/alMain.h | 26 ++++++++++++-------------- OpenAL32/alAuxEffectSlot.c | 6 +++--- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 6949c565..c7bc82f8 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -581,7 +581,7 @@ static void InitPanning(ALCdevice *device) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; } else @@ -708,7 +708,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin if(bformatdec_getOrder(device->AmbiDecoder) < 2) { - memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; } else @@ -763,7 +763,7 @@ static void InitHrtfPanning(ALCdevice *device) &device->Dry.NumChannels, AL_TRUE); device->Dry.CoeffCount = 4; - memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; for(i = 0;i < device->Dry.NumChannels;i++) @@ -788,7 +788,7 @@ static void InitUhjPanning(ALCdevice *device) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi)); + device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e1411b83..13aadef5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -504,6 +504,13 @@ typedef struct BFChannelConfig { ALuint Index; } BFChannelConfig; +typedef union AmbiConfig { + /* Ambisonic coefficients for mixing to the dry buffer. */ + ChannelConfig Coeffs[MAX_OUTPUT_CHANNELS]; + /* Coefficient channel mapping for mixing to the dry buffer. */ + BFChannelConfig Map[MAX_OUTPUT_CHANNELS]; +} AmbiConfig; + #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1<Effect.Type = effect->type; - memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); + EffectSlot->Effect.Props = effect->Props; } EffectSlot->Effect.State = State; @@ -519,7 +519,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e } else if(effect) { - memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); + EffectSlot->Effect.Props = effect->Props; UpdateEffectSlotProps(EffectSlot); } @@ -630,7 +630,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed); ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed); - memcpy(&props->Props, &slot->Effect.Props, sizeof(props->Props)); + props->Props = slot->Effect.Props; /* Swap out any stale effect state object there may be in the container, to * delete it. */ -- cgit v1.2.3 From 7ec89b4b6e787c9bb0b73aea7f736351f1b0bfca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Jul 2016 10:26:42 -0700 Subject: Avoid function calls to get the HRTF sample rate and IR size --- Alc/ALc.c | 6 +++--- Alc/ALu.c | 2 +- Alc/hrtf.c | 25 ------------------------- Alc/hrtf.h | 18 ++++++++++++++---- Alc/mixer.c | 2 +- Alc/panning.c | 4 ++-- 6 files changed, 21 insertions(+), 36 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c50f0b25..bc6304d7 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1906,9 +1906,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->FmtChans = DevFmtStereo; if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) - device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, hrtf_id).hrtf); + device->Frequency = VECTOR_ELEM(device->Hrtf_List, hrtf_id).hrtf->sampleRate; else - device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, 0).hrtf); + device->Frequency = VECTOR_ELEM(device->Hrtf_List, 0).hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; } else @@ -1937,7 +1937,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++) { const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf_List, i).hrtf; - if(GetHrtfSampleRate(hrtf) == device->Frequency) + if(hrtf->sampleRate == device->Frequency) break; } } diff --git a/Alc/ALu.c b/Alc/ALu.c index ac9057b7..ac958d41 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1506,7 +1506,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(lidx != -1 && ridx != -1) { HrtfMixerFunc HrtfMix = SelectHrtfMixer(); - ALuint irsize = GetHrtfIrSize(device->Hrtf); + ALuint irsize = device->Hrtf->irSize; MixHrtfParams hrtfparams; memset(&hrtfparams, 0, sizeof(hrtfparams)); for(c = 0;c < device->Dry.NumChannels;c++) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 1f972f87..eb586d38 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -44,20 +44,6 @@ #define MIN_AZ_COUNT (1) #define MAX_AZ_COUNT (128) -struct Hrtf { - ALuint sampleRate; - ALuint irSize; - ALubyte evCount; - - const ALubyte *azCount; - const ALushort *evOffset; - const ALshort *coeffs; - const ALubyte *delays; - - const char *filename; - struct Hrtf *next; -}; - static const ALchar magicMarker00[8] = "MinPHR00"; static const ALchar magicMarker01[8] = "MinPHR01"; @@ -696,17 +682,6 @@ void FreeHrtfList(vector_HrtfEntry *list) } -ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf) -{ - return Hrtf->sampleRate; -} - -ALuint GetHrtfIrSize(const struct Hrtf *Hrtf) -{ - return Hrtf->irSize; -} - - void FreeHrtfs(void) { struct Hrtf *Hrtf = LoadedHrtfs; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index e8a127c7..e9f04d49 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -6,7 +6,20 @@ #include "alstring.h" -struct Hrtf; + +struct Hrtf { + ALuint sampleRate; + ALuint irSize; + ALubyte evCount; + + const ALubyte *azCount; + const ALushort *evOffset; + const ALshort *coeffs; + const ALubyte *delays; + + const char *filename; + struct Hrtf *next; +}; typedef struct HrtfEntry { al_string name; @@ -27,9 +40,6 @@ void FreeHrtfs(void); vector_HrtfEntry EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_HrtfEntry *list); -ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf); -ALuint GetHrtfIrSize(const struct Hrtf *Hrtf); - void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); #endif /* ALC_HRTF_H */ diff --git a/Alc/mixer.c b/Alc/mixer.c index 1ee422be..094d3768 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -393,7 +393,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Looping = voice->Looping; increment = voice->Step; - IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0); + IrSize = (Device->Hrtf ? Device->Hrtf->irSize : 0); Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : ResampleSamples); diff --git a/Alc/panning.c b/Alc/panning.c index c7bc82f8..bfdd47e2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -922,7 +922,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) { const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + if(entry->hrtf->sampleRate == device->Frequency) { device->Hrtf = entry->hrtf; al_string_copy(&device->Hrtf_Name, entry->name); @@ -932,7 +932,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) { const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); - if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + if(entry->hrtf->sampleRate == device->Frequency) { device->Hrtf = entry->hrtf; al_string_copy(&device->Hrtf_Name, entry->name); -- cgit v1.2.3 From 745cad52315cac31f6ecdb131f710ad60f4f8cac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Jul 2016 10:31:43 -0700 Subject: Avoid standard malloc/free for Hrtf allocation --- Alc/hrtf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index eb586d38..8b0bb505 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -31,6 +31,7 @@ #include "hrtf.h" #include "compat.h" +#include "almalloc.h" /* Current data set limits defined by the makehrtf utility. */ @@ -310,7 +311,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) total += sizeof(delays[0])*irCount; total += al_string_length(filename)+1; - Hrtf = malloc(total); + Hrtf = al_calloc(16, total); if(Hrtf == NULL) { ERR("Out of memory.\n"); @@ -462,7 +463,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) total += sizeof(delays[0])*irCount; total += al_string_length(filename)+1; - Hrtf = malloc(total); + Hrtf = al_calloc(16, total); if(Hrtf == NULL) { ERR("Out of memory.\n"); @@ -690,7 +691,7 @@ void FreeHrtfs(void) while(Hrtf != NULL) { struct Hrtf *next = Hrtf->next; - free(Hrtf); + al_free(Hrtf); Hrtf = next; } } -- cgit v1.2.3 From 0aae992f946c397dbed79b0b7dd41fb1f9fe0087 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Jul 2016 19:48:21 -0700 Subject: Reorder some source fields --- OpenAL32/Include/alSource.h | 10 +++++----- OpenAL32/alSource.c | 41 ++++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 49bda7e4..4b047b80 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -167,6 +167,11 @@ typedef struct ALsource { ALenum state; ALenum new_state; + /** Source Buffer Queue info. */ + RWLock queue_lock; + ATOMIC(ALbufferlistitem*) queue; + ATOMIC(ALbufferlistitem*) current_buffer; + /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue, and the fractional (fixed-point) offset to the next @@ -175,11 +180,6 @@ typedef struct ALsource { ATOMIC(ALuint) position; ATOMIC(ALuint) position_fraction; - /** Source Buffer Queue info. */ - ATOMIC(ALbufferlistitem*) queue; - ATOMIC(ALbufferlistitem*) current_buffer; - RWLock queue_lock; - /** Current buffer sample info. */ ALuint NumChannels; ALuint SampleSize; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 7d34f368..46467b01 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2729,15 +2729,18 @@ static void InitSourceParams(ALsource *Source) Source->Send[i].LFReference = HIGHPASSFREQREF; } + Source->Offset = 0.0; + Source->OffsetType = AL_NONE; + Source->SourceType = AL_UNDETERMINED; Source->state = AL_INITIAL; Source->new_state = AL_NONE; - Source->SourceType = AL_UNDETERMINED; - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; ATOMIC_INIT(&Source->queue, NULL); ATOMIC_INIT(&Source->current_buffer, NULL); + ATOMIC_INIT(&Source->position, 0); + ATOMIC_INIT(&Source->position_fraction, 0); + ATOMIC_INIT(&Source->Update, NULL); ATOMIC_INIT(&Source->FreeList, NULL); } @@ -2939,9 +2942,9 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_PAUSED) { Source->state = AL_PLAYING; + ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->current_buffer, BufferList); + ATOMIC_STORE(&Source->position_fraction, 0); discontinuity = AL_TRUE; } else @@ -3033,9 +3036,10 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_INITIAL) { Source->state = AL_INITIAL; + ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue), + almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue)); + ATOMIC_STORE(&Source->position_fraction, 0); } Source->OffsetType = AL_NONE; Source->Offset = 0.0; @@ -3072,13 +3076,13 @@ ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clo while(((refcount=ReadRef(&device->MixCount))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ + + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); } while(refcount != ReadRef(&device->MixCount)); while(BufferList && BufferList != Current) { @@ -3120,12 +3124,12 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 while(((refcount=ReadRef(&device->MixCount))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << FRACTIONBITS; - readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<position_fraction, almemory_order_relaxed); } while(refcount != ReadRef(&device->MixCount)); while(BufferList && BufferList != Current) { @@ -3177,12 +3181,11 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device do { while(((refcount=ReadRef(&device->MixCount))&1)) althrd_yield(); - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); - readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + + readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); + readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); } while(refcount != ReadRef(&device->MixCount)); while(BufferList != NULL) -- cgit v1.2.3 From fe2fb8104774580b074429055083be3b125be95d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Jul 2016 16:42:36 -0700 Subject: Fix a direct access to a UIntMap --- common/threads.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/threads.c b/common/threads.c index 1e528b5b..24a197a4 100644 --- a/common/threads.c +++ b/common/threads.c @@ -413,8 +413,8 @@ static void NTAPI altss_callback(void* UNUSED(handle), DWORD reason, void* UNUSE LockUIntMapRead(&TlsDestructors); for(i = 0;i < TlsDestructors.size;i++) { - void *ptr = altss_get(TlsDestructors.array[i].key); - altss_dtor_t callback = (altss_dtor_t)TlsDestructors.array[i].value; + void *ptr = altss_get(TlsDestructors.keys[i]); + altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i]; if(ptr && callback) callback(ptr); } -- cgit v1.2.3 From e4039cb9ae488badd5575d7179b80130d5c5c740 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 10 Jul 2016 22:00:27 -0700 Subject: Update comment about the source radius calculations --- Alc/panning.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index bfdd47e2..619b89c6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -143,17 +143,26 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MA * angle spread. See: * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3 * - * The gain of the source is compensated for size, so that the - * loundness doesn't depend on the spread. + * When adjusted for N3D normalization instead of SN3D, these + * calculations are: + * + * ZH0 = -sqrt(pi) * (-1+ca); + * ZH1 = 0.5*sqrt(pi) * sa*sa; + * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1); + * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1); + * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3); + * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1); * - * ZH0 = (-sqrt_pi * (-1.f + ca)); - * ZH1 = ( 0.5f*sqrtf(3.f)*sqrt_pi * sa*sa); - * ZH2 = (-0.5f*sqrtf(5.f)*sqrt_pi * ca*(-1.f+ca)*(ca+1.f)); - * ZH3 = (-0.125f*sqrtf(7.f)*sqrt_pi * (-1.f+ca)*(ca+1.f)*(5.f*ca*ca-1.f)); - * solidangle = 2.f*F_PI*(1.f-ca) - * size_normalisation_coef = 1.f/ZH0; + * The gain of the source is compensated for size, so that the + * loundness doesn't depend on the spread. That is, the factors are + * scaled so that ZH0 remains 1 regardless of the spread. Thus: * - * This is then adjusted for N3D normalization over SN3D. + * ZH0 = 1.0f; + * ZH1 = 0.5f * (ca+1.0f); + * ZH2 = 0.5f * (ca+1.0f)*ca; + * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f); + * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca; + * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f); */ ALfloat ca = cosf(spread * 0.5f); -- cgit v1.2.3 From 14166264d6fc59386d9cbbfcd12c78ffab5989fb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Jul 2016 23:30:32 -0700 Subject: Store the voice output buffers separate from the params --- Alc/ALu.c | 40 ++++++++++++++++++++-------------------- Alc/mixer.c | 28 ++++++++++++++-------------- OpenAL32/Include/alSource.h | 10 ++++++++++ OpenAL32/Include/alu.h | 6 ------ 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index ac958d41..ecf89d59 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -418,8 +418,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * StereoMap[0].angle = -ATOMIC_LOAD(&props->StereoPan[0], almemory_order_relaxed); StereoMap[1].angle = -ATOMIC_LOAD(&props->StereoPan[1], almemory_order_relaxed); - voice->Direct.OutBuffer = Device->Dry.Buffer; - voice->Direct.OutChannels = Device->Dry.NumChannels; + voice->DirectOut.Buffer = Device->Dry.Buffer; + voice->DirectOut.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); @@ -428,13 +428,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; - voice->Send[i].OutBuffer = NULL; - voice->Send[i].OutChannels = 0; + voice->SendOut[i].Buffer = NULL; + voice->SendOut[i].Channels = 0; } else { - voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer; - voice->Send[i].OutChannels = SendSlots[i]->NumChannels; + voice->SendOut[i].Buffer = SendSlots[i]->WetBuffer; + voice->SendOut[i].Channels = SendSlots[i]->NumChannels; } } voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); @@ -544,8 +544,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale ); - voice->Direct.OutBuffer = Device->FOAOut.Buffer; - voice->Direct.OutChannels = Device->FOAOut.NumChannels; + voice->DirectOut.Buffer = Device->FOAOut.Buffer; + voice->DirectOut.Channels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, voice->Direct.Gains[c].Target); @@ -580,8 +580,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(DirectChannels) { /* Skip the virtual channels and write inputs to the real output. */ - voice->Direct.OutBuffer = Device->RealOut.Buffer; - voice->Direct.OutChannels = Device->RealOut.NumChannels; + voice->DirectOut.Buffer = Device->RealOut.Buffer; + voice->DirectOut.Channels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { int idx; @@ -620,8 +620,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Full HRTF rendering. Skip the virtual channels and render each * input channel to the real outputs. */ - voice->Direct.OutBuffer = Device->RealOut.Buffer; - voice->Direct.OutChannels = Device->RealOut.NumChannels; + voice->DirectOut.Buffer = Device->RealOut.Buffer; + voice->DirectOut.Channels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { if(chans[c].channel == LFE) @@ -864,8 +864,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro WetGainHFAuto = ATOMIC_LOAD(&props->WetGainHFAuto, almemory_order_relaxed); RoomRolloffBase = ATOMIC_LOAD(&props->RoomRolloffFactor, almemory_order_relaxed); - voice->Direct.OutBuffer = Device->Dry.Buffer; - voice->Direct.OutChannels = Device->Dry.NumChannels; + voice->DirectOut.Buffer = Device->Dry.Buffer; + voice->DirectOut.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); @@ -897,13 +897,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(!SendSlots[i]) { - voice->Send[i].OutBuffer = NULL; - voice->Send[i].OutChannels = 0; + voice->SendOut[i].Buffer = NULL; + voice->SendOut[i].Channels = 0; } else { - voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer; - voice->Send[i].OutChannels = SendSlots[i]->NumChannels; + voice->SendOut[i].Buffer = SendSlots[i]->WetBuffer; + voice->SendOut[i].Channels = SendSlots[i]->NumChannels; } } voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); @@ -1138,8 +1138,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat spread = 0.0f; - voice->Direct.OutBuffer = Device->RealOut.Buffer; - voice->Direct.OutChannels = Device->RealOut.NumChannels; + voice->DirectOut.Buffer = Device->RealOut.Buffer; + voice->DirectOut.Channels = Device->RealOut.NumChannels; if(Distance > FLT_EPSILON) { diff --git a/Alc/mixer.c b/Alc/mixer.c index 094d3768..748a2357 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -569,7 +569,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam if(!Counter) { - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->DirectOut.Channels;j++) { gains[j].Target = targets[j]; gains[j].Current = gains[j].Target; @@ -578,7 +578,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } else { - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->DirectOut.Channels;j++) { ALfloat diff; gains[j].Target = targets[j]; @@ -594,10 +594,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } - MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains, - Counter, OutPos, DstBufferSize); + MixSamples(samples, voice->DirectOut.Channels, voice->DirectOut.Buffer, + gains, Counter, OutPos, DstBufferSize); - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->DirectOut.Channels;j++) currents[j] = gains[j].Current; } else @@ -639,9 +639,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ridx = GetChannelIdxByName(Device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); - MixHrtfSamples(parms->OutBuffer, lidx, ridx, samples, Counter, voice->Offset, - OutPos, IrSize, &hrtfparams, &parms->Hrtf[chan].State, - DstBufferSize); + MixHrtfSamples(voice->DirectOut.Buffer, lidx, ridx, samples, Counter, + voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf[chan].State, DstBufferSize); } } @@ -653,7 +653,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam MixGains gains[MAX_OUTPUT_CHANNELS]; const ALfloat *samples; - if(!parms->OutBuffer) + if(!voice->SendOut[j].Buffer) continue; samples = DoFilters( @@ -664,7 +664,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam if(!Counter) { - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->SendOut[j].Channels;j++) { gains[j].Target = targets[j]; gains[j].Current = gains[j].Target; @@ -673,7 +673,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } else { - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->SendOut[j].Channels;j++) { ALfloat diff; gains[j].Target = targets[j]; @@ -689,10 +689,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } - MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains, - Counter, OutPos, DstBufferSize); + MixSamples(samples, voice->SendOut[j].Channels, voice->SendOut[j].Buffer, + gains, Counter, OutPos, DstBufferSize); - for(j = 0;j < parms->OutChannels;j++) + for(j = 0;j < voice->SendOut[j].Channels;j++) currents[j] = gains[j].Current; } } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 4b047b80..2dd8229c 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -41,6 +41,16 @@ typedef struct ALvoice { BsincState SincState; + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint Channels; + } DirectOut; + + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint Channels; + } SendOut[MAX_SENDS]; + DirectParams Direct; SendParams Send[MAX_SENDS]; } ALvoice; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index fca60b15..266c0588 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -125,9 +125,6 @@ typedef struct MixHrtfParams { } MixHrtfParams; typedef struct DirectParams { - ALfloat (*OutBuffer)[BUFFERSIZE]; - ALuint OutChannels; - struct { enum ActiveFilters ActiveType; ALfilterState LowPass; @@ -147,9 +144,6 @@ typedef struct DirectParams { } DirectParams; typedef struct SendParams { - ALfloat (*OutBuffer)[BUFFERSIZE]; - ALuint OutChannels; - struct { enum ActiveFilters ActiveType; ALfilterState LowPass; -- cgit v1.2.3 From 4898234da8d732c91fa2d08d2ef9f36323e2a6c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Jul 2016 14:22:17 -0700 Subject: Add a cmake option to embed the HRTF data --- Alc/hrtf_res.h | 5 ++++ Alc/hrtf_res.rc | 4 +++ CMakeLists.txt | 60 +++++++++++++++++++++++++++++++++----- config.h.in | 6 ++++ utils/alsoft-config/CMakeLists.txt | 1 + 5 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 Alc/hrtf_res.h create mode 100644 Alc/hrtf_res.rc diff --git a/Alc/hrtf_res.h b/Alc/hrtf_res.h new file mode 100644 index 00000000..027e49de --- /dev/null +++ b/Alc/hrtf_res.h @@ -0,0 +1,5 @@ + +#define MHRTYPE 256 + +#define IDR_DEFAULT_44100_MHR 0 +#define IDR_DEFAULT_48000_MHR 1 diff --git a/Alc/hrtf_res.rc b/Alc/hrtf_res.rc new file mode 100644 index 00000000..a17b7447 --- /dev/null +++ b/Alc/hrtf_res.rc @@ -0,0 +1,4 @@ +#include "hrtf_res.h" + +IDR_DEFAULT_44100_MHR MHRTYPE "../hrtf/default-44100.mhr" +IDR_DEFAULT_48000_MHR MHRTYPE "../hrtf/default-48000.mhr" diff --git a/CMakeLists.txt b/CMakeLists.txt index 6deb43a4..e5a5ecfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,10 +239,11 @@ IF(NOT CMAKE_DEBUG_POSTFIX) FORCE) ENDIF() +SET(EXTRA_CFLAGS "") IF(MSVC) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE) - ADD_DEFINITIONS("/wd4098") + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} /wd4098") IF(NOT DXSDK_DIR) STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}") @@ -264,14 +265,14 @@ IF(MSVC) ENDFOREACH(flag_var) ENDIF() ELSE() - ADD_DEFINITIONS(-Winline -Wall) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Winline -Wall") CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA) IF(HAVE_W_EXTRA) - ADD_DEFINITIONS(-Wextra) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wextra") ENDIF() IF(ALSOFT_WERROR) - ADD_DEFINITIONS(-Werror) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror") ENDIF() # Force enable -fPIC for CMake versions before 2.8.9 (later versions have @@ -281,7 +282,7 @@ ELSE() IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32) CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH) IF(HAVE_FPIC_SWITCH) - ADD_DEFINITIONS(-fPIC) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC") ENDIF() ENDIF() @@ -317,6 +318,7 @@ int main() ENDIF() # Set visibility/export options if available +SET(HIDDEN_DECL "") IF(WIN32) SET(EXPORT_DECL "__declspec(dllexport)") IF(NOT MINGW) @@ -344,7 +346,8 @@ ELSE() IF(HAVE_GCC_PROTECTED_VISIBILITY OR HAVE_GCC_DEFAULT_VISIBILITY) CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_SWITCH) IF(HAVE_VISIBILITY_HIDDEN_SWITCH) - ADD_DEFINITIONS(-fvisibility=hidden) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") + SET(HIDDEN_DECL "__attribute__((visibility(\"hidden\")))") ENDIF() ENDIF() @@ -534,7 +537,7 @@ IF(NOT HAVE_WINDOWS_H) CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD) IF(HAVE_PTHREAD) - ADD_DEFINITIONS(-pthread) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -pthread") SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -pthread") SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread) ENDIF() @@ -1060,6 +1063,30 @@ ENDIF() # This is always available SET(BACKENDS "${BACKENDS} Null") +option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" OFF) +if(ALSOFT_EMBED_HRTF_DATA) + if(WIN32) + set(ALC_OBJS ${ALC_OBJS} Alc/hrtf_res.rc) + else() + set(FILENAMES default-44100.mhr default-48000.mhr) + foreach(FILENAME ${FILENAMES}) + set(outfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}) + add_custom_command(OUTPUT ${outfile} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/hrtf/${FILENAME}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/hrtf" + COMMAND "${CMAKE_LINKER}" -r -b binary -o "${outfile}" ${FILENAME} + COMMAND "${CMAKE_OBJCOPY}" --rename-section .data=.rodata,alloc,load,readonly,data,contents "${outfile}" "${outfile}" + COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" + VERBATIM + ) + set(ALC_OBJS ${ALC_OBJS} ${outfile}) + endforeach() + unset(outfile) + unset(FILENAMES) + endif() +endif() + + IF(ALSOFT_UTILS AND NOT ALSOFT_NO_CONFIG_UTIL) add_subdirectory(utils/alsoft-config) ENDIF() @@ -1101,6 +1128,7 @@ CONFIGURE_FILE( # Build a common library with reusable helpers ADD_LIBRARY(common STATIC ${COMMON_OBJS}) +SET_PROPERTY(TARGET common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(NOT LIBTYPE STREQUAL "STATIC") SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE) ENDIF() @@ -1111,6 +1139,7 @@ IF(LIBTYPE STREQUAL "STATIC") ELSE() ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS}) ENDIF() +SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) 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) @@ -1209,6 +1238,11 @@ IF(WIN32) ENDIF() ENDIF() +if(ALSOFT_EMBED_HRTF_DATA) + message(STATUS "Embedding HRTF datasets") + message(STATUS "") +endif() + # Install alsoft.conf configuration file IF(ALSOFT_CONFIG) INSTALL(FILES alsoftrc.sample @@ -1244,14 +1278,17 @@ ENDIF() IF(ALSOFT_UTILS) ADD_EXECUTABLE(openal-info utils/openal-info.c) + SET_PROPERTY(TARGET openal-info APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) TARGET_LINK_LIBRARIES(openal-info ${LIBNAME}) ADD_EXECUTABLE(makehrtf utils/makehrtf.c) + SET_PROPERTY(TARGET makehrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(HAVE_LIBM) TARGET_LINK_LIBRARIES(makehrtf m) ENDIF() ADD_EXECUTABLE(bsincgen utils/bsincgen.c) + SET_PROPERTY(TARGET bsincgen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(HAVE_LIBM) TARGET_LINK_LIBRARIES(bsincgen m) ENDIF() @@ -1273,9 +1310,11 @@ ENDIF() IF(ALSOFT_TESTS) ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) + SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) ADD_EXECUTABLE(altonegen examples/altonegen.c) TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME}) + SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(ALSOFT_INSTALL) INSTALL(TARGETS altonegen @@ -1293,36 +1332,42 @@ IF(ALSOFT_EXAMPLES) IF(SDL2_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 COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET ex-common APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alstream examples/alstream.c) TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) + SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alreverb examples/alreverb.c) TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) + SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(allatency examples/allatency.c) TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) + SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alloopback examples/alloopback.c) TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) + SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) ADD_EXECUTABLE(alhrtf examples/alhrtf.c) TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) + SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) @@ -1361,6 +1406,7 @@ IF(ALSOFT_EXAMPLES) IF(FFVER_OK AND NOT MSVC) ADD_EXECUTABLE(alffplay examples/alffplay.c) TARGET_LINK_LIBRARIES(alffplay common ex-common ${SDL2_LIBRARY} ${LIBNAME} ${FFMPEG_LIBRARIES}) + SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) diff --git a/config.h.in b/config.h.in index 41fa3b61..a06c2039 100644 --- a/config.h.in +++ b/config.h.in @@ -8,6 +8,12 @@ /* Define any available alignment declaration */ #define ALIGN(x) ${ALIGN_DECL} +/* Explicit hidden visibility attribute */ +#define HIDDEN_DECL ${HIDDEN_DECL} + +/* Define if HRTF data is embedded in the library */ +#cmakedefine ALSOFT_EMBED_HRTF_DATA + /* Define if we have the C11 aligned_alloc function */ #cmakedefine HAVE_ALIGNED_ALLOC diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index a6707a3d..99d68ad5 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -19,6 +19,7 @@ if(QT4_FOUND) add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) target_link_libraries(alsoft-config ${QT_LIBRARIES}) + set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) install(TARGETS alsoft-config -- cgit v1.2.3 From ee929a2eeabb23e701e595900a6e7e1e75f4c6aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Jul 2016 19:02:19 -0700 Subject: Enumerate the embedded HRTF resources when available --- Alc/hrtf.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 345 insertions(+), 3 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 8b0bb505..c74517e5 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -345,7 +345,6 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) return Hrtf; } - static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; @@ -497,7 +496,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) return Hrtf; } - static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) { HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; @@ -595,6 +593,330 @@ done: al_string_deinit(filename); } + +/* Unfortunate that we have to duplicate LoadHrtf01 like this, to take a memory + * buffer for input instead of a FILE*, but there's no portable way to access a + * memory buffer through the standard FILE* I/O API (POSIX 2008 has fmemopen, + * and Windows doesn't seem to have anything). + */ +static struct Hrtf *LoadBuiltInHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) +{ + const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0, irCount = 0; + ALubyte irSize = 0, evCount = 0; + const ALubyte *azCount = NULL; + ALushort *evOffset = NULL; + ALshort *coeffs = NULL; + const ALubyte *delays = NULL; + ALuint i, j; + + if(datalen < 6) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), 6, datalen); + return NULL; + } + + rate = *(data++); + rate |= *(data++)<<8; + rate |= *(data++)<<16; + rate |= *(data++)<<24; + datalen -= 4; + + irSize = *(data++); + datalen -= 1; + + evCount = *(data++); + datalen -= 1; + + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + if(failed) + return NULL; + + if(datalen < evCount) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), evCount, datalen); + return NULL; + } + + azCount = data; + data += evCount; + datalen -= evCount; + + evOffset = malloc(sizeof(evOffset[0])*evCount); + if(azCount == NULL || evOffset == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + + if(!failed) + { + for(i = 0;i < evCount;i++) + { + if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + } + + if(!failed) + { + evOffset[0] = 0; + irCount = azCount[0]; + for(i = 1;i < evCount;i++) + { + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; + } + + coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); + if(coeffs == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", + al_string_get_cstr(filename), reqsize, datalen); + failed = AL_TRUE; + } + } + + if(!failed) + { + for(i = 0;i < irCount*irSize;i+=irSize) + { + for(j = 0;j < irSize;j++) + { + ALshort coeff; + coeff = *(data++); + coeff |= *(data++)<<8; + datalen -= 2; + coeffs[i+j] = coeff; + } + } + + delays = data; + data += irCount; + datalen -= irCount; + for(i = 0;i < irCount;i++) + { + if(delays[i] > maxDelay) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); + failed = AL_TRUE; + } + } + } + + if(!failed) + { + size_t total = sizeof(struct Hrtf); + total += sizeof(azCount[0])*evCount; + total += sizeof(evOffset[0])*evCount; + total += sizeof(coeffs[0])*irSize*irCount; + total += sizeof(delays[0])*irCount; + total += al_string_length(filename)+1; + + Hrtf = al_calloc(16, total); + if(Hrtf == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->evCount = evCount; + Hrtf->azCount = ((ALubyte*)(Hrtf+1)); + Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); + Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); + Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); + Hrtf->filename = ((char*)(Hrtf->delays + irCount)); + Hrtf->next = NULL; + + memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); + memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); + memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); + memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); + memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); + } + + free(evOffset); + free(coeffs); + return Hrtf; +} + +/* Another unfortunate duplication, this time of AddFileEntry to take a memory + * buffer for input instead of opening the given filename. + */ +static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename) +{ + HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; + struct Hrtf *hrtf = NULL; + const HrtfEntry *iter; + int i; + + entry.hrtf = LoadedHrtfs; + while(entry.hrtf) + { + if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0) + { + TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); + goto done; + } + entry.hrtf = entry.hrtf->next; + } + + TRACE("Loading %s...\n", al_string_get_cstr(*filename)); + if(datalen < sizeof(magicMarker01)) + { + ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), datalen); + goto done; + } + + if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) + { + TRACE("Detected data set format v1\n"); + hrtf = LoadBuiltInHrtf01( + data+sizeof(magicMarker01), datalen-sizeof(magicMarker01), + *filename + ); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), data); + + if(!hrtf) + { + ERR("Failed to load %s\n", al_string_get_cstr(*filename)); + goto done; + } + + hrtf->next = LoadedHrtfs; + LoadedHrtfs = hrtf; + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + entry.hrtf = hrtf; + + i = 0; + do { + al_string_copy(&entry.name, *filename); + if(i != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", i+1); + al_string_append_cstr(&entry.name, str); + } + ++i; + +#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); +#undef MATCH_NAME + } while(iter != VECTOR_END(*list)); + + TRACE("Adding built-in entry \"%s\"\n", al_string_get_cstr(entry.name)); + VECTOR_PUSH_BACK(*list, entry); + +done: + al_string_deinit(filename); +} + + +#ifndef ALSOFT_EMBED_HRTF_DATA +#define IDR_DEFAULT_44100_MHR 0 +#define IDR_DEFAULT_48000_MHR 1 + +static const ALubyte *GetResource(int UNUSED(name), size_t *size) +{ + *size = 0; + return NULL; +} + +#else +#include "hrtf_res.h" + +#ifdef _WIN32 +static const ALubyte *GetResource(int name, size_t *size) +{ + HMODULE handle; + HGLOBAL res; + HRSRC rc; + + GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCWSTR)GetResource, &handle + ); + rc = FindResourceW(handle, MAKEINTRESOURCEW(name), MAKEINTRESOURCEW(MHRTYPE)); + res = LoadResource(handle, rc); + + *size = SizeofResource(handle, rc); + return LockResource(res); +} + +#else + +extern const ALubyte _binary_default_44100_mhr_start[] HIDDEN_DECL; +extern const ALubyte _binary_default_44100_mhr_end[] HIDDEN_DECL; +extern const ALubyte _binary_default_44100_mhr_size[] HIDDEN_DECL; + +extern const ALubyte _binary_default_48000_mhr_start[] HIDDEN_DECL; +extern const ALubyte _binary_default_48000_mhr_end[] HIDDEN_DECL; +extern const ALubyte _binary_default_48000_mhr_size[] HIDDEN_DECL; + +static const ALubyte *GetResource(int name, size_t *size) +{ + if(name == IDR_DEFAULT_44100_MHR) + { + /* Make sure all symbols are referenced, to ensure the compiler won't + * ignore the declarations and lose the visibility attribute used to + * hide them (would be nice if ld or objcopy could automatically mark + * them as hidden when generating them, but apparently they can't). + */ + const void *volatile ptr =_binary_default_44100_mhr_size; + (void)ptr; + *size = _binary_default_44100_mhr_end - _binary_default_44100_mhr_start; + return _binary_default_44100_mhr_start; + } + if(name == IDR_DEFAULT_48000_MHR) + { + const void *volatile ptr =_binary_default_48000_mhr_size; + (void)ptr; + *size = _binary_default_48000_mhr_end - _binary_default_48000_mhr_start; + return _binary_default_48000_mhr_start; + } + *size = 0; + return NULL; +} +#endif +#endif + vector_HrtfEntry EnumerateHrtf(const_al_string devname) { vector_HrtfEntry list = VECTOR_INIT_STATIC(); @@ -646,9 +968,29 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) if(usedefaults) { - vector_al_string flist = SearchDataFiles(".mhr", "openal/hrtf"); + vector_al_string flist; + const ALubyte *rdata; + size_t rsize; + + flist = SearchDataFiles(".mhr", "openal/hrtf"); VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); VECTOR_DEINIT(flist); + + rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); + if(rdata != NULL && rsize > 0) + { + al_string ename = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&ename, "Built-In 44100hz"); + AddBuiltInEntry(&list, rdata, rsize, &ename); + } + + rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); + if(rdata != NULL && rsize > 0) + { + al_string ename = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&ename, "Built-In 48000hz"); + AddBuiltInEntry(&list, rdata, rsize, &ename); + } } if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) -- cgit v1.2.3 From b4cb0e9bf56b6f2192439c5ec767b3a699c60d53 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Jul 2016 19:05:21 -0700 Subject: Fix a copy-paste message error --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5a5ecfc..4bca46b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1272,7 +1272,7 @@ IF(ALSOFT_AMBDEC_PRESETS) presets/presets.txt DESTINATION ${SHARE_INSTALL_DIR}/openal/presets ) - MESSAGE(STATUS "Installing HRTF definitions") + MESSAGE(STATUS "Installing AmbDec presets") MESSAGE(STATUS "") ENDIF() -- cgit v1.2.3 From e8202b915d63703e6f6dd00a085cefb24ad7b315 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Jul 2016 19:05:56 -0700 Subject: Fix indentation --- CMakeLists.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bca46b0..85bc0dda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1309,23 +1309,23 @@ IF(ALSOFT_UTILS) ENDIF() IF(ALSOFT_TESTS) - ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) - SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) + SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - ADD_EXECUTABLE(altonegen examples/altonegen.c) - TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME}) - SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + ADD_EXECUTABLE(altonegen examples/altonegen.c) + TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME}) + SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - IF(ALSOFT_INSTALL) - INSTALL(TARGETS altonegen - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - ) - ENDIF() + IF(ALSOFT_INSTALL) + INSTALL(TARGETS altonegen + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + ENDIF() - MESSAGE(STATUS "Building test programs") - MESSAGE(STATUS "") + MESSAGE(STATUS "Building test programs") + MESSAGE(STATUS "") ENDIF() IF(ALSOFT_EXAMPLES) -- cgit v1.2.3 From 5106f035df7153efa411feb090ba22b1d756998b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Jul 2016 01:39:44 -0700 Subject: Move the input channel array out of the DirectParams and SendParams --- Alc/ALu.c | 111 ++++++++++++++++++++++---------------------- Alc/mixer.c | 38 +++++++-------- OpenAL32/Include/alSource.h | 6 ++- OpenAL32/Include/alu.h | 22 ++++----- OpenAL32/alSource.c | 6 +-- 5 files changed, 90 insertions(+), 93 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index ecf89d59..2a94d940 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -548,7 +548,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->DirectOut.Channels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, - voice->Direct.Gains[c].Target); + voice->Chan[c].Direct.Gains.Target); for(i = 0;i < NumSends;i++) { @@ -557,7 +557,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(c = 0;c < num_channels;c++) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } } else @@ -566,7 +566,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { const ALeffectslot *Slot = SendSlots[i]; ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], - WetGain[i], voice->Send[i].Gains[c].Target); + WetGain[i], voice->Chan[c].Send[i].Gains.Target); } } } @@ -586,9 +586,9 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Gains[c].Target[j] = 0.0f; + voice->Chan[c].Direct.Gains.Target[j] = 0.0f; if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Gains[c].Target[idx] = DryGain; + voice->Chan[c].Direct.Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal panning since they mix to B-Format, which can't @@ -602,13 +602,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + WetGain[i], voice->Chan[c].Send[i].Gains.Target); } } } @@ -627,18 +627,18 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(chans[c].channel == LFE) { /* Skip LFE */ - voice->Direct.Hrtf[c].Target.Delay[0] = 0; - voice->Direct.Hrtf[c].Target.Delay[1] = 0; + voice->Chan[c].Direct.Hrtf.Target.Delay[0] = 0; + voice->Chan[c].Direct.Hrtf.Target.Delay[1] = 0; for(i = 0;i < HRIR_LENGTH;i++) { - voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f; - voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f; + voice->Chan[c].Direct.Hrtf.Target.Coeffs[i][0] = 0.0f; + voice->Chan[c].Direct.Hrtf.Target.Coeffs[i][1] = 0.0f; } for(i = 0;i < NumSends;i++) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } continue; @@ -647,8 +647,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Get the static HRIR coefficients and delays for this channel. */ GetLerpedHrtfCoeffs(Device->Hrtf, chans[c].elevation, chans[c].angle, 0.0f, DryGain, - voice->Direct.Hrtf[c].Target.Coeffs, - voice->Direct.Hrtf[c].Target.Delay + voice->Chan[c].Direct.Hrtf.Target.Coeffs, + voice->Chan[c].Direct.Hrtf.Target.Delay ); /* Normal panning for auxiliary sends. */ @@ -659,13 +659,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + WetGain[i], voice->Chan[c].Send[i].Gains.Target); } } } @@ -681,19 +681,19 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(chans[c].channel == LFE) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Gains[c].Target[j] = 0.0f; + voice->Chan[c].Direct.Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx; if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Gains[c].Target[idx] = DryGain; + voice->Chan[c].Direct.Gains.Target[idx] = DryGain; } for(i = 0;i < NumSends;i++) { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } continue; } @@ -703,10 +703,10 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain; - voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain; + voice->Chan[c].Direct.Gains.Target[0] = coeffs[0] * DryGain; + voice->Chan[c].Direct.Gains.Target[1] = (1.0f-coeffs[0]) * DryGain; for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Gains[c].Target[j] = 0.0f; + voice->Chan[c].Direct.Gains.Target[j] = 0.0f; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); } @@ -714,7 +714,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, DryGain, - voice->Direct.Gains[c].Target); + voice->Chan[c].Direct.Gains.Target); } for(i = 0;i < NumSends;i++) @@ -723,13 +723,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[c].Target[j] = 0.0f; + voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[c].Target); + WetGain[i], voice->Chan[c].Send[i].Gains.Target); } } } @@ -747,15 +747,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * DryGainLF = maxf(DryGainLF, 0.0001f); for(c = 0;c < num_channels;c++) { - voice->Direct.Filters[c].ActiveType = AF_None; - if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass; + voice->Chan[c].Direct.FilterType = AF_None; + if(DryGainHF != 1.0f) voice->Chan[c].Direct.FilterType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Chan[c].Direct.FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, + &voice->Chan[c].Direct.LowPass, ALfilterType_HighShelf, DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, + &voice->Chan[c].Direct.HighPass, ALfilterType_LowShelf, DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } @@ -770,15 +770,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); for(c = 0;c < num_channels;c++) { - voice->Send[i].Filters[c].ActiveType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass; + voice->Chan[c].Send[i].FilterType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Chan[c].Send[i].FilterType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Chan[c].Send[i].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, + &voice->Chan[c].Send[i].LowPass, ALfilterType_HighShelf, WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, + &voice->Chan[c].Send[i].HighPass, ALfilterType_LowShelf, WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } @@ -1161,8 +1161,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Get the HRIR coefficients and delays. */ GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, spread, DryGain, - voice->Direct.Hrtf[0].Target.Coeffs, - voice->Direct.Hrtf[0].Target.Delay); + voice->Chan[0].Direct.Hrtf.Target.Coeffs, + voice->Chan[0].Direct.Hrtf.Target.Delay); CalcDirectionCoeffs(dir, spread, coeffs); @@ -1172,13 +1172,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[0].Target[j] = 0.0f; + voice->Chan[0].Send[i].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[0].Target); + WetGain[i], voice->Chan[0].Send[i].Gains.Target); } } @@ -1209,17 +1209,18 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f)); x = clampf(x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Gains[0].Target[0] = x * DryGain; - voice->Direct.Gains[0].Target[1] = (1.0f-x) * DryGain; + voice->Chan[0].Direct.Gains.Target[0] = x * DryGain; + voice->Chan[0].Direct.Gains.Target[1] = (1.0f-x) * DryGain; for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) - voice->Direct.Gains[0].Target[i] = 0.0f; + voice->Chan[0].Direct.Gains.Target[i] = 0.0f; CalcDirectionCoeffs(dir, spread, coeffs); } else { CalcDirectionCoeffs(dir, spread, coeffs); - ComputePanningGains(Device->Dry, coeffs, DryGain, voice->Direct.Gains[0].Target); + ComputePanningGains(Device->Dry, coeffs, DryGain, + voice->Chan[0].Direct.Gains.Target); } for(i = 0;i < NumSends;i++) @@ -1228,13 +1229,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Gains[0].Target[j] = 0.0f; + voice->Chan[0].Send[i].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Send[i].Gains[0].Target); + WetGain[i], voice->Chan[0].Send[i].Gains.Target); } } @@ -1248,15 +1249,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Frequency; DryGainHF = maxf(DryGainHF, 0.0001f); DryGainLF = maxf(DryGainLF, 0.0001f); - voice->Direct.Filters[0].ActiveType = AF_None; - if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass; + voice->Chan[0].Direct.FilterType = AF_None; + if(DryGainHF != 1.0f) voice->Chan[0].Direct.FilterType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Chan[0].Direct.FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, + &voice->Chan[0].Direct.LowPass, ALfilterType_HighShelf, DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, + &voice->Chan[0].Direct.HighPass, ALfilterType_LowShelf, DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } @@ -1268,15 +1269,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); - voice->Send[i].Filters[0].ActiveType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass; + voice->Chan[0].Send[i].FilterType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Chan[0].Send[i].FilterType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Chan[0].Send[i].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, + &voice->Chan[0].Send[i].LowPass, ALfilterType_HighShelf, WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, + &voice->Chan[0].Send[i].HighPass, ALfilterType_LowShelf, WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } diff --git a/Alc/mixer.c b/Alc/mixer.c index 748a2357..1d14f890 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -553,18 +553,17 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Device->ResampledData, DstBufferSize ); { - DirectParams *parms = &voice->Direct; + DirectParams *parms = &voice->Chan[chan].Direct; const ALfloat *samples; samples = DoFilters( - &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - parms->Filters[chan].ActiveType + &parms->LowPass, &parms->HighPass, Device->FilteredData, + ResampledData, DstBufferSize, parms->FilterType ); if(!voice->IsHrtf) { - ALfloat *restrict currents = parms->Gains[chan].Current; - const ALfloat *targets = parms->Gains[chan].Target; + ALfloat *restrict currents = parms->Gains.Current; + const ALfloat *targets = parms->Gains.Target; MixGains gains[MAX_OUTPUT_CHANNELS]; if(!Counter) @@ -607,7 +606,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam if(!Counter) { - parms->Hrtf[chan].Current = parms->Hrtf[chan].Target; + parms->Hrtf.Current = parms->Hrtf.Target; for(j = 0;j < HRIR_LENGTH;j++) { hrtfparams.Steps.Coeffs[j][0] = 0.0f; @@ -622,18 +621,18 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALint delaydiff; for(j = 0;j < IrSize;j++) { - coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][0] - parms->Hrtf[chan].Current.Coeffs[j][0]; + coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; hrtfparams.Steps.Coeffs[j][0] = coeffdiff * Delta; - coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][1] - parms->Hrtf[chan].Current.Coeffs[j][1]; + coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1]; hrtfparams.Steps.Coeffs[j][1] = coeffdiff * Delta; } - delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[0] - parms->Hrtf[chan].Current.Delay[0]); + delaydiff = (ALint)(parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]); hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * Delta); - delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[1] - parms->Hrtf[chan].Current.Delay[1]); + delaydiff = (ALint)(parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]); hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * Delta); } - hrtfparams.Target = &parms->Hrtf[chan].Target; - hrtfparams.Current = &parms->Hrtf[chan].Current; + hrtfparams.Target = &parms->Hrtf.Target; + hrtfparams.Current = &parms->Hrtf.Current; lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); ridx = GetChannelIdxByName(Device->RealOut, FrontRight); @@ -641,15 +640,15 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam MixHrtfSamples(voice->DirectOut.Buffer, lidx, ridx, samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf[chan].State, DstBufferSize); + &parms->Hrtf.State, DstBufferSize); } } for(j = 0;j < Device->NumAuxSends;j++) { - SendParams *parms = &voice->Send[j]; - ALfloat *restrict currents = parms->Gains[chan].Current; - const ALfloat *targets = parms->Gains[chan].Target; + SendParams *parms = &voice->Chan[chan].Send[j]; + ALfloat *restrict currents = parms->Gains.Current; + const ALfloat *targets = parms->Gains.Target; MixGains gains[MAX_OUTPUT_CHANNELS]; const ALfloat *samples; @@ -657,9 +656,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam continue; samples = DoFilters( - &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - parms->Filters[chan].ActiveType + &parms->LowPass, &parms->HighPass, Device->FilteredData, + ResampledData, DstBufferSize, parms->FilterType ); if(!Counter) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 2dd8229c..db138be1 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -51,8 +51,10 @@ typedef struct ALvoice { ALuint Channels; } SendOut[MAX_SENDS]; - DirectParams Direct; - SendParams Send[MAX_SENDS]; + struct { + DirectParams Direct; + SendParams Send[MAX_SENDS]; + } Chan[MAX_INPUT_CHANNELS]; } ALvoice; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 266c0588..9913a117 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -125,35 +125,31 @@ typedef struct MixHrtfParams { } MixHrtfParams; typedef struct DirectParams { - struct { - enum ActiveFilters ActiveType; - ALfilterState LowPass; - ALfilterState HighPass; - } Filters[MAX_INPUT_CHANNELS]; + enum ActiveFilters FilterType; + ALfilterState LowPass; + ALfilterState HighPass; struct { HrtfParams Current; HrtfParams Target; HrtfState State; - } Hrtf[MAX_INPUT_CHANNELS]; + } Hrtf; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[MAX_INPUT_CHANNELS]; + } Gains; } DirectParams; typedef struct SendParams { - struct { - enum ActiveFilters ActiveType; - ALfilterState LowPass; - ALfilterState HighPass; - } Filters[MAX_INPUT_CHANNELS]; + enum ActiveFilters FilterType; + ALfilterState LowPass; + ALfilterState HighPass; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[MAX_INPUT_CHANNELS]; + } Gains; } SendParams; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 46467b01..4a50d217 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3005,11 +3005,11 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALsizei j; for(j = 0;j < HRTF_HISTORY_LENGTH;j++) - voice->Direct.Hrtf[i].State.History[j] = 0.0f; + voice->Chan[i].Direct.Hrtf.State.History[j] = 0.0f; for(j = 0;j < HRIR_LENGTH;j++) { - voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f; - voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f; + voice->Chan[i].Direct.Hrtf.State.Values[j][0] = 0.0f; + voice->Chan[i].Direct.Hrtf.State.Values[j][1] = 0.0f; } } -- cgit v1.2.3 From 470f454c5363b09eb4ae7cf12bde9c5fbe6d8266 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Jul 2016 23:08:11 -0700 Subject: Modify bs2b_cross_feed to do multiple samples at once --- Alc/ALu.c | 39 +++++++++++++++------------------ Alc/bs2b.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- OpenAL32/Include/bs2b.h | 41 +++++------------------------------ 3 files changed, 78 insertions(+), 59 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 2a94d940..c1478b50 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1534,33 +1534,28 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->Dry.Buffer, SamplesToDo ); } - else + else if(device->Uhj_Encoder) { - if(device->Uhj_Encoder) + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + if(lidx != -1 && ridx != -1) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); - if(lidx != -1 && ridx != -1) - { - /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, - device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo - ); - } + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, + device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, SamplesToDo + ); } - if(device->Bs2b) + } + else if(device->Bs2b) + { + int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + if(lidx != -1 && ridx != -1) { /* Apply binaural/crossfeed filter */ - for(i = 0;i < SamplesToDo;i++) - { - float samples[2]; - samples[0] = device->RealOut.Buffer[0][i]; - samples[1] = device->RealOut.Buffer[1][i]; - bs2b_cross_feed(device->Bs2b, samples); - device->RealOut.Buffer[0][i] = samples[0]; - device->RealOut.Buffer[1][i] = samples[1]; - } + bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], + device->RealOut.Buffer[ridx], SamplesToDo); } } diff --git a/Alc/bs2b.c b/Alc/bs2b.c index 6c3f052b..ddc2e2f2 100644 --- a/Alc/bs2b.c +++ b/Alc/bs2b.c @@ -129,4 +129,59 @@ void bs2b_clear(struct bs2b *bs2b) memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); } /* bs2b_clear */ -extern inline void bs2b_cross_feed(struct bs2b *bs2b, float *restrict samples); +void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo) +{ + float lsamples[128][2]; + float rsamples[128][2]; + unsigned int base; + + for(base = 0;base < SamplesToDo;) + { + unsigned int todo = minu(128, SamplesToDo-base); + unsigned int i; + + /* Process left input */ + lsamples[0][0] = bs2b->a0_lo*Left[0] + + bs2b->b1_lo*bs2b->last_sample[0].lo; + lsamples[0][1] = bs2b->a0_hi*Left[0] + + bs2b->a1_hi*bs2b->last_sample[0].asis + + bs2b->b1_hi*bs2b->last_sample[0].hi; + for(i = 1;i < todo;i++) + { + lsamples[i][0] = bs2b->a0_lo*Left[i] + + bs2b->b1_lo*lsamples[i-1][0]; + lsamples[i][1] = bs2b->a0_hi*Left[i] + + bs2b->a1_hi*Left[i-1] + + bs2b->b1_hi*lsamples[i-1][1]; + } + bs2b->last_sample[0].asis = Left[i-1]; + bs2b->last_sample[0].lo = lsamples[i-1][0]; + bs2b->last_sample[0].hi = lsamples[i-1][1]; + + /* Process right input */ + rsamples[0][0] = bs2b->a0_lo*Right[0] + + bs2b->b1_lo*bs2b->last_sample[1].lo; + rsamples[0][1] = bs2b->a0_hi*Right[0] + + bs2b->a1_hi*bs2b->last_sample[1].asis + + bs2b->b1_hi*bs2b->last_sample[1].hi; + for(i = 1;i < todo;i++) + { + rsamples[i][0] = bs2b->a0_lo*Right[i] + + bs2b->b1_lo*rsamples[i-1][0]; + rsamples[i][1] = bs2b->a0_hi*Right[i] + + bs2b->a1_hi*Right[i-1] + + bs2b->b1_hi*rsamples[i-1][1]; + } + bs2b->last_sample[1].asis = Right[i-1]; + bs2b->last_sample[1].lo = rsamples[i-1][0]; + bs2b->last_sample[1].hi = rsamples[i-1][1]; + + /* Crossfeed */ + for(i = 0;i < todo;i++) + *(Left++) = lsamples[i][1] + rsamples[i][0]; + for(i = 0;i < todo;i++) + *(Right++) = rsamples[i][1] + lsamples[i][0]; + + base += todo; + } +} /* bs2b_cross_feed */ diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h index 903c6bc5..bfe5c274 100644 --- a/OpenAL32/Include/bs2b.h +++ b/OpenAL32/Include/bs2b.h @@ -63,10 +63,10 @@ struct bs2b { * [0] - first channel, [1] - second channel */ struct t_last_sample { - float asis[2]; - float lo[2]; - float hi[2]; - } last_sample; + float asis; + float lo; + float hi; + } last_sample[2]; }; /* Clear buffers and set new coefficients with new crossfeed level and sample @@ -85,38 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b); /* Clear buffer */ void bs2b_clear(struct bs2b *bs2b); -/* Crossfeeds one stereo sample that are pointed by sample. - * [0] - first channel, [1] - second channel. - * Returns crossfided sample by sample pointer. - */ -inline void bs2b_cross_feed(struct bs2b *bs2b, float *restrict sample) -{ -/* Single pole IIR filter. - * O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1] - */ - -/* Lowpass filter */ -#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1)) - -/* Highboost filter */ -#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1)) - - /* Lowpass filter */ - bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]); - bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]); - - /* Highboost filter */ - bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]); - bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]); - bs2b->last_sample.asis[0] = sample[0]; - bs2b->last_sample.asis[1] = sample[1]; - - /* Crossfeed */ - sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1]; - sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0]; -#undef hi_filter -#undef lo_filter -} /* bs2b_cross_feed */ +void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo); #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3 From 2f3cffa517bdb26d2a56e49a3633353c6769995a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Jul 2016 01:42:02 -0700 Subject: Improve the UHJ encoder's allpass processing loops --- Alc/uhjfilter.c | 119 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index 4a71287f..0a702873 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -6,7 +6,7 @@ /* This is the maximum number of samples processed for each inner loop * iteration. */ -#define MAX_UPDATE_SAMPLES 256 +#define MAX_UPDATE_SAMPLES 128 static const ALfloat Filter1Coeff[4] = { @@ -16,6 +16,32 @@ static const ALfloat Filter2Coeff[4] = { 0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f }; +static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALuint todo) +{ + ALuint i; + + if(todo > 1) + { + dst[0] = aa*(src[0] + state->y[1]) - state->x[1]; + dst[1] = aa*(src[1] + state->y[0]) - state->x[0]; + for(i = 2;i < todo;i++) + dst[i] = aa*(src[i] + dst[i-2]) - src[i-2]; + state->x[1] = src[i-2]; + state->x[0] = src[i-1]; + state->y[1] = dst[i-2]; + state->y[0] = dst[i-1]; + } + else if(todo == 1) + { + dst[0] = aa*(src[0] + state->y[1]) - state->x[1]; + state->x[1] = state->x[0]; + state->x[0] = src[0]; + state->y[1] = state->y[0]; + state->y[0] = dst[0]; + } +} + + /* NOTE: There seems to be a bit of an inconsistency in how this encoding is * supposed to work. Some references, such as * @@ -38,68 +64,63 @@ static const ALfloat Filter2Coeff[4] = { void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { - ALuint base, i, c; + ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; + ALfloat temp[2][MAX_UPDATE_SAMPLES]; + ALuint base, i; for(base = 0;base < SamplesToDo;) { - ALfloat D[MAX_UPDATE_SAMPLES/2], S[MAX_UPDATE_SAMPLES/2]; - ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES/2); + ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES); /* D = 0.6554516*Y */ for(i = 0;i < todo;i++) - { - ALfloat in = 0.6554516f*InSamples[2][base+i]; - for(c = 0;c < 4;c++) - { - ALfloat aa = Filter1Coeff[c]*Filter1Coeff[c]; - ALfloat out = aa*(in + enc->Filter1_Y[c].y[1]) - enc->Filter1_Y[c].x[1]; - enc->Filter1_Y[c].x[1] = enc->Filter1_Y[c].x[0]; - enc->Filter1_Y[c].x[0] = in; - enc->Filter1_Y[c].y[1] = enc->Filter1_Y[c].y[0]; - enc->Filter1_Y[c].y[0] = out; - in = out; - } - /* NOTE: Filter1 requires a 1 sample delay for the base output, so - * take the sample before the last for output. - */ - D[i] = enc->Filter1_Y[3].y[1]; - } + temp[0][i] = 0.6554516f*InSamples[2][base+i]; + allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], + Filter1Coeff[0]*Filter1Coeff[0], todo); + allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], + Filter1Coeff[1]*Filter1Coeff[1], todo); + allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], + Filter1Coeff[2]*Filter1Coeff[2], todo); + /* NOTE: Filter1 requires a 1 sample delay for the final output, so + * take the last processed sample from the previous run as the first + * output sample. + */ + D[0] = enc->Filter1_Y[3].y[0]; + allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], + Filter1Coeff[3]*Filter1Coeff[3], todo); + for(i = 1;i < todo;i++) + D[i] = temp[0][i-1]; /* D += j(-0.3420201*W + 0.5098604*X) */ for(i = 0;i < todo;i++) - { - ALfloat in = -0.3420201f*InSamples[0][base+i] + + temp[0][i] = -0.3420201f*InSamples[0][base+i] + 0.5098604f*InSamples[1][base+i]; - for(c = 0;c < 4;c++) - { - ALfloat aa = Filter2Coeff[c]*Filter2Coeff[c]; - ALfloat out = aa*(in + enc->Filter2_WX[c].y[1]) - enc->Filter2_WX[c].x[1]; - enc->Filter2_WX[c].x[1] = enc->Filter2_WX[c].x[0]; - enc->Filter2_WX[c].x[0] = in; - enc->Filter2_WX[c].y[1] = enc->Filter2_WX[c].y[0]; - enc->Filter2_WX[c].y[0] = out; - in = out; - } - D[i] += enc->Filter2_WX[3].y[0]; - } + allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], + Filter2Coeff[0]*Filter2Coeff[0], todo); + allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], + Filter2Coeff[1]*Filter2Coeff[1], todo); + allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], + Filter2Coeff[2]*Filter2Coeff[2], todo); + allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], + Filter2Coeff[3]*Filter2Coeff[3], todo); + for(i = 0;i < todo;i++) + D[i] += temp[0][i]; /* S = 0.9396926*W + 0.1855740*X */ for(i = 0;i < todo;i++) - { - ALfloat in = 0.9396926f*InSamples[0][base+i] + + temp[0][i] = 0.9396926f*InSamples[0][base+i] + 0.1855740f*InSamples[1][base+i]; - for(c = 0;c < 4;c++) - { - ALfloat aa = Filter1Coeff[c]*Filter1Coeff[c]; - ALfloat out = aa*(in + enc->Filter1_WX[c].y[1]) - enc->Filter1_WX[c].x[1]; - enc->Filter1_WX[c].x[1] = enc->Filter1_WX[c].x[0]; - enc->Filter1_WX[c].x[0] = in; - enc->Filter1_WX[c].y[1] = enc->Filter1_WX[c].y[0]; - enc->Filter1_WX[c].y[0] = out; - in = out; - } - S[i] = enc->Filter1_WX[3].y[1]; - } + allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], + Filter1Coeff[0]*Filter1Coeff[0], todo); + allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], + Filter1Coeff[1]*Filter1Coeff[1], todo); + allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], + Filter1Coeff[2]*Filter1Coeff[2], todo); + S[0] = enc->Filter1_WX[3].y[0]; + allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], + Filter1Coeff[3]*Filter1Coeff[3], todo); + for(i = 1;i < todo;i++) + S[i] = temp[0][i-1]; /* Left = (S + D)/2.0 */ for(i = 0;i < todo;i++) -- cgit v1.2.3 From 35cbecabf91fe449bb7209aa98ba7461bfd078a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Jul 2016 00:29:02 -0700 Subject: Repack the ambisonic dual-band decoder matrices The decoders use a row of the HF decoder matrix followed by a row of the LF decoder matrix, for each given output channel in turn. Packing the two matrices accordingly results in less memory hopping. --- Alc/bformatdec.c | 199 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 94 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 9ebaba27..49532cc5 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -116,39 +116,29 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; -static const ALfloat SquareMatrixHF[4][MAX_AMBI_COEFFS] = { - { 0.353553f, 0.204094f, 0.0f, 0.204094f }, - { 0.353553f, -0.204094f, 0.0f, 0.204094f }, - { 0.353553f, 0.204094f, 0.0f, -0.204094f }, - { 0.353553f, -0.204094f, 0.0f, -0.204094f }, +enum FreqBand { + FB_HighFreq, + FB_LowFreq, + FB_Max }; -static const ALfloat SquareMatrixLF[4][MAX_AMBI_COEFFS] = { - { 0.25f, 0.204094f, 0.0f, 0.204094f }, - { 0.25f, -0.204094f, 0.0f, 0.204094f }, - { 0.25f, 0.204094f, 0.0f, -0.204094f }, - { 0.25f, -0.204094f, 0.0f, -0.204094f }, + +static const ALfloat SquareMatrix[4][FB_Max][MAX_AMBI_COEFFS] = { + { { 0.353553f, 0.204094f, 0.0f, 0.204094f }, { 0.25f, 0.204094f, 0.0f, 0.204094f } }, + { { 0.353553f, -0.204094f, 0.0f, 0.204094f }, { 0.25f, -0.204094f, 0.0f, 0.204094f } }, + { { 0.353553f, 0.204094f, 0.0f, -0.204094f }, { 0.25f, 0.204094f, 0.0f, -0.204094f } }, + { { 0.353553f, -0.204094f, 0.0f, -0.204094f }, { 0.25f, -0.204094f, 0.0f, -0.204094f } }, }; static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS]; -static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = { - { 0.25f, 0.14425f, 0.14425f, 0.14425f }, - { 0.25f, -0.14425f, 0.14425f, 0.14425f }, - { 0.25f, 0.14425f, 0.14425f, -0.14425f }, - { 0.25f, -0.14425f, 0.14425f, -0.14425f }, - { 0.25f, 0.14425f, -0.14425f, 0.14425f }, - { 0.25f, -0.14425f, -0.14425f, 0.14425f }, - { 0.25f, 0.14425f, -0.14425f, -0.14425f }, - { 0.25f, -0.14425f, -0.14425f, -0.14425f }, -}; -static const ALfloat CubeMatrixLF[8][MAX_AMBI_COEFFS] = { - { 0.125f, 0.125f, 0.125f, 0.125f }, - { 0.125f, -0.125f, 0.125f, 0.125f }, - { 0.125f, 0.125f, 0.125f, -0.125f }, - { 0.125f, -0.125f, 0.125f, -0.125f }, - { 0.125f, 0.125f, -0.125f, 0.125f }, - { 0.125f, -0.125f, -0.125f, 0.125f }, - { 0.125f, 0.125f, -0.125f, -0.125f }, - { 0.125f, -0.125f, -0.125f, -0.125f }, +static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { + { { 0.25f, 0.14425f, 0.14425f, 0.14425f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, + { { 0.25f, -0.14425f, 0.14425f, 0.14425f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, + { { 0.25f, 0.14425f, 0.14425f, -0.14425f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, + { { 0.25f, -0.14425f, 0.14425f, -0.14425f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, + { { 0.25f, 0.14425f, -0.14425f, 0.14425f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, + { { 0.25f, -0.14425f, -0.14425f, 0.14425f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, + { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, + { { 0.25f, -0.14425f, -0.14425f, -0.14425f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; @@ -207,14 +197,14 @@ static void init_bformatdec(void) #define MAX_DELAY_LENGTH 128 -/* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with - * single-band decoding - */ +/* NOTE: BandSplitter filters are unused with single-band decoding */ typedef struct BFormatDec { ALboolean Enabled[MAX_OUTPUT_CHANNELS]; - alignas(16) ALfloat MatrixHF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; - alignas(16) ALfloat MatrixLF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + union { + alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS]; + alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; + } Matrix; BandSplitter XOver[MAX_AMBI_COEFFS]; @@ -233,8 +223,7 @@ typedef struct BFormatDec { struct { BandSplitter XOver[4]; - const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS]; - const ALfloat (*restrict MatrixLF)[MAX_AMBI_COEFFS]; + const ALfloat (*restrict Matrix)[FB_Max][MAX_AMBI_COEFFS]; const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; ALuint NumChannels; } UpSampler; @@ -316,16 +305,14 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, bandsplit_init(&dec->UpSampler.XOver[i], ratio); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - dec->UpSampler.MatrixHF = CubeMatrixHF; - dec->UpSampler.MatrixLF = CubeMatrixLF; + dec->UpSampler.Matrix = CubeMatrix; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder; dec->UpSampler.NumChannels = 8; dec->Periphonic = AL_TRUE; } else { - dec->UpSampler.MatrixHF = SquareMatrixHF; - dec->UpSampler.MatrixLF = SquareMatrixLF; + dec->UpSampler.Matrix = SquareMatrix; dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder; dec->UpSampler.NumChannels = 4; dec->Periphonic = AL_FALSE; @@ -366,10 +353,44 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, } } + memset(&dec->Matrix, 0, sizeof(dec->Matrix)); if(conf->FreqBands == 1) { dec->DualBand = AL_FALSE; - ratio = 1.0f; + for(i = 0;i < conf->NumSpeakers;i++) + { + ALuint chan = chanmap[i]; + ALfloat gain; + ALuint j, k; + + if(!dec->Periphonic) + { + for(j = 0,k = 0;j < 7;j++) + { + ALuint l = map2DTo3D[j]; + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 3) gain = conf->HFOrderGain[2]; + else if(j == 5) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * + gain * distgain[i]; + } + } + else + { + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0]; + else if(j == 1) gain = conf->HFOrderGain[1]; + else if(j == 4) gain = conf->HFOrderGain[2]; + else if(j == 9) gain = conf->HFOrderGain[3]; + if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * + gain * distgain[i]; + } + } + } } else { @@ -380,16 +401,27 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, bandsplit_init(&dec->XOver[i], ratio); ratio = powf(10.0f, conf->XOverRatio / 40.0f); - memset(dec->MatrixLF, 0, sizeof(dec->MatrixLF)); for(i = 0;i < conf->NumSpeakers;i++) { ALuint chan = chanmap[i]; - ALuint j, k = 0; ALfloat gain; + ALuint j, k; if(!dec->Periphonic) { - for(j = 0;j < 7;j++) + for(j = 0,k = 0;j < 7;j++) + { + ALuint l = map2DTo3D[j]; + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 3) gain = conf->HFOrderGain[2] * ratio; + else if(j == 5) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / + coeff_scale[l] * gain * + distgain[i]; + } + for(j = 0,k = 0;j < 7;j++) { ALuint l = map2DTo3D[j]; if(j == 0) gain = conf->LFOrderGain[0] / ratio; @@ -397,61 +429,38 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, else if(j == 3) gain = conf->LFOrderGain[2] / ratio; else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[l] * - gain * distgain[i]; + dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / + coeff_scale[l] * gain * + distgain[i]; } } else { - for(j = 0;j < MAX_AMBI_COEFFS;j++) + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) + { + if(j == 0) gain = conf->HFOrderGain[0] * ratio; + else if(j == 1) gain = conf->HFOrderGain[1] * ratio; + else if(j == 4) gain = conf->HFOrderGain[2] * ratio; + else if(j == 9) gain = conf->HFOrderGain[3] * ratio; + if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / + coeff_scale[j] * gain * + distgain[i]; + } + for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) { if(j == 0) gain = conf->LFOrderGain[0] / ratio; else if(j == 1) gain = conf->LFOrderGain[1] / ratio; else if(j == 4) gain = conf->LFOrderGain[2] / ratio; else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] * - gain * distgain[i]; + dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / + coeff_scale[j] * gain * + distgain[i]; } } } } - - memset(dec->MatrixHF, 0, sizeof(dec->MatrixHF)); - for(i = 0;i < conf->NumSpeakers;i++) - { - ALuint chan = chanmap[i]; - ALuint j, k = 0; - ALfloat gain; - - if(!dec->Periphonic) - { - for(j = 0;j < 7;j++) - { - ALuint l = map2DTo3D[j]; - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 3) gain = conf->HFOrderGain[2] * ratio; - else if(j == 5) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * - gain * distgain[i]; - } - } - else - { - for(j = 0;j < MAX_AMBI_COEFFS;j++) - { - if(j == 0) gain = conf->HFOrderGain[0] * ratio; - else if(j == 1) gain = conf->HFOrderGain[1] * ratio; - else if(j == 4) gain = conf->HFOrderGain[2] * ratio; - else if(j == 9) gain = conf->HFOrderGain[3] * ratio; - if((conf->ChanMask&(1<MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - gain * distgain[i]; - } - } - } } @@ -471,10 +480,12 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF, - dec->NumChannels, SamplesToDo); - MixMatrixRow(dec->ChannelMix, dec->MatrixLF[chan], dec->SamplesLF, - dec->NumChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], + dec->SamplesHF, dec->NumChannels, SamplesToDo + ); + MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], + dec->SamplesLF, dec->NumChannels, SamplesToDo + ); if(dec->Delay[chan].Length > 0) { @@ -510,7 +521,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->MatrixHF[chan], InSamples, + MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, dec->NumChannels, SamplesToDo); if(dec->Delay[chan].Length > 0) @@ -562,10 +573,10 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B for(k = 0;k < dec->UpSampler.NumChannels;k++) { memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->UpSampler.MatrixHF[k], dec->SamplesHF, - InChannels, SamplesToDo); - MixMatrixRow(dec->ChannelMix, dec->UpSampler.MatrixLF[k], dec->SamplesLF, - InChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->UpSampler.Matrix[k][FB_HighFreq], + dec->SamplesHF, InChannels, SamplesToDo); + MixMatrixRow(dec->ChannelMix, dec->UpSampler.Matrix[k][FB_LowFreq], + dec->SamplesLF, InChannels, SamplesToDo); for(j = 0;j < dec->NumChannels;j++) { -- cgit v1.2.3 From 84ca38ba957d90b6b864cd50cc313e4a7fe1386c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Jul 2016 00:46:18 -0700 Subject: Make a MAX_AMBI2D_COEFFS macro instead of a magic number --- Alc/bformatdec.c | 8 ++++---- OpenAL32/Include/alMain.h | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 49532cc5..d6cf25e2 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -272,7 +272,7 @@ int bformatdec_getOrder(const struct BFormatDec *dec) void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags) { - static const ALuint map2DTo3D[7] = { + static const ALuint map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; @@ -365,7 +365,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, if(!dec->Periphonic) { - for(j = 0,k = 0;j < 7;j++) + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { ALuint l = map2DTo3D[j]; if(j == 0) gain = conf->HFOrderGain[0]; @@ -409,7 +409,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, if(!dec->Periphonic) { - for(j = 0,k = 0;j < 7;j++) + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { ALuint l = map2DTo3D[j]; if(j == 0) gain = conf->HFOrderGain[0] * ratio; @@ -421,7 +421,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, coeff_scale[l] * gain * distgain[i]; } - for(j = 0,k = 0;j < 7;j++) + for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { ALuint l = map2DTo3D[j]; if(j == 0) gain = conf->LFOrderGain[0] / ratio; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 13aadef5..05abc0fa 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -485,7 +485,8 @@ enum RenderMode { /* The maximum number of Ambisonics coefficients. For a given order (o), the * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, - * second-order has 9, third-order has 16, and fourth-order has 25. */ + * second-order has 9, third-order has 16, and fourth-order has 25. + */ #define MAX_AMBI_ORDER 3 #define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1)) @@ -497,6 +498,12 @@ enum RenderMode { */ #define AMBI_PERIPHONIC_MASK (0xfe7ce4) +/* The maximum number of Ambisonic coefficients for 2D (non-periphonic) + * representation. This is 2 per each order above zero-order, plus 1 for zero- + * order. Or simply, o*2 + 1. + */ +#define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1) + typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; typedef struct BFChannelConfig { -- cgit v1.2.3 From dc8bbca7f1c6d11c4304f9c6e0977f4402593729 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Jul 2016 15:38:39 -0700 Subject: Constify and use the correct size for an array --- Alc/panning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 619b89c6..7d16afe2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -694,7 +694,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin } else { - static int map[MAX_AMBI_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; + static const int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; count = (conf->ChanMask > 0x1ff) ? 7 : (conf->ChanMask > 0xf) ? 5 : 3; -- cgit v1.2.3 From fbba2828cddb5488b12d3f26fe3edb1ee286a20c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Jul 2016 19:42:11 -0700 Subject: Update the default quad decoder matrix --- Alc/panning.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 7d16afe2..f81a6fc0 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -481,10 +481,10 @@ static const ChannelMap MonoCfg[1] = { { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, }, QuadCfg[4] = { - { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, - { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, - { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + { FrontLeft, { 0.353553f, 0.306186f, 0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.125000f } }, + { FrontRight, { 0.353553f, 0.306186f, -0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.125000f } }, + { BackLeft, { 0.353553f, -0.306186f, 0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.125000f } }, + { BackRight, { 0.353553f, -0.306186f, -0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.125000f } }, }, X51SideCfg[5] = { { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, -- cgit v1.2.3 From 69af50cadb0f4c0f8b9b8b159785bc2a3cae8dc1 Mon Sep 17 00:00:00 2001 From: "Ryan P.C. McQuen" Date: Thu, 21 Jul 2016 08:09:31 -0700 Subject: Fix for ffmpeg. Closes https://github.com/kcat/openal-soft/issues/48. --- examples/alffplay.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index 7feaa5ae..b9acbb8e 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -942,7 +942,7 @@ static void update_picture(MovieState *movState, bool *first_update, SDL_Window void *pixels = NULL; int pitch = 0; - if(movState->video.st->codec->pix_fmt == PIX_FMT_YUV420P) + if(movState->video.st->codec->pix_fmt == AV_PIX_FMT_YUV420P) SDL_UpdateYUVTexture(vp->bmp, NULL, frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], @@ -960,7 +960,7 @@ static void update_picture(MovieState *movState, bool *first_update, SDL_Window if(!movState->video.swscale_ctx) movState->video.swscale_ctx = sws_getContext( w, h, movState->video.st->codec->pix_fmt, - w, h, PIX_FMT_YUV420P, SWS_X, NULL, NULL, NULL + w, h, AV_PIX_FMT_YUV420P, SWS_X, NULL, NULL, NULL ); /* point pict at the queue */ -- cgit v1.2.3 From c0e7aab823ce58ebd16ac393e6ed2407174ed535 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Jul 2016 21:59:02 -0700 Subject: Properly skip loading of already-loaded HRTF data sets Previously, if an HRTF file was loaded it would not only skip loading it, but it would also skip adding it to the output enumeration list. Now it properly skips loading it when it's already loaded, but still adds it to the enumeration list if it's not already in it. --- Alc/hrtf.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index c74517e5..9e927e4f 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -512,13 +512,22 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) if(!name) name = al_string_get_cstr(*filename); else ++name; +#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0) + VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); + goto done; + } +#undef MATCH_FNAME + entry.hrtf = LoadedHrtfs; while(entry.hrtf) { if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); - goto done; + TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename)); + goto skip_load; } entry.hrtf = entry.hrtf->next; } @@ -562,6 +571,7 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); entry.hrtf = hrtf; +skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ ext = strrchr(name, '.'); @@ -784,13 +794,22 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t const HrtfEntry *iter; int i; +#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0) + VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); + goto done; + } +#undef MATCH_FNAME + entry.hrtf = LoadedHrtfs; while(entry.hrtf) { if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); - goto done; + TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename)); + goto skip_load; } entry.hrtf = entry.hrtf->next; } @@ -825,6 +844,7 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); entry.hrtf = hrtf; +skip_load: i = 0; do { al_string_copy(&entry.name, *filename); -- cgit v1.2.3 From 94dd34fb4b106b001797d9f5b4e98b3319a36579 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jul 2016 06:29:08 -0700 Subject: Increase the default thunk array size This value should be enough to hold IDs for most apps without needing to reallocate it, while not being unnecessarily large (4KB). --- OpenAL32/alThunk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c index 29da9bbd..72fc0dcb 100644 --- a/OpenAL32/alThunk.c +++ b/OpenAL32/alThunk.c @@ -35,7 +35,7 @@ static RWLock ThunkLock; void ThunkInit(void) { RWLockInit(&ThunkLock); - ThunkArraySize = 1; + ThunkArraySize = 1024; ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray)); } -- cgit v1.2.3 From e4bbbe06fa99c8450e33af8bc8fdda5cc5d8770f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jul 2016 19:04:54 -0700 Subject: Avoid manual loops for ALfilterState processing --- Alc/effects/distortion.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index deec6092..eabf8a5d 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -97,7 +97,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples for(base = 0;base < SamplesToDo;) { - float oversample_buffer[64][4]; + float buffer[2][64 * 4]; ALuint td = minu(64, SamplesToDo-base); /* Perform 4x oversampling to avoid aliasing. */ @@ -109,10 +109,10 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples /* Fill oversample buffer using zero stuffing */ for(it = 0;it < td;it++) { - oversample_buffer[it][0] = SamplesIn[0][it+base]; - oversample_buffer[it][1] = 0.0f; - oversample_buffer[it][2] = 0.0f; - oversample_buffer[it][3] = 0.0f; + buffer[0][it*4 + 0] = SamplesIn[0][it+base]; + buffer[0][it*4 + 1] = 0.0f; + buffer[0][it*4 + 2] = 0.0f; + buffer[0][it*4 + 3] = 0.0f; } /* First step, do lowpass filtering of original signal, */ @@ -120,38 +120,30 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples /* 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; - } - } + ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4); + /* 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(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]; + /* Restore signal power by multiplying sample by amount of oversampling */ + ALfloat smp = buffer[1][it*4 + ot] * 4.0f; 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; + buffer[1][it*4 + ot] = smp; } } + /* Third step, do bandpass filtering of distorted signal */ + ALfilterState_process(&state->bandpass, buffer[0], buffer[1], td*4); + for(kt = 0;kt < NumChannels;kt++) { /* Fourth step, final, do attenuation and perform decimation, @@ -162,7 +154,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples continue; for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * oversample_buffer[it][0]; + SamplesOut[kt][base+it] += gain * buffer[0][it*4]; } base += td; -- cgit v1.2.3 From 8fcc4afd2d8fd431232e616003a8620605661146 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jul 2016 22:20:47 -0700 Subject: Fix use of a loop var --- Alc/mixer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 1d14f890..b2af812a 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -381,7 +381,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALuint SampleSize; ALint64 DataSize64; ALuint IrSize; - ALuint chan, j; + ALuint chan, send, j; /* Get source info */ State = AL_PLAYING; /* Only called while playing. */ @@ -644,15 +644,15 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } - for(j = 0;j < Device->NumAuxSends;j++) + for(send = 0;send < Device->NumAuxSends;send++) { - SendParams *parms = &voice->Chan[chan].Send[j]; + SendParams *parms = &voice->Chan[chan].Send[send]; ALfloat *restrict currents = parms->Gains.Current; const ALfloat *targets = parms->Gains.Target; MixGains gains[MAX_OUTPUT_CHANNELS]; const ALfloat *samples; - if(!voice->SendOut[j].Buffer) + if(!voice->SendOut[send].Buffer) continue; samples = DoFilters( @@ -662,7 +662,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam if(!Counter) { - for(j = 0;j < voice->SendOut[j].Channels;j++) + for(j = 0;j < voice->SendOut[send].Channels;j++) { gains[j].Target = targets[j]; gains[j].Current = gains[j].Target; @@ -671,7 +671,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } else { - for(j = 0;j < voice->SendOut[j].Channels;j++) + for(j = 0;j < voice->SendOut[send].Channels;j++) { ALfloat diff; gains[j].Target = targets[j]; @@ -687,10 +687,12 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } - MixSamples(samples, voice->SendOut[j].Channels, voice->SendOut[j].Buffer, - gains, Counter, OutPos, DstBufferSize); + MixSamples(samples, + voice->SendOut[send].Channels, voice->SendOut[send].Buffer, + gains, Counter, OutPos, DstBufferSize + ); - for(j = 0;j < voice->SendOut[j].Channels;j++) + for(j = 0;j < voice->SendOut[send].Channels;j++) currents[j] = gains[j].Current; } } -- cgit v1.2.3 From 0a693d039a376c116dc5facf2da5de5d2ef580ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Jul 2016 23:51:37 -0700 Subject: Avoid more uses of ALfilterState_processSingle It's a horriobly inefficient way to process multiple samples through the filter. --- Alc/effects/reverb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f8680d24..9b0dbe1d 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1253,15 +1253,14 @@ static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restri // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) +static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) { ALuint i; - // Low-pass filter the incoming samples. + // Low-pass filter the incoming samples (use the early buffer as temp storage). + ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, - ALfilterState_processSingle(&State->LpFilter, in[i]) - ); + DelayLineIn(&State->Delay, State->Offset+i, early[i>>2][i&3]); // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); @@ -1279,12 +1278,13 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa { ALuint i; - // Band-pass and modulate the incoming samples. + // Band-pass and modulate the incoming samples (use the early buffer as temp storage). + ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); + ALfilterState_process(&State->HpFilter, &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo); + for(i = 0;i < todo;i++) { - ALfloat sample = input[i]; - sample = ALfilterState_processSingle(&State->LpFilter, sample); - sample = ALfilterState_processSingle(&State->HpFilter, sample); + ALfloat sample = early[(MAX_UPDATE_SAMPLES/4)+(i>>2)][i&3]; // Perform any modulation on the input. sample = EAXModulation(State, State->Offset+i, sample); -- cgit v1.2.3 From 11b38e11907ea383544bcf902f9ea891f4a3a5a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 00:03:44 -0700 Subject: Rename input_gain to b0 --- Alc/effects/autowah.c | 2 +- Alc/effects/equalizer.c | 8 ++++---- Alc/effects/modulator.c | 2 +- Alc/mixer_c.c | 8 ++++---- OpenAL32/Include/alFilter.h | 5 ++--- OpenAL32/alFilter.c | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 648afc83..c8b70595 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -128,9 +128,9 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, state->LowPass.a1 = a[1] / a[0]; state->LowPass.a2 = a[2] / a[0]; + state->LowPass.b0 = b[0] / a[0]; state->LowPass.b1 = b[1] / a[0]; state->LowPass.b2 = b[2] / a[0]; - state->LowPass.input_gain = b[0] / a[0]; temps[it] = ALfilterState_processSingle(&state->LowPass, smp); } diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 25e36724..96676d34 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -131,9 +131,9 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { state->filter[0][i].a1 = state->filter[0][0].a1; state->filter[0][i].a2 = state->filter[0][0].a2; + state->filter[0][i].b0 = state->filter[0][0].b0; state->filter[0][i].b1 = state->filter[0][0].b1; state->filter[0][i].b2 = state->filter[0][0].b2; - state->filter[0][i].input_gain = state->filter[0][0].input_gain; state->filter[0][i].process = state->filter[0][0].process; } @@ -148,9 +148,9 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { state->filter[1][i].a1 = state->filter[1][0].a1; state->filter[1][i].a2 = state->filter[1][0].a2; + state->filter[1][i].b0 = state->filter[1][0].b0; state->filter[1][i].b1 = state->filter[1][0].b1; state->filter[1][i].b2 = state->filter[1][0].b2; - state->filter[1][i].input_gain = state->filter[1][0].input_gain; state->filter[1][i].process = state->filter[1][0].process; } @@ -165,9 +165,9 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { state->filter[2][i].a1 = state->filter[2][0].a1; state->filter[2][i].a2 = state->filter[2][0].a2; + state->filter[2][i].b0 = state->filter[2][0].b0; state->filter[2][i].b1 = state->filter[2][0].b1; state->filter[2][i].b2 = state->filter[2][0].b2; - state->filter[2][i].input_gain = state->filter[2][0].input_gain; state->filter[2][i].process = state->filter[2][0].process; } @@ -180,9 +180,9 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { state->filter[3][i].a1 = state->filter[3][0].a1; state->filter[3][i].a2 = state->filter[3][0].a2; + state->filter[3][i].b0 = state->filter[3][0].b0; state->filter[3][i].b1 = state->filter[3][0].b1; state->filter[3][i].b2 = state->filter[3][0].b2; - state->filter[3][i].input_gain = state->filter[3][0].input_gain; state->filter[3][i].process = state->filter[3][0].process; } } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 0b0971b2..7e3e89b2 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -117,9 +117,9 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * { state->Filter[i].a1 = -a; state->Filter[i].a2 = 0.0f; + state->Filter[i].b0 = a; state->Filter[i].b1 = -a; state->Filter[i].b2 = 0.0f; - state->Filter[i].input_gain = a; state->Filter[i].process = ALfilterState_processC; } diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index f741e28f..7dca7a61 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -98,18 +98,18 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALuint i; if(numsamples > 1) { - dst[0] = filter->input_gain * src[0] + + dst[0] = filter->b0 * src[0] + filter->b1 * filter->x[0] + filter->b2 * filter->x[1] - filter->a1 * filter->y[0] - filter->a2 * filter->y[1]; - dst[1] = filter->input_gain * src[1] + + dst[1] = filter->b0 * src[1] + filter->b1 * src[0] + filter->b2 * filter->x[0] - filter->a1 * dst[0] - filter->a2 * filter->y[0]; for(i = 2;i < numsamples;i++) - dst[i] = filter->input_gain * src[i] + + dst[i] = filter->b0 * src[i] + filter->b1 * src[i-1] + filter->b2 * src[i-2] - filter->a1 * dst[i-1] - @@ -121,7 +121,7 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const } else if(numsamples == 1) { - dst[0] = filter->input_gain * src[0] + + dst[0] = filter->b0 * src[0] + filter->b1 * filter->x[0] + filter->b2 * filter->x[1] - filter->a1 * filter->y[0] - diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 855bb534..8012e398 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -43,8 +43,7 @@ typedef struct ALfilterState { ALfloat x[2]; /* History of two last input samples */ ALfloat y[2]; /* History of two last output samples */ ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ - ALfloat b1, b2; /* Transfer function coefficients "b" (b0 is input_gain) */ - ALfloat input_gain; + ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); } ALfilterState; @@ -83,7 +82,7 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample { ALfloat outsmp; - outsmp = filter->input_gain * sample + + outsmp = filter->b0 * sample + filter->b1 * filter->x[0] + filter->b2 * filter->x[1] - filter->a1 * filter->y[0] - diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 7b96263a..da447c27 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -429,9 +429,9 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->a1 = a[1] / a[0]; filter->a2 = a[2] / a[0]; + filter->b0 = b[0] / a[0]; filter->b1 = b[1] / a[0]; filter->b2 = b[2] / a[0]; - filter->input_gain = b[0] / a[0]; filter->process = ALfilterState_processC; } -- cgit v1.2.3 From 45514ee32f8566d35d6153a64c575dfde256d941 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 00:07:39 -0700 Subject: Add some more restrict keywords --- Alc/mixer_c.c | 2 +- OpenAL32/Include/alFilter.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 7dca7a61..5b3e7b74 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -93,7 +93,7 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, A } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples) +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples) { ALuint i; if(numsamples > 1) diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 8012e398..5d5c2136 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -45,7 +45,7 @@ typedef struct ALfilterState { ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ - void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); + void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); } ALfilterState; #define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__)) @@ -95,7 +95,7 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample return outsmp; } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) { -- cgit v1.2.3 From 25d1b7bdba7b0c68e9e8e6f727c991cb69f24f4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 03:45:25 -0700 Subject: Remove broken autowah effect code It's been disabled forever, and I have no idea how to make it work properly. Better to just redo it when making something that works. --- Alc/ALc.c | 7 - Alc/effects/autowah.c | 271 ------------------------------------- CMakeLists.txt | 1 - OpenAL32/Include/alAuxEffectSlot.h | 1 - OpenAL32/Include/alEffect.h | 9 -- OpenAL32/alAuxEffectSlot.c | 1 - OpenAL32/alEffect.c | 7 - OpenAL32/alExtension.c | 3 - 8 files changed, 300 deletions(-) delete mode 100644 Alc/effects/autowah.c diff --git a/Alc/ALc.c b/Alc/ALc.c index bc6304d7..9d3553c8 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -666,13 +666,6 @@ static const ALCenums enumeration[] = { DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), -#if 0 - DECL(AL_AUTOWAH_ATTACK_TIME), - DECL(AL_AUTOWAH_PEAK_GAIN), - DECL(AL_AUTOWAH_RELEASE_TIME), - DECL(AL_AUTOWAH_RESONANCE), -#endif - DECL(AL_COMPRESSOR_ONOFF), DECL(AL_EQUALIZER_LOW_GAIN), diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c deleted file mode 100644 index c8b70595..00000000 --- a/Alc/effects/autowah.c +++ /dev/null @@ -1,271 +0,0 @@ -/** - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include - -#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 20hz (no amplitude) to - * 20khz (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[MAX_OUTPUT_CHANNELS]; - - /* Effect parameters */ - ALfloat AttackRate; - ALfloat ReleaseRate; - ALfloat Resonance; - ALfloat PeakGain; - ALfloat GainCtrl; - ALfloat Frequency; - - /* Samples processing */ - ALfilterState LowPass; -} ALautowahState; - -static ALvoid ALautowahState_Destruct(ALautowahState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device) -{ - state->Frequency = (ALfloat)device->Frequency; - return AL_TRUE; -} - -static ALvoid ALautowahState_update(ALautowahState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props) -{ - ALfloat attackTime, releaseTime; - - attackTime = props->Autowah.AttackTime * state->Frequency; - releaseTime = props->Autowah.ReleaseTime * state->Frequency; - - state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime); - state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime); - state->PeakGain = props->Autowah.PeakGain; - state->Resonance = props->Autowah.Resonance; - - ComputeAmbientGains(device->Dry, slot->Params.Gain, state->Gain); -} - -static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) -{ - ALuint it, kt; - ALuint base; - - for(base = 0;base < SamplesToDo;) - { - ALfloat temps[256]; - ALuint td = minu(256, SamplesToDo-base); - ALfloat gain = state->GainCtrl; - - for(it = 0;it < td;it++) - { - ALfloat smp = SamplesIn[0][it+base]; - ALfloat a[3], b[3]; - 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 = fabsf(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(20.0f, 20000.0f, 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_TAU * 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); - b[0] = (1.0f - cosf(w0)) / 2.0f; - b[1] = 1.0f - cosf(w0); - b[2] = (1.0f - cosf(w0)) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cosf(w0); - a[2] = 1.0f - alpha; - - state->LowPass.a1 = a[1] / a[0]; - state->LowPass.a2 = a[2] / a[0]; - state->LowPass.b0 = b[0] / a[0]; - state->LowPass.b1 = b[1] / a[0]; - state->LowPass.b2 = b[2] / a[0]; - - temps[it] = ALfilterState_processSingle(&state->LowPass, smp); - } - state->GainCtrl = gain; - - for(kt = 0;kt < NumChannels;kt++) - { - ALfloat gain = state->Gain[kt]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * temps[it]; - } - - base += td; - } -} - -DECLARE_DEFAULT_ALLOCATORS(ALautowahState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); - - -typedef struct ALautowahStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALautowahStateFactory; - -static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *UNUSED(factory)) -{ - ALautowahState *state; - - state = ALautowahState_New(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALautowahState, ALeffectState, state); - - state->AttackRate = 1.0f; - state->ReleaseRate = 1.0f; - state->Resonance = 2.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/CMakeLists.txt b/CMakeLists.txt index 85bc0dda..d8f15153 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -634,7 +634,6 @@ SET(ALC_OBJS Alc/ALc.c Alc/alcConfig.c Alc/alcRing.c Alc/bs2b.c - Alc/effects/autowah.c Alc/effects/chorus.c Alc/effects/compressor.c Alc/effects/dedicated.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 034ac217..d0c7c76c 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -155,7 +155,6 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); ALeffectStateFactory *ALnullStateFactory_getFactory(void); ALeffectStateFactory *ALreverbStateFactory_getFactory(void); -ALeffectStateFactory *ALautowahStateFactory_getFactory(void); ALeffectStateFactory *ALchorusStateFactory_getFactory(void); ALeffectStateFactory *ALcompressorStateFactory_getFactory(void); ALeffectStateFactory *ALdistortionStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index d20ef077..b97b0147 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -12,7 +12,6 @@ struct ALeffect; enum { EAXREVERB = 0, REVERB, - AUTOWAH, CHORUS, COMPRESSOR, DISTORTION, @@ -51,7 +50,6 @@ const struct ALeffectVtable T##_vtable = { \ 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; @@ -93,13 +91,6 @@ typedef union ALeffectProps { ALfloat LFReference; } Reverb; - struct { - ALfloat AttackTime; - ALfloat ReleaseTime; - ALfloat PeakGain; - ALfloat Resonance; - } Autowah; - struct { ALint Waveform; ALint Phase; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 14066cf9..796eec5b 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -452,7 +452,6 @@ void InitEffectFactoryMap(void) 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); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 1057f3c1..32053325 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -450,13 +450,6 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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; diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 609cc969..1a559d9c 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -38,9 +38,6 @@ const struct EffectList EffectList[] = { { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, -#if 0 - { "autowah", AUTOWAH, "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH }, -#endif { "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, { "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, { "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, -- cgit v1.2.3 From a6f41e4cb085c12d7adca291624ac3c33bebd3cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 04:09:01 -0700 Subject: Remove the last use of ALfilterState_processSingle --- Alc/effects/echo.c | 20 +++++++++++++++++--- OpenAL32/Include/alFilter.h | 17 ----------------- OpenAL32/alFilter.c | 1 - 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 163b6ecb..4d2fd6f4 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -124,10 +124,14 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const const ALuint tap1 = state->Tap[0].delay; const ALuint tap2 = state->Tap[1].delay; ALuint offset = state->Offset; - ALfloat smp; + ALfloat x[2], y[2], in, out; ALuint base; ALuint i, k; + x[0] = state->Filter.x[0]; + x[1] = state->Filter.x[1]; + y[0] = state->Filter.y[0]; + y[1] = state->Filter.y[1]; for(base = 0;base < SamplesToDo;) { ALfloat temps[128][2]; @@ -142,8 +146,14 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const // Apply damping and feedback gain to the second tap, and mix in the // new sample - smp = ALfilterState_processSingle(&state->Filter, temps[i][1]+SamplesIn[0][i+base]); - state->SampleBuffer[offset&mask] = smp * state->FeedGain; + in = temps[i][1] + SamplesIn[0][i+base]; + out = in*state->Filter.b0 + + x[0]*state->Filter.b1 + x[1]*state->Filter.b2 - + y[0]*state->Filter.a1 - y[1]*state->Filter.a2; + x[1] = x[0]; x[0] = in; + y[1] = y[0]; y[0] = out; + + state->SampleBuffer[offset&mask] = out * state->FeedGain; offset++; } @@ -166,6 +176,10 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const base += td; } + state->Filter.x[0] = x[0]; + state->Filter.x[1] = x[1]; + state->Filter.y[0] = y[0]; + state->Filter.y[1] = y[1]; state->Offset = offset; } diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 5d5c2136..a682d3ba 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -78,23 +78,6 @@ inline void ALfilterState_clear(ALfilterState *filter) void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); -inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample) -{ - ALfloat outsmp; - - outsmp = filter->b0 * sample + - filter->b1 * filter->x[0] + - filter->b2 * filter->x[1] - - filter->a1 * filter->y[0] - - filter->a2 * 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; -} - void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index da447c27..e7382919 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -37,7 +37,6 @@ extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); -extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); -- cgit v1.2.3 From b047eda1cbd9c8c1345c610b7ac236867b908cc6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 04:53:25 -0700 Subject: Avoid passing NULL to a parameter that must not be NULL --- Alc/helpers.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index bd345b6a..e065b022 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -858,8 +858,9 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t ob * sizeof(*vector_) may not equal base_size). */ temp = al_calloc(16, base_size + obj_size*obj_count); if(temp == NULL) return AL_FALSE; - memcpy(((ALubyte*)temp)+base_size, ((ALubyte*)*vecptr)+base_size, - obj_size*old_size); + if(*vecptr) + memcpy(((ALubyte*)temp)+base_size, ((ALubyte*)*vecptr)+base_size, + obj_size*old_size); al_free(*vecptr); *vecptr = temp; -- cgit v1.2.3 From d2eb866abeb699394a35610b4764c8e42acc71b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 04:54:27 -0700 Subject: Avoid a NULL deref when creating 0 auxiliary effect slots --- OpenAL32/alAuxEffectSlot.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 796eec5b..db084e5a 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -42,7 +42,6 @@ extern inline void UnlockEffectSlotsWrite(ALCcontext *context); extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); -static void AddEffectSlotList(ALCcontext *Context, ALeffectslot *first, ALeffectslot *last); static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot); @@ -97,12 +96,19 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo aluInitEffectPanning(slot); if(!first) first = slot; - if(last) ATOMIC_STORE(&last->next, slot); + if(last) ATOMIC_STORE(&last->next, slot, almemory_order_relaxed); last = slot; effectslots[cur] = slot->id; } - AddEffectSlotList(context, first, last); + if(last != NULL) + { + ALeffectslot *root = ATOMIC_LOAD(&context->ActiveAuxSlotList); + do { + ATOMIC_STORE(&last->next, root, almemory_order_relaxed); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot*, &context->ActiveAuxSlotList, + &root, first)); + } done: ALCcontext_DecRef(context); @@ -415,15 +421,6 @@ done: } -static void AddEffectSlotList(ALCcontext *context, ALeffectslot *start, ALeffectslot *last) -{ - ALeffectslot *root = ATOMIC_LOAD(&context->ActiveAuxSlotList); - do { - ATOMIC_STORE(&last->next, root, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot*, &context->ActiveAuxSlotList, - &root, start)); -} - static void RemoveEffectSlotList(ALCcontext *context, const ALeffectslot *slot) { ALCdevice *device = context->Device; -- cgit v1.2.3 From 5e11a738c6b18a367070450ec46dfb714fe433d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Jul 2016 11:45:20 -0700 Subject: Combine VECTOR_RESIZE and VECTOR_RESERVE --- Alc/backends/alsa.c | 2 +- Alc/backends/dsound.c | 2 +- Alc/backends/mmdevapi.c | 8 +--- Alc/backends/pulseaudio.c | 2 +- Alc/backends/qsa.c | 7 ++- Alc/backends/winmm.c | 6 +-- Alc/helpers.c | 107 ++++++++++++---------------------------------- Alc/vector.h | 39 +++++++++++++---- 8 files changed, 69 insertions(+), 104 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 280f5019..7a9045bb 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -242,7 +242,7 @@ static void clear_devlist(vector_DevMap *devlist) AL_STRING_DEINIT((i)->device_name); \ } while(0) VECTOR_FOR_EACH(DevMap, *devlist, FREE_DEV); - VECTOR_RESIZE(*devlist, 0); + VECTOR_RESIZE(*devlist, 0, 0); #undef FREE_DEV } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 1ff99352..da6fbacf 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -123,7 +123,7 @@ static void clear_devlist(vector_DevMap *list) { #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name) VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR); - VECTOR_RESIZE(*list, 0); + VECTOR_RESIZE(*list, 0, 0); #undef DEINIT_STR } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index f102e385..60d3be00 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -79,7 +79,7 @@ static void clear_devlist(vector_DevMap *list) (i)->devid = NULL; \ } while(0) VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); - VECTOR_RESIZE(*list, 0); + VECTOR_RESIZE(*list, 0, 0); #undef CLEAR_DEVMAP } @@ -258,11 +258,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve if(SUCCEEDED(hr) && count > 0) { clear_devlist(list); - if(!VECTOR_RESERVE(*list, count)) - { - IMMDeviceCollection_Release(coll); - return E_OUTOFMEMORY; - } + VECTOR_RESIZE(*list, 0, count); hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, eMultimedia, &defdev); diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index d317b576..220c1b7d 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -443,7 +443,7 @@ static void clear_devlist(vector_DevMap *list) #define DEINIT_STRS(i) (AL_STRING_DEINIT((i)->name),AL_STRING_DEINIT((i)->device_name)) VECTOR_FOR_EACH(DevMap, *list, DEINIT_STRS); #undef DEINIT_STRS - VECTOR_RESIZE(*list, 0); + VECTOR_RESIZE(*list, 0, 0); } diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index a1fbce63..b7923517 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -117,8 +117,7 @@ static void deviceList(int type, vector_DevMap *devmap) if(max_cards < 0) return; - VECTOR_RESERVE(*devmap, max_cards+1); - VECTOR_RESIZE(*devmap, 0); + VECTOR_RESIZE(*devmap, 0, max_cards+1); entry.name = strdup(qsaDevice); entry.card = 0; @@ -893,8 +892,8 @@ void alc_qsa_probe(enum DevProbe type) case ALL_DEVICE_PROBE: #define FREE_NAME(iter) free((iter)->name) VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); + VECTOR_RESIZE(DeviceNameMap, 0, 0); #undef FREE_NAME - VECTOR_RESIZE(DeviceNameMap, 0); deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); #define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name) @@ -905,8 +904,8 @@ void alc_qsa_probe(enum DevProbe type) case CAPTURE_DEVICE_PROBE: #define FREE_NAME(iter) free((iter)->name) VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); + VECTOR_RESIZE(CaptureNameMap, 0, 0); #undef FREE_NAME - VECTOR_RESIZE(CaptureNameMap, 0); deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); #define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name) diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 180f764b..6e990a35 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -46,7 +46,7 @@ static vector_al_string CaptureDevices; static void clear_devlist(vector_al_string *list) { VECTOR_FOR_EACH(al_string, *list, al_string_deinit); - VECTOR_RESIZE(*list, 0); + VECTOR_RESIZE(*list, 0, 0); } @@ -58,7 +58,7 @@ static void ProbePlaybackDevices(void) clear_devlist(&PlaybackDevices); numdevs = waveOutGetNumDevs(); - VECTOR_RESERVE(PlaybackDevices, numdevs); + VECTOR_RESIZE(PlaybackDevices, 0, numdevs); for(i = 0;i < numdevs;i++) { WAVEOUTCAPSW WaveCaps; @@ -101,7 +101,7 @@ static void ProbeCaptureDevices(void) clear_devlist(&CaptureDevices); numdevs = waveInGetNumDevs(); - VECTOR_RESERVE(CaptureDevices, numdevs); + VECTOR_RESIZE(CaptureDevices, 0, numdevs); for(i = 0;i < numdevs;i++) { WAVEINCAPSW WaveCaps; diff --git a/Alc/helpers.c b/Alc/helpers.c index e065b022..2a059c68 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -838,51 +838,6 @@ void SetRTPriority(void) } -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact) -{ - vector_ *vecptr = (vector_*)ptr; - if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count) - { - size_t old_size = (*vecptr ? (*vecptr)->Size : 0); - void *temp; - - /* Use the next power-of-2 size if we don't need to allocate the exact - * amount. This is preferred when regularly increasing the vector since - * it means fewer reallocations. Though it means it also wastes some - * memory. */ - if(exact == AL_FALSE && obj_count < INT_MAX) - obj_count = NextPowerOf2((ALuint)obj_count); - - /* Need to be explicit with the caller type's base size, because it - * could have extra padding before the start of the array (that is, - * sizeof(*vector_) may not equal base_size). */ - temp = al_calloc(16, base_size + obj_size*obj_count); - if(temp == NULL) return AL_FALSE; - if(*vecptr) - memcpy(((ALubyte*)temp)+base_size, ((ALubyte*)*vecptr)+base_size, - obj_size*old_size); - - al_free(*vecptr); - *vecptr = temp; - (*vecptr)->Capacity = obj_count; - (*vecptr)->Size = old_size; - } - return AL_TRUE; -} - -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count) -{ - vector_ *vecptr = (vector_*)ptr; - if(*vecptr || obj_count > 0) - { - if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE)) - return AL_FALSE; - (*vecptr)->Size = obj_count; - } - return AL_TRUE; -} - - extern inline void al_string_deinit(al_string *str); extern inline size_t al_string_length(const_al_string str); extern inline ALboolean al_string_empty(const_al_string str); @@ -896,9 +851,8 @@ void al_string_clear(al_string *str) * is to ensure we have space to add a null terminator in the string * data so it can be used as a C-style string. */ - VECTOR_RESERVE(*str, 1); - VECTOR_RESIZE(*str, 0); - *VECTOR_END(*str) = 0; + VECTOR_RESIZE(*str, 0, 1); + VECTOR_ELEM(*str, 0) = 0; } } @@ -930,11 +884,10 @@ void al_string_copy(al_string *str, const_al_string from) size_t len = al_string_length(from); size_t i; - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, len); + VECTOR_RESIZE(*str, len, len+1); for(i = 0;i < len;i++) VECTOR_ELEM(*str, i) = VECTOR_ELEM(from, i); - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, i) = 0; } void al_string_copy_cstr(al_string *str, const al_string_char_type *from) @@ -942,11 +895,10 @@ void al_string_copy_cstr(al_string *str, const al_string_char_type *from) size_t len = strlen(from); size_t i; - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, len); + VECTOR_RESIZE(*str, len, len+1); for(i = 0;i < len;i++) VECTOR_ELEM(*str, i) = from[i]; - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, i) = 0; } void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) @@ -954,18 +906,18 @@ void al_string_copy_range(al_string *str, const al_string_char_type *from, const size_t len = to - from; size_t i; - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, len); + VECTOR_RESIZE(*str, len, len+1); for(i = 0;i < len;i++) VECTOR_ELEM(*str, i) = from[i]; - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, i) = 0; } void al_string_append_char(al_string *str, const al_string_char_type c) { - VECTOR_RESERVE(*str, al_string_length(*str)+2); + size_t len = al_string_length(*str); + VECTOR_RESIZE(*str, len, len+2); VECTOR_PUSH_BACK(*str, c); - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, len+1) = 0; } void al_string_append_cstr(al_string *str, const al_string_char_type *from) @@ -976,27 +928,25 @@ void al_string_append_cstr(al_string *str, const al_string_char_type *from) size_t base = al_string_length(*str); size_t i; - VECTOR_RESERVE(*str, base+len+1); - VECTOR_RESIZE(*str, base+len); + VECTOR_RESIZE(*str, base+len, base+len+1); for(i = 0;i < len;i++) VECTOR_ELEM(*str, base+i) = from[i]; - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, base+i) = 0; } } void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { - if(to != from) + size_t len = to - from; + if(len != 0) { size_t base = al_string_length(*str); - size_t len = to - from; size_t i; - VECTOR_RESERVE(*str, base+len+1); - VECTOR_RESIZE(*str, base+len); + VECTOR_RESIZE(*str, base+len, base+len+1); for(i = 0;i < len;i++) VECTOR_ELEM(*str, base+i) = from[i]; - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, base+i) = 0; } } @@ -1006,10 +956,9 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from) int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) { - VECTOR_RESERVE(*str, len); - VECTOR_RESIZE(*str, len-1); + VECTOR_RESIZE(*str, len-1, len); WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); - *VECTOR_END(*str) = 0; + VECTOR_ELEM(*str, len-1) = 0; } } @@ -1018,11 +967,10 @@ void al_string_append_wcstr(al_string *str, const wchar_t *from) int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) { - size_t strlen = al_string_length(*str); - VECTOR_RESERVE(*str, strlen+len); - VECTOR_RESIZE(*str, strlen+len-1); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL); - *VECTOR_END(*str) = 0; + size_t base = al_string_length(*str); + VECTOR_RESIZE(*str, base+len-1, base+len); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); + VECTOR_ELEM(*str, base+len-1) = 0; } } @@ -1031,11 +979,10 @@ void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) { - size_t strlen = al_string_length(*str); - VECTOR_RESERVE(*str, strlen+len+1); - VECTOR_RESIZE(*str, strlen+len); - WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL); - *VECTOR_END(*str) = 0; + size_t base = al_string_length(*str); + VECTOR_RESIZE(*str, base+len, base+len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); + VECTOR_ELEM(*str, base+len) = 0; } } #endif diff --git a/Alc/vector.h b/Alc/vector.h index 12de74f5..b340fe71 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -31,12 +31,32 @@ typedef const _##N* const_##N; #define VECTOR_INIT_STATIC() NULL #define VECTOR_DEINIT(_x) do { al_free((_x)); (_x) = NULL; } while(0) -/* Helper to increase a vector's reserve. Do not call directly. */ -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact); -#define VECTOR_RESERVE(_x, _c) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c), AL_TRUE)) - -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count); -#define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c))) +#define VECTOR_RESIZE(_x, _s, _c) do { \ + size_t _size = (_s); \ + size_t _cap = (_c); \ + if(_size > _cap) \ + _cap = _size; \ + \ + if(!(_x) && _cap == 0) \ + break; \ + \ + if(((_x) ? (_x)->Capacity : 0) < _cap) \ + { \ + size_t old_size = ((_x) ? (_x)->Size : 0); \ + void *temp; \ + \ + temp = al_calloc(16, sizeof(*(_x)) + sizeof((_x)->Data[0])*_cap); \ + assert(temp != NULL); \ + if((_x)) \ + memcpy(((ALubyte*)temp)+sizeof(*(_x)), (_x)->Data, \ + sizeof((_x)->Data[0])*old_size); \ + \ + al_free((_x)); \ + (_x) = temp; \ + (_x)->Capacity = _cap; \ + } \ + (_x)->Size = _size; \ +} while(0) \ #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) #define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) @@ -44,8 +64,11 @@ ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj #define VECTOR_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) #define VECTOR_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) -#define VECTOR_PUSH_BACK(_x, _obj) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), VECTOR_SIZE(_x)+1, AL_FALSE) && \ - (((_x)->Data[(_x)->Size++] = (_obj)),AL_TRUE)) +#define VECTOR_PUSH_BACK(_x, _obj) do { \ + size_t _pbsize = VECTOR_SIZE(_x)+1; \ + VECTOR_RESIZE(_x, _pbsize, _pbsize); \ + (_x)->Data[(_x)->Size-1] = (_obj); \ +} while(0) #define VECTOR_POP_BACK(_x) ((void)((_x)->Size--)) #define VECTOR_BACK(_x) ((_x)->Data[(_x)->Size-1]) -- cgit v1.2.3 From 96e83f95eef5be8e1f64a1a2e61810cb7b82ff5c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Jul 2016 08:02:02 -0700 Subject: Don't try freeing the context in ReleaseThreadCtx Unfortunately on certain systems, the TLS callback is called in a restricted context, and isn't allowed to access certain messaging sub-systems. Such sub- systems may be used if the thread's context is freed, in turn freeing the device, which it tries to close. Ideally, the app shouldn't have tried to destroy a context while it was still current on a thread, or even leave a context current on a thread that's being destroyed,. So for now, release the context ref and print an ERR that it might be leaked. --- Alc/ALc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 9d3553c8..b6192317 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2376,23 +2376,23 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) void ALCcontext_IncRef(ALCcontext *context) { - uint ref; - ref = IncrementRef(&context->ref); + uint ref = IncrementRef(&context->ref); TRACEREF("%p increasing refcount to %u\n", context, ref); } void ALCcontext_DecRef(ALCcontext *context) { - uint ref; - ref = DecrementRef(&context->ref); + uint ref = DecrementRef(&context->ref); TRACEREF("%p decreasing refcount to %u\n", context, ref); if(ref == 0) FreeContext(context); } static void ReleaseThreadCtx(void *ptr) { - WARN("%p current for thread being destroyed\n", ptr); - ALCcontext_DecRef(ptr); + ALCcontext *context = ptr; + uint ref = DecrementRef(&context->ref); + TRACEREF("%p decreasing refcount to %u\n", context, ref); + ERR("Context %p current for thread being destroyed, possible leak!\n", context); } /* VerifyContext -- cgit v1.2.3 From b5b3ea95f899410a5392fb633ace74c10bbd9921 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 29 Jul 2016 21:55:43 -0700 Subject: Add a config to output first-, second-, or third-order ambisonics Currently incomplete, as second- and third-order output will not correctly handle B-Format input buffers. A standalone up-sampler will be needed, similar to the high-quality decoder. Also, output is ACN ordering with SN3D normalization. A config option will eventually be provided to change this if desired. --- Alc/ALc.c | 58 +++++++++++++++++++++++++++++++++++++++++++---- Alc/backends/coreaudio.c | 3 +++ Alc/backends/dsound.c | 6 +++++ Alc/backends/mmdevapi.c | 6 +++++ Alc/backends/opensl.c | 6 ++++- Alc/backends/pulseaudio.c | 3 +++ Alc/backends/wave.c | 5 ++++ Alc/backends/winmm.c | 3 +++ Alc/effects/reverb.c | 4 +++- Alc/panning.c | 42 +++++++++++++++++++++++++++++++++- OpenAL32/Include/alMain.h | 3 +++ 11 files changed, 132 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b6192317..13f881dd 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1294,6 +1294,9 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; case DevFmtBFormat3D: return "B-Format 3D"; + case DevFmtAmbi1: return "Ambisonics (1st Order)"; + case DevFmtAmbi2: return "Ambisonics (2nd Order)"; + case DevFmtAmbi3: return "Ambisonics (3rd Order)"; } return "(unknown channels)"; } @@ -1325,6 +1328,9 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) case DevFmtX61: return 7; case DevFmtX71: return 8; case DevFmtBFormat3D: return 4; + case DevFmtAmbi1: return 4; + case DevFmtAmbi2: return 9; + case DevFmtAmbi3: return 16; } return 0; } @@ -1493,6 +1499,41 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) device->RealOut.ChannelName[2] = Aux2; device->RealOut.ChannelName[3] = Aux3; break; + case DevFmtAmbi1: + device->RealOut.ChannelName[0] = Aux0; + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; + break; + case DevFmtAmbi2: + device->RealOut.ChannelName[0] = Aux0; + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; + device->RealOut.ChannelName[4] = Aux4; + device->RealOut.ChannelName[5] = Aux5; + device->RealOut.ChannelName[6] = Aux6; + device->RealOut.ChannelName[7] = Aux7; + device->RealOut.ChannelName[8] = Aux8; + break; + case DevFmtAmbi3: + device->RealOut.ChannelName[0] = Aux0; + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; + device->RealOut.ChannelName[4] = Aux4; + device->RealOut.ChannelName[5] = Aux5; + device->RealOut.ChannelName[6] = Aux6; + device->RealOut.ChannelName[7] = Aux7; + device->RealOut.ChannelName[8] = Aux8; + device->RealOut.ChannelName[9] = Aux9; + device->RealOut.ChannelName[10] = Aux10; + device->RealOut.ChannelName[11] = Aux11; + device->RealOut.ChannelName[12] = Aux12; + device->RealOut.ChannelName[13] = Aux13; + device->RealOut.ChannelName[14] = Aux14; + device->RealOut.ChannelName[15] = Aux15; + break; } } @@ -1535,6 +1576,9 @@ void SetDefaultChannelOrder(ALCdevice *device) case DevFmtX51: case DevFmtX61: case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: SetDefaultWFXChannelOrder(device); break; } @@ -1992,10 +2036,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /* Allocate extra channels for any post-filter output. */ size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); - if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) + if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2)) size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); else if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); + else if(device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) + size += 4 * sizeof(device->Dry.Buffer[0]); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) { @@ -2014,10 +2060,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->RealOut.NumChannels = device->Dry.NumChannels; } - if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) + if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || + device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) { - /* Higher-order high quality decoding requires upsampling first-order - * content, so make sure to mix it separately. + /* Higher-order rendering requires upsampling first-order content, so + * make sure to mix it separately. */ device->FOAOut.Buffer = device->RealOut.Buffer + device->RealOut.NumChannels; device->FOAOut.NumChannels = 4; @@ -3409,6 +3456,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "surround61", DevFmtX61 }, { "surround71", DevFmtX71 }, { "surround51rear", DevFmtX51Rear }, + { "ambisonic1", DevFmtAmbi1 }, + { "ambisonic2", DevFmtAmbi2 }, + { "ambisonic3", DevFmtAmbi3 }, }; size_t i; diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 4907f362..3d610fcb 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -529,6 +529,9 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) case DevFmtX61: case DevFmtX71: case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index da6fbacf..a477360c 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -473,6 +473,9 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: @@ -789,6 +792,9 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi SPEAKER_SIDE_RIGHT; break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: break; } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 60d3be00..03f2f56b 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -882,6 +882,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.dwChannelMask = MONO; break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: @@ -1523,6 +1526,9 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: return E_FAIL; } switch(device->FmtType) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 7b8fdb25..7e053b81 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -79,7 +79,11 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtBFormat3D: break; + case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: + break; } return 0; } diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 220c1b7d..a4d8438b 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -999,6 +999,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) mapname = "mono"; break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index af996233..85b4c720 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -277,6 +277,11 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: + device->FmtChans = DevFmtBFormat3D; + /*fall-through*/ case DevFmtBFormat3D: isbformat = 1; chanmask = 0; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 6e990a35..45547cee 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -562,6 +562,9 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) case DevFmtX61: case DevFmtX71: case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: return ALC_INVALID_ENUM; } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9b0dbe1d..7f69e06f 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -961,7 +961,9 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, props->Reverb.LateReverbGain, State); - else if(Device->FmtChans == DevFmtBFormat3D || Device->AmbiDecoder) + else if(Device->FmtChans == DevFmtBFormat3D || Device->FmtChans == DevFmtAmbi1 || + Device->FmtChans == DevFmtAmbi2 || Device->FmtChans == DevFmtAmbi3 || + Device->AmbiDecoder) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, diff --git a/Alc/panning.c b/Alc/panning.c index f81a6fc0..0c1bf06f 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -575,6 +575,9 @@ static void InitPanning(ALCdevice *device) break; case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: break; } @@ -593,6 +596,40 @@ static void InitPanning(ALCdevice *device) device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; } + else if(device->FmtChans == DevFmtAmbi1) + { + count = 4; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f/SN3D2N3DScale[i]; + device->Dry.Ambi.Map[i].Index = i; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + } + else if(device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) + { + count = (device->FmtChans == DevFmtAmbi3) ? 16 : + (device->FmtChans == DevFmtAmbi2) ? 9 : 1; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f/SN3D2N3DScale[i]; + device->Dry.Ambi.Map[i].Index = i; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; + + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; + } else { SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, @@ -835,10 +872,13 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf case DevFmtX51Rear: layout = "surround51rear"; break; case DevFmtX61: layout = "surround61"; break; case DevFmtX71: layout = "surround71"; break; - /* Mono, Stereo, and B-Fornat output don't use custom decoders. */ + /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ case DevFmtMono: case DevFmtStereo: case DevFmtBFormat3D: + case DevFmtAmbi1: + case DevFmtAmbi2: + case DevFmtAmbi3: break; } if(layout) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 05abc0fa..34533da9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -448,6 +448,9 @@ enum DevFmtChannels { DevFmtX51Rear = 0x80000000, DevFmtBFormat3D, + DevFmtAmbi1, + DevFmtAmbi2, + DevFmtAmbi3, DevFmtChannelsDefault = DevFmtStereo }; -- cgit v1.2.3 From 33a84f17ac78ac1f77b48fbd1193fafab5ca14e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 09:29:21 -0700 Subject: Add a stand-alone upsampler for higher-order ambisonic oputput --- Alc/ALc.c | 7 ++-- Alc/ALu.c | 7 ++++ Alc/bformatdec.c | 85 ++++++++++++++++++++++++++++++++++++++++++----- Alc/bformatdec.h | 10 ++++++ Alc/panning.c | 19 +++++++++++ OpenAL32/Include/alMain.h | 5 ++- 6 files changed, 122 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 13f881dd..8c6381ad 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2040,7 +2040,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); else if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); - else if(device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) + else if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) size += 4 * sizeof(device->Dry.Buffer[0]); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) @@ -2061,7 +2061,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || - device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) + (device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3)) { /* Higher-order rendering requires upsampling first-order content, so * make sure to mix it separately. @@ -2211,6 +2211,9 @@ static ALCvoid FreeDevice(ALCdevice *device) bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; + AL_STRING_DEINIT(device->DeviceName); al_free(device->Dry.Buffer); diff --git a/Alc/ALu.c b/Alc/ALu.c index c1478b50..d1a12672 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1534,6 +1534,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->Dry.Buffer, SamplesToDo ); } + else if(device->AmbiUp) + { + ambiup_process(device->AmbiUp, + device->RealOut.Buffer, device->RealOut.NumChannels, + device->FOAOut.Buffer, SamplesToDo + ); + } else if(device->Uhj_Encoder) { int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index d6cf25e2..3c175b33 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -130,6 +130,16 @@ static const ALfloat SquareMatrix[4][FB_Max][MAX_AMBI_COEFFS] = { }; static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS]; +static const ALfloat CubePoints[8][3] = { + { -0.577350269f, 0.577350269f, -0.577350269f }, + { 0.577350269f, 0.577350269f, -0.577350269f }, + { -0.577350269f, 0.577350269f, 0.577350269f }, + { 0.577350269f, 0.577350269f, 0.577350269f }, + { -0.577350269f, -0.577350269f, -0.577350269f }, + { 0.577350269f, -0.577350269f, -0.577350269f }, + { -0.577350269f, -0.577350269f, 0.577350269f }, + { 0.577350269f, -0.577350269f, 0.577350269f }, +}; static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { { { 0.25f, 0.14425f, 0.14425f, 0.14425f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, { { 0.25f, -0.14425f, 0.14425f, 0.14425f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, @@ -167,14 +177,8 @@ static void init_bformatdec(void) MixMatrixRow = SelectMixer(); - CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[0]); - CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[1]); - CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[2]); - CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[3]); - CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[4]); - CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[5]); - CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[6]); - CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[7]); + for(i = 0;i < COUNTOF(CubePoints);i++) + CalcDirectionCoeffs(CubePoints[i], 0.0f, CubeEncoder[i]); CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[0]); CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[1]); @@ -588,3 +592,68 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B } } } + + +typedef struct AmbiUpsampler { + alignas(16) ALfloat SamplesHF[4][BUFFERSIZE]; + alignas(16) ALfloat SamplesLF[4][BUFFERSIZE]; + + alignas(16) ALfloat ChannelMix[BUFFERSIZE]; + + BandSplitter XOver[4]; + + ALfloat Gains[8][MAX_OUTPUT_CHANNELS]; + ALuint NumChannels; +} AmbiUpsampler; + +AmbiUpsampler *ambiup_alloc() +{ + alcall_once(&bformatdec_inited, init_bformatdec); + return al_calloc(16, sizeof(AmbiUpsampler)); +} + +void ambiup_free(struct AmbiUpsampler *ambiup) +{ + al_free(ambiup); +} + +void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) +{ + ALfloat ratio; + ALuint i; + + ratio = 400.0f / (ALfloat)device->Frequency; + for(i = 0;i < 4;i++) + bandsplit_init(&ambiup->XOver[i], ratio); + + ambiup->NumChannels = COUNTOF(CubePoints); + for(i = 0;i < ambiup->NumChannels;i++) + ComputePanningGains(device->Dry, CubeEncoder[i], 1.0f, ambiup->Gains[i]); +} + +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +{ + ALuint i, j, k; + + for(i = 0;i < 4;i++) + bandsplit_process(&ambiup->XOver[i], ambiup->SamplesHF[i], ambiup->SamplesLF[i], + InSamples[i], SamplesToDo); + + for(k = 0;k < ambiup->NumChannels;k++) + { + memset(ambiup->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); + MixMatrixRow(ambiup->ChannelMix, CubeMatrix[k][FB_HighFreq], + ambiup->SamplesHF, 4, SamplesToDo); + MixMatrixRow(ambiup->ChannelMix, CubeMatrix[k][FB_LowFreq], + ambiup->SamplesLF, 4, SamplesToDo); + + for(j = 0;j < OutChannels;j++) + { + ALfloat gain = ambiup->Gains[k][j]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(i = 0;i < SamplesToDo;i++) + OutBuffer[j][i] += ambiup->ChannelMix[i] * gain; + } + } +} diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 3ad06373..be5a69f6 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -5,6 +5,7 @@ struct AmbDecConf; struct BFormatDec; +struct AmbiUpsampler; enum BFormatDecFlags { BFDF_DistanceComp = 1<<0 @@ -21,4 +22,13 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU /* Up-samples a first-order input to the decoder's configuration. */ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); +/* Stand-alone first-order upsampler. Kept here because it shares some stuff + * with bformatdec. + */ +struct AmbiUpsampler *ambiup_alloc(); +void ambiup_free(struct AmbiUpsampler *ambiup); +void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); + +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); + #endif /* BFORMATDEC_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 0c1bf06f..80909564 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -622,6 +622,9 @@ static void InitPanning(ALCdevice *device) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; + /* FOA output is always ACN+N3D for higher-order ambisonic output. The + * upsampler expects this and will convert it for output. + */ memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); for(i = 0;i < 4;i++) { @@ -629,6 +632,8 @@ static void InitPanning(ALCdevice *device) device->FOAOut.Ambi.Map[i].Index = i; } device->FOAOut.CoeffCount = 0; + + ambiup_reset(device->AmbiUp, device); } else { @@ -903,6 +908,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) { + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); } @@ -910,6 +917,16 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; + if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + { + if(!device->AmbiUp) + device->AmbiUp = ambiup_alloc(); + } + else + { + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; + } } if(!pconf) @@ -923,6 +940,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf return; } + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 34533da9..d07cb589 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -597,9 +597,12 @@ struct ALCdevice_struct /* High quality Ambisonic decoder */ struct BFormatDec *AmbiDecoder; - // Stereo-to-binaural filter + /* Stereo-to-binaural filter */ struct bs2b *Bs2b; + /* First-order ambisonic upsampler for higher-order output */ + struct AmbiUpsampler *AmbiUp; + /* Rendering mode. */ enum RenderMode Render_Mode; -- cgit v1.2.3 From d253719ead0034b867eded551a4839b48209572e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 09:35:54 -0700 Subject: Rename ambisonic channel config values to be shorter --- Alc/ALc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8c6381ad..c8ed3dd9 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3459,9 +3459,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "surround61", DevFmtX61 }, { "surround71", DevFmtX71 }, { "surround51rear", DevFmtX51Rear }, - { "ambisonic1", DevFmtAmbi1 }, - { "ambisonic2", DevFmtAmbi2 }, - { "ambisonic3", DevFmtAmbi3 }, + { "ambi1", DevFmtAmbi1 }, + { "ambi2", DevFmtAmbi2 }, + { "ambi3", DevFmtAmbi3 }, }; size_t i; -- cgit v1.2.3 From 0c5985374acf121f448cb84e101f8d8f9aebafe6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 10:16:29 -0700 Subject: Simplify a format check --- Alc/effects/reverb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7f69e06f..b89b1988 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -961,9 +961,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, props->Reverb.LateReverbGain, State); - else if(Device->FmtChans == DevFmtBFormat3D || Device->FmtChans == DevFmtAmbi1 || - Device->FmtChans == DevFmtAmbi2 || Device->FmtChans == DevFmtAmbi3 || - Device->AmbiDecoder) + else if(Device->AmbiDecoder || (Device->FmtChans >= DevFmtBFormat3D && + Device->FmtChans <= DevFmtAmbi3)) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, -- cgit v1.2.3 From e4380ece5e15e561902ec28aea14276b607ca930 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 15:56:22 -0700 Subject: Update alsoftrc.sample for proper txt filenames --- alsoftrc.sample | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index f8127549..fcf642dd 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -112,7 +112,7 @@ ## hrtf-paths: # Specifies a comma-separated list of paths containing HRTF data sets. The -# format of the files are described in hrtf.txt. The files within the +# format of the files are described in docs/hrtf.txt. The files within the # directories must have the .mhr file extension to be recognized. By default, # OS-dependent data paths will be used. They will also be used if the list # ends with a comma. On Windows this is: @@ -227,29 +227,29 @@ distance-comp = true ## quad: # Decoder configuration file for Quadrophonic channel output. See -# alsoft_ambdec.txt for a description of the file format. +# docs/ambdec.txt for a description of the file format. quad = ## surround51: # Decoder configuration file for 5.1 Surround (Side) channel output. See -# alsoft_ambdec.txt for a description of the file format. +# docs/ambdec.txt for a description of the file format. surround51 = ## surround51rear: # Decoder configuration file for 5.1 Surround (Rear) channel output. See -# alsoft_ambdec.txt for a description of the file format. +# docs/ambdec.txt for a description of the file format. surround51rear = ## surround61: # Decoder configuration file for 6.1 Surround channel output. See -# alsoft_ambdec.txt for a description of the file format. +# docs/ambdec.txt for a description of the file format. surround61 = ## surround71: # Decoder configuration file for 7.1 Surround channel output. See -# alsoft_ambdec.txt for a description of the file format. Note: This can be -# used to enable 3D7.1 with the appropriate configuration file and speaker -# placement. +# docs/ambdec.txt for a description of the file format. Note: This can be used +# to enable 3D7.1 with the appropriate configuration and speaker placement, +# see docs/3D7.1.txt. surround71 = ## -- cgit v1.2.3 From af258efda4d8e840e00859262fb894355bdbb270 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 16:24:46 -0700 Subject: Update alsoftrc.sample with the new channel configurations --- alsoftrc.sample | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index fcf642dd..ae965fba 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -48,7 +48,10 @@ ## channels: # Sets the output channel configuration. If left unspecified, one will try to # be detected from the system, and defaulting to stereo. The available values -# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71 +# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71, +# ambi1, ambi2, ambi3. Note that the ambi* configurations provide ambisonic +# channels of the given order (using ACN ordering and SN3D normalization by +# default), which need to be decoded to play correctly on speakers. #channels = ## sample-type: -- cgit v1.2.3 From 01af7b432d775fc2eb054fbbd3f131481c636e2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Jul 2016 16:32:26 -0700 Subject: Update alsoft-config for the ambisonic output configurations --- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 16 ++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index bbe179e1..c5fd0a2d 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -78,6 +78,10 @@ static const struct NameValuePair { { "6.1 Surround", "surround61" }, { "7.1 Surround", "surround71" }, + { "Ambisonics, 1st Order", "ambi1" }, + { "Ambisonics, 2nd Order", "ambi2" }, + { "Ambisonics, 3rd Order", "ambi3" }, + { "", "" } }, sampleTypeList[] = { { "Autodetect", "" }, diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 268b5ea9..0606d08c 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -62,7 +62,7 @@ - 120 + 110 50 78 22 @@ -79,7 +79,7 @@ float and converted to the output sample type as needed. - 10 + 0 50 101 21 @@ -95,7 +95,7 @@ float and converted to the output sample type as needed. - 10 + 0 20 101 21 @@ -111,7 +111,7 @@ float and converted to the output sample type as needed. - 120 + 110 20 78 22 @@ -129,7 +129,7 @@ to stereo output. - 370 + 380 20 96 22 @@ -191,7 +191,7 @@ to stereo output. - 280 + 290 20 81 21 @@ -207,7 +207,7 @@ to stereo output. - 280 + 290 50 81 21 @@ -223,7 +223,7 @@ to stereo output. - 370 + 380 50 78 22 -- cgit v1.2.3 From 4bcd2fbb2e79419c9b0973b7587df47d20004a5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jul 2016 07:46:38 -0700 Subject: Add an option to specify the ambisonic output configuration --- Alc/ALc.c | 15 +++++++++++++ Alc/panning.c | 57 ++++++++++++++++++++++++++--------------------- OpenAL32/Include/alMain.h | 12 ++++++++++ alsoftrc.sample | 5 +++++ 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c8ed3dd9..1119a270 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3427,6 +3427,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; device->IsHeadphones = AL_FALSE; + device->AmbiFmt = AmbiFormat_Default; device->NumUpdates = 4; device->UpdateSize = 1024; @@ -3544,6 +3545,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } almtx_init(&device->BackendLock, almtx_plain); + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) + { + if(strcasecmp(fmt, "fuma") == 0) + device->AmbiFmt = AmbiFormat_FuMa; + else if(strcasecmp(fmt, "acn+sn3d") == 0) + device->AmbiFmt = AmbiFormat_ACN_SN3D; + else if(strcasecmp(fmt, "acn+n3d") == 0) + device->AmbiFmt = AmbiFormat_ACN_N3D; + else + ERR("Unsupported ambi-format: %s\n", fmt); + } + if(DefaultEffect.type != AL_EFFECT_NULL) { device->DefaultSlot = (ALeffectslot*)device->_slot_mem; @@ -3706,6 +3719,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return NULL; } device->IsHeadphones = AL_FALSE; + device->AmbiFmt = AmbiFormat_Default; device->UpdateSize = samples; device->NumUpdates = 1; @@ -3903,6 +3917,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->IsHeadphones = AL_FALSE; + device->AmbiFmt = AmbiFormat_Default; ConfigValueUInt(NULL, NULL, "sources", &device->SourcesMax); if(device->SourcesMax == 0) device->SourcesMax = 256; diff --git a/Alc/panning.c b/Alc/panning.c index 80909564..685c3de6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -63,6 +63,10 @@ static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = { 15, /* P */ 9, /* Q */ }; +static const ALuint ACN2ACN[MAX_AMBI_COEFFS] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 +}; /* NOTE: These are scale factors as applied to Ambisonics content. Decoder * coefficients should be divided by these values to get proper N3D scalings. @@ -596,44 +600,45 @@ static void InitPanning(ALCdevice *device) device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; } - else if(device->FmtChans == DevFmtAmbi1) + else if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { - count = 4; - for(i = 0;i < count;i++) - { - device->Dry.Ambi.Map[i].Scale = 1.0f/SN3D2N3DScale[i]; - device->Dry.Ambi.Map[i].Index = i; - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; + const ALuint *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dcale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : + (device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale : + /*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale; - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - } - else if(device->FmtChans == DevFmtAmbi2 || device->FmtChans == DevFmtAmbi3) - { count = (device->FmtChans == DevFmtAmbi3) ? 16 : - (device->FmtChans == DevFmtAmbi2) ? 9 : 1; + (device->FmtChans == DevFmtAmbi2) ? 9 : + (device->FmtChans == DevFmtAmbi1) ? 4 : 1; for(i = 0;i < count;i++) { - device->Dry.Ambi.Map[i].Scale = 1.0f/SN3D2N3DScale[i]; - device->Dry.Ambi.Map[i].Index = i; + ALuint acn = acnmap[i]; + device->Dry.Ambi.Map[i].Scale = 1.0f/n3dcale[acn]; + device->Dry.Ambi.Map[i].Index = acn; } device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - /* FOA output is always ACN+N3D for higher-order ambisonic output. The - * upsampler expects this and will convert it for output. - */ - memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < 4;i++) + if(device->FmtChans == DevFmtAmbi1) { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; } - device->FOAOut.CoeffCount = 0; + else + { + /* FOA output is always ACN+N3D for higher-order ambisonic output. + * The upsampler expects this and will convert it for output. + */ + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; - ambiup_reset(device->AmbiUp, device); + ambiup_reset(device->AmbiUp, device); + } } else { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d07cb589..dff94487 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -463,6 +463,14 @@ inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType typ return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); } +enum AmbiFormat { + AmbiFormat_FuMa, /* FuMa channel order and normalization */ + AmbiFormat_ACN_SN3D, /* ACN channel order and SN3D normalization */ + AmbiFormat_ACN_N3D, /* ACN channel order and N3D normalization */ + + AmbiFormat_Default = AmbiFormat_ACN_SN3D +}; + extern const struct EffectList { const char *name; @@ -557,6 +565,10 @@ struct ALCdevice_struct enum DevFmtChannels FmtChans; enum DevFmtType FmtType; ALboolean IsHeadphones; + /* For DevFmtAmbi* output only, specifies the channel order and + * normalization. + */ + enum AmbiFormat AmbiFmt; al_string DeviceName; diff --git a/alsoftrc.sample b/alsoftrc.sample index ae965fba..444ebc6f 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -97,6 +97,11 @@ # disabled. #stereo-panning = uhj +## ambi-format: +# Specifies the channel order and normalization for the "ambi*" set of channel +# configurations. Valid settings are: fuma, acn+sn3d, acn+n3d +#ambi-format = acn+sn3d + ## hrtf: # Controls HRTF processing. These filters provide better spatialization of # sounds while using headphones, but do require a bit more CPU power. The -- cgit v1.2.3 From 2dd27568903033dfb017aaa85b53c6fa4abfd0de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jul 2016 08:03:26 -0700 Subject: Handle ambi-format with alsoft-config --- utils/alsoft-config/mainwindow.cpp | 24 ++++++++++++++++++++++++ utils/alsoft-config/mainwindow.ui | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index c5fd0a2d..80fbdf80 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -114,6 +114,13 @@ static const struct NameValuePair { { "UHJ", "uhj" }, { "Pair-Wise", "paired" }, + { "", "" } +}, ambiFormatList[] = { + { "Default", "" }, + { "ACN + SN3D", "acn+sn3d" }, + { "ACN + N3D", "acn+n3d" }, + { "Furse-Malham", "fuma" }, + { "", "" } }; @@ -229,6 +236,9 @@ MainWindow::MainWindow(QWidget *parent) : for(int i = 0;stereoPanList[i].name[0];i++) ui->stereoPanningComboBox->addItem(stereoPanList[i].name); ui->stereoPanningComboBox->adjustSize(); + for(int i = 0;ambiFormatList[i].name[0];i++) + ui->ambiFormatComboBox->addItem(ambiFormatList[i].name); + ui->ambiFormatComboBox->adjustSize(); int count; for(count = 0;resamplerList[count].name[0];count++) { @@ -316,6 +326,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(toggleHqState(int))); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -628,6 +639,18 @@ void MainWindow::loadConfig(const QString &fname) } } + QString ambiformat = settings.value("ambi-format").toString(); + ui->ambiFormatComboBox->setCurrentIndex(0); + if(ambiformat.isEmpty() == false) + { + QString str = getNameFromValue(ambiFormatList, ambiformat); + if(!str.isEmpty()) + { + int j = ui->ambiFormatComboBox->findText(str); + if(j > 0) ui->ambiFormatComboBox->setCurrentIndex(j); + } + } + bool hqmode = settings.value("decoder/hq-mode", false).toBool(); ui->decoderHQModeCheckBox->setChecked(hqmode); bool distcomp = settings.value("decoder/distance-comp", true).toBool(); @@ -855,6 +878,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("stereo-mode", getValueFromName(stereoModeList, ui->stereoModeCombo->currentText())); settings.setValue("stereo-panning", getValueFromName(stereoPanList, ui->stereoPanningComboBox->currentText())); + settings.setValue("ambi-format", getValueFromName(ambiFormatList, ui->ambiFormatComboBox->currentText())); settings.setValue("decoder/hq-mode", ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 0606d08c..0356d491 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -461,6 +461,29 @@ Pair-Wise uses standard pair-wise panning between Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + 270 + 130 + 111 + 21 + + + + Ambisonic Format: + + + + + + 390 + 130 + 131 + 22 + + + -- cgit v1.2.3 From bff5268ed49261db9bfe432a0439bb4d508d8997 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jul 2016 08:13:41 -0700 Subject: Remove DevFmtBFormat3D, which is covered by DevFmtAmbi1 --- Alc/ALc.c | 9 --------- Alc/backends/coreaudio.c | 1 - Alc/backends/dsound.c | 2 -- Alc/backends/mmdevapi.c | 2 -- Alc/backends/opensl.c | 1 - Alc/backends/pulseaudio.c | 1 - Alc/backends/wave.c | 7 +++---- Alc/backends/winmm.c | 1 - Alc/effects/reverb.c | 2 +- Alc/panning.c | 19 +------------------ OpenAL32/Include/alMain.h | 2 +- 11 files changed, 6 insertions(+), 41 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1119a270..cfd3a077 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1293,7 +1293,6 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) case DevFmtX51Rear: return "5.1 Surround (Rear)"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; - case DevFmtBFormat3D: return "B-Format 3D"; case DevFmtAmbi1: return "Ambisonics (1st Order)"; case DevFmtAmbi2: return "Ambisonics (2nd Order)"; case DevFmtAmbi3: return "Ambisonics (3rd Order)"; @@ -1327,7 +1326,6 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; - case DevFmtBFormat3D: return 4; case DevFmtAmbi1: return 4; case DevFmtAmbi2: return 9; case DevFmtAmbi3: return 16; @@ -1493,12 +1491,6 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) device->RealOut.ChannelName[6] = SideLeft; device->RealOut.ChannelName[7] = SideRight; break; - case DevFmtBFormat3D: - device->RealOut.ChannelName[0] = Aux0; - device->RealOut.ChannelName[1] = Aux1; - device->RealOut.ChannelName[2] = Aux2; - device->RealOut.ChannelName[3] = Aux3; - break; case DevFmtAmbi1: device->RealOut.ChannelName[0] = Aux0; device->RealOut.ChannelName[1] = Aux1; @@ -1575,7 +1567,6 @@ void SetDefaultChannelOrder(ALCdevice *device) case DevFmtQuad: case DevFmtX51: case DevFmtX61: - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 3d610fcb..cde3d505 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -528,7 +528,6 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index a477360c..bb38d516 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -472,7 +472,6 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) case DevFmtMono: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: @@ -791,7 +790,6 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 03f2f56b..bcef0a5f 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -881,7 +881,6 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.Format.nChannels = 1; OutputType.dwChannelMask = MONO; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: @@ -1525,7 +1524,6 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) OutputType.dwChannelMask = X7DOT1; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 7e053b81..0796c49a 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -79,7 +79,6 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index a4d8438b..f46386e4 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -998,7 +998,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) case DevFmtMono: mapname = "mono"; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 85b4c720..9bf5a727 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -249,7 +249,7 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) clearerr(self->mFile); if(GetConfigValueBool(NULL, "wave", "bformat", 0)) - device->FmtChans = DevFmtBFormat3D; + device->FmtChans = DevFmtAmbi1; switch(device->FmtType) { @@ -280,9 +280,8 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: - device->FmtChans = DevFmtBFormat3D; - /*fall-through*/ - case DevFmtBFormat3D: + /* .amb output requires FuMa */ + device->AmbiFmt = AmbiFormat_FuMa; isbformat = 1; chanmask = 0; break; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 45547cee..9d8f8e9d 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -561,7 +561,6 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index b89b1988..71c39f8c 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -961,7 +961,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, props->Reverb.LateReverbGain, State); - else if(Device->AmbiDecoder || (Device->FmtChans >= DevFmtBFormat3D && + else if(Device->AmbiDecoder || (Device->FmtChans >= DevFmtAmbi1 && Device->FmtChans <= DevFmtAmbi3)) Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, diff --git a/Alc/panning.c b/Alc/panning.c index 685c3de6..d4d7c25b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -578,29 +578,13 @@ static void InitPanning(ALCdevice *device) coeffcount = 16; break; - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: break; } - if(device->FmtChans == DevFmtBFormat3D) - { - count = 4; - for(i = 0;i < count;i++) - { - ALuint acn = FuMa2ACN[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; - device->Dry.Ambi.Map[i].Index = acn; - } - device->Dry.CoeffCount = 0; - device->Dry.NumChannels = count; - - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - } - else if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { const ALuint *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dcale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : @@ -885,7 +869,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ case DevFmtMono: case DevFmtStereo: - case DevFmtBFormat3D: case DevFmtAmbi1: case DevFmtAmbi2: case DevFmtAmbi3: diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index dff94487..3b6113ef 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -447,7 +447,7 @@ enum DevFmtChannels { /* Similar to 5.1, except using rear channels instead of sides */ DevFmtX51Rear = 0x80000000, - DevFmtBFormat3D, + /* Ambisonic formats should be kept together */ DevFmtAmbi1, DevFmtAmbi2, DevFmtAmbi3, -- cgit v1.2.3 From 48ff5d4ce8bd5f2d65c1aa8af77c2923d3be801c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jul 2016 08:17:08 -0700 Subject: Rename Ambisonics to Ambisonic in a couple places --- Alc/ALc.c | 6 +++--- utils/alsoft-config/mainwindow.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index cfd3a077..dbda46f1 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1293,9 +1293,9 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) case DevFmtX51Rear: return "5.1 Surround (Rear)"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; - case DevFmtAmbi1: return "Ambisonics (1st Order)"; - case DevFmtAmbi2: return "Ambisonics (2nd Order)"; - case DevFmtAmbi3: return "Ambisonics (3rd Order)"; + case DevFmtAmbi1: return "Ambisonic (1st Order)"; + case DevFmtAmbi2: return "Ambisonic (2nd Order)"; + case DevFmtAmbi3: return "Ambisonic (3rd Order)"; } return "(unknown channels)"; } diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 80fbdf80..309c4d7b 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -78,9 +78,9 @@ static const struct NameValuePair { { "6.1 Surround", "surround61" }, { "7.1 Surround", "surround71" }, - { "Ambisonics, 1st Order", "ambi1" }, - { "Ambisonics, 2nd Order", "ambi2" }, - { "Ambisonics, 3rd Order", "ambi3" }, + { "Ambisonic, 1st Order", "ambi1" }, + { "Ambisonic, 2nd Order", "ambi2" }, + { "Ambisonic, 3rd Order", "ambi3" }, { "", "" } }, sampleTypeList[] = { -- cgit v1.2.3 From 0fcd39c4c0205b8229df16f48b05cf0bf6600287 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Jul 2016 23:42:30 -0700 Subject: Don't store the looping state in the voice Certain operations on the buffer queue depend on the loop state to behave properly, so it should not be deferred until the async voice update occurs. --- Alc/ALu.c | 2 -- Alc/mixer.c | 2 +- OpenAL32/Include/alSource.h | 6 ++---- OpenAL32/alSource.c | 29 ++++++++++++++++++++--------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d1a12672..70fe7f49 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -437,7 +437,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->SendOut[i].Channels = SendSlots[i]->NumChannels; } } - voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); /* Calculate the stepping value */ Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; @@ -906,7 +905,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro voice->SendOut[i].Channels = SendSlots[i]->NumChannels; } } - voice->Looping = ATOMIC_LOAD(&props->Looping, almemory_order_relaxed); /* Transform source to listener space (convert to head relative) */ if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE) diff --git a/Alc/mixer.c b/Alc/mixer.c index b2af812a..9f6ec9d1 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -388,9 +388,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam BufferListItem = ATOMIC_LOAD(&Source->current_buffer); DataPosInt = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); DataPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); NumChannels = Source->NumChannels; SampleSize = Source->SampleSize; - Looping = voice->Looping; increment = voice->Step; IrSize = (Device->Hrtf ? Device->Hrtf->irSize : 0); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index db138be1..74987b34 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -28,8 +28,6 @@ typedef struct ALvoice { /** Current target parameters used for mixing. */ ALint Step; - ALboolean Looping; - /* If not 'moving', gain/coefficients are set directly without fading. */ ALboolean Moving; @@ -74,7 +72,6 @@ struct ALsourceProps { ATOMIC(ALfloat) Direction[3]; ATOMIC(ALfloat) Orientation[2][3]; ATOMIC(ALboolean) HeadRelative; - ATOMIC(ALboolean) Looping; ATOMIC(enum DistanceModel) DistanceModel; ATOMIC(ALboolean) DirectChannels; @@ -128,7 +125,6 @@ typedef struct ALsource { ALfloat Direction[3]; ALfloat Orientation[2][3]; ALboolean HeadRelative; - ALboolean Looping; enum DistanceModel DistanceModel; ALboolean DirectChannels; @@ -192,6 +188,8 @@ typedef struct ALsource { ATOMIC(ALuint) position; ATOMIC(ALuint) position_fraction; + ATOMIC(ALboolean) looping; + /** Current buffer sample info. */ ALuint NumChannels; ALuint SampleSize; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 4a50d217..0e98f2f5 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -642,8 +642,9 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_LOOPING: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - Source->Looping = (ALboolean)*values; - DO_UPDATEPROPS(); + WriteLock(&Source->queue_lock); + ATOMIC_STORE(&Source->looping, *values); + WriteUnlock(&Source->queue_lock); return AL_TRUE; case AL_BUFFER: @@ -1198,7 +1199,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_LOOPING: - *values = Source->Looping; + *values = ATOMIC_LOAD(&Source->looping); return AL_TRUE; case AL_BUFFER: @@ -1285,7 +1286,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFERS_PROCESSED: ReadLock(&Source->queue_lock); - if(Source->Looping || Source->SourceType != AL_STREAMING) + if(ATOMIC_LOAD(&Source->looping) || Source->SourceType != AL_STREAMING) { /* Buffers on a looping source are in a perpetual state of * PENDING, so don't report any as PROCESSED */ @@ -2605,6 +2606,13 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); WriteLock(&source->queue_lock); + if(ATOMIC_LOAD(&source->looping) || source->SourceType != AL_STREAMING) + { + WriteUnlock(&source->queue_lock); + /* Trying to unqueue buffers on a looping or non-streaming source. */ + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + } + /* Find the new buffer queue head */ OldTail = ATOMIC_LOAD(&source->queue); Current = ATOMIC_LOAD(&source->current_buffer); @@ -2617,10 +2625,10 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint OldTail = next; } } - if(source->Looping || source->SourceType != AL_STREAMING || i != nb) + if(i != nb) { WriteUnlock(&source->queue_lock); - /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */ + /* Trying to unqueue pending buffers. */ SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } @@ -2693,7 +2701,6 @@ static void InitSourceParams(ALsource *Source) Source->RefDistance = 1.0f; Source->MaxDistance = FLT_MAX; Source->RollOffFactor = 1.0f; - Source->Looping = AL_FALSE; Source->Gain = 1.0f; Source->MinGain = 0.0f; Source->MaxGain = 1.0f; @@ -2741,6 +2748,8 @@ static void InitSourceParams(ALsource *Source) ATOMIC_INIT(&Source->position, 0); ATOMIC_INIT(&Source->position_fraction, 0); + ATOMIC_INIT(&Source->looping, AL_FALSE); + ATOMIC_INIT(&Source->Update, NULL); ATOMIC_INIT(&Source->FreeList, NULL); } @@ -2832,7 +2841,6 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *co almemory_order_relaxed); } ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); - ATOMIC_STORE(&props->Looping, source->Looping, almemory_order_relaxed); ATOMIC_STORE(&props->DistanceModel, context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel, almemory_order_relaxed @@ -3168,6 +3176,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ALuint readPos, readPosFrac; ALuint totalBufferLen; ALdouble offset = 0.0; + ALboolean looping; ALuint refcount; ReadLock(&Source->queue_lock); @@ -3186,6 +3195,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + + looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); } while(refcount != ReadRef(&device->MixCount)); while(BufferList != NULL) @@ -3202,7 +3213,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device } assert(Buffer != NULL); - if(Source->Looping) + if(looping) readPos %= totalBufferLen; else { -- cgit v1.2.3 From f1e3f0762ba7ffdfb45693b92c0ebde2f18414d4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Aug 2016 09:16:12 -0700 Subject: Use the ACN and N3D map and scale lookup tables in SetChannelMap --- Alc/panning.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index d4d7c25b..2d7502ec 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -345,6 +345,8 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff const ChannelMap *chanmap, size_t count, ALuint *outcount, ALboolean isfuma) { + const ALuint *acnmap = isfuma ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dscale = isfuma ? FuMa2N3DScale : UnitScale; size_t j, k; ALuint i; @@ -362,19 +364,10 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff if(devchans[i] != chanmap[j].ChanName) continue; - if(isfuma) + for(k = 0;k < MAX_AMBI_COEFFS;++k) { - /* Reformat FuMa -> ACN/N3D */ - for(k = 0;k < MAX_AMBI_COEFFS;++k) - { - ALuint acn = FuMa2ACN[k]; - ambicoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn]; - } - } - else - { - for(k = 0;k < MAX_AMBI_COEFFS;++k) - ambicoeffs[i][k] = chanmap[j].Config[k]; + ALuint acn = acnmap[k]; + ambicoeffs[i][acn] = chanmap[j].Config[k] / n3dscale[acn]; } break; } @@ -587,9 +580,9 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { const ALuint *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dcale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : - (device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale : - /*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale; + const ALfloat *n3dscale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : + (device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale : + /*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale; count = (device->FmtChans == DevFmtAmbi3) ? 16 : (device->FmtChans == DevFmtAmbi2) ? 9 : @@ -597,7 +590,7 @@ static void InitPanning(ALCdevice *device) for(i = 0;i < count;i++) { ALuint acn = acnmap[i]; - device->Dry.Ambi.Map[i].Scale = 1.0f/n3dcale[acn]; + device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn]; device->Dry.Ambi.Map[i].Index = acn; } device->Dry.CoeffCount = 0; -- cgit v1.2.3 From 2b3c7f211c45616826f0fda721b2ccd3fe53f13a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Aug 2016 08:34:25 -0700 Subject: Add 'restrict' to another parameter --- OpenAL32/Include/alFilter.h | 2 +- OpenAL32/alFilter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index a682d3ba..a74cd211 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -80,7 +80,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); -inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) +inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples) { if(numsamples >= 2) { diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index e7382919..daf981d5 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -36,7 +36,7 @@ extern inline void UnlockFiltersWrite(ALCdevice *device); extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); -extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); +extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); -- cgit v1.2.3 From 3b2d8d394984da94fd286c5d57dfd68f22e2740b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Aug 2016 17:36:42 -0700 Subject: Use al_calloc/al_free in more places --- OpenAL32/alEffect.c | 10 +++++----- OpenAL32/alFilter.c | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 32053325..65a4dcb6 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -60,11 +60,11 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) device = context->Device; for(cur = 0;cur < n;cur++) { - ALeffect *effect = calloc(1, sizeof(ALeffect)); + ALeffect *effect = al_calloc(16, sizeof(ALeffect)); ALenum err = AL_OUT_OF_MEMORY; if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR) { - free(effect); + al_free(effect); alDeleteEffects(cur, effects); SET_ERROR_AND_GOTO(context, err, done); } @@ -76,7 +76,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) { FreeThunkEntry(effect->id); memset(effect, 0, sizeof(ALeffect)); - free(effect); + al_free(effect); alDeleteEffects(cur, effects); SET_ERROR_AND_GOTO(context, err, done); @@ -115,7 +115,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) FreeThunkEntry(effect->id); memset(effect, 0, sizeof(*effect)); - free(effect); + al_free(effect); } done: @@ -381,7 +381,7 @@ ALvoid ReleaseALEffects(ALCdevice *device) // Release effect structure FreeThunkEntry(temp->id); memset(temp, 0, sizeof(ALeffect)); - free(temp); + al_free(temp); } } diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index daf981d5..fa3496c9 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -59,7 +59,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) device = context->Device; for(cur = 0;cur < n;cur++) { - ALfilter *filter = calloc(1, sizeof(ALfilter)); + ALfilter *filter = al_calloc(16, sizeof(ALfilter)); if(!filter) { alDeleteFilters(cur, filters); @@ -74,7 +74,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) { FreeThunkEntry(filter->id); memset(filter, 0, sizeof(ALfilter)); - free(filter); + al_free(filter); alDeleteFilters(cur, filters); SET_ERROR_AND_GOTO(context, err, done); @@ -113,7 +113,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) FreeThunkEntry(filter->id); memset(filter, 0, sizeof(*filter)); - free(filter); + al_free(filter); } done: @@ -641,7 +641,7 @@ ALvoid ReleaseALFilters(ALCdevice *device) // Release filter structure FreeThunkEntry(temp->id); memset(temp, 0, sizeof(ALfilter)); - free(temp); + al_free(temp); } } -- cgit v1.2.3 From 48b954160ec5bffab04d072cdfd0685ca521c407 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Aug 2016 19:07:35 -0700 Subject: Look for the correct DLL for JACK on Windows --- Alc/backends/jack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index cfdc62e8..517f99a4 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -94,7 +94,12 @@ static ALCboolean jack_load(void) #ifdef HAVE_DYNLOAD if(!jack_handle) { - jack_handle = LoadLib("libjack.so.0"); +#ifdef _WIN32 +#define JACKLIB "libjack.dll" +#else +#define JACKLIB "libjack.so.0" +#endif + jack_handle = LoadLib(JACKLIB); if(!jack_handle) return ALC_FALSE; -- cgit v1.2.3 From 232293792dad120da91f62b92ea270a58e065a91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Aug 2016 20:42:25 -0700 Subject: Constify some variables --- Alc/ALu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 70fe7f49..8b885121 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1284,7 +1284,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro static void CalcSourceParams(ALvoice *voice, ALCcontext *context) { ALsource *source = voice->Source; - ALbufferlistitem *BufferListItem; + const ALbufferlistitem *BufferListItem; struct ALsourceProps *first; struct ALsourceProps *props; @@ -1294,7 +1294,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context) BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); while(BufferListItem != NULL) { - ALbuffer *buffer; + const ALbuffer *buffer; if((buffer=BufferListItem->buffer) != NULL) { if(buffer->FmtChannels == FmtMono) -- cgit v1.2.3 From f775f2537920ef0031926872c57332e99c048f63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Aug 2016 21:06:00 -0700 Subject: Modify NumUpdates for different sample rates instead of UpdateSize Not that this really changes anything since the CoreAudio backend doesn't honor the ALCdevice's buffer metrics, nor accurately report the device's actual metrics. But it clears up warnings from a non-multiple-of-four update size if the sample rate causes it to change. --- Alc/backends/coreaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index cde3d505..24aeabd4 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -238,7 +238,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) if(device->Frequency != streamFormat.mSampleRate) { - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + device->NumUpdates = (ALuint)((ALuint64)device->NumUpdates * streamFormat.mSampleRate / device->Frequency); device->Frequency = streamFormat.mSampleRate; -- cgit v1.2.3 From 6117cb2377b95e5800b6ff4febe77cf029d58e64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Aug 2016 18:47:26 -0700 Subject: Mix gain steps using SIMD with Neon --- Alc/mixer_neon.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 073f62c8..48e41703 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -89,6 +89,30 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer if(step != 0.0f && Counter > 0) { ALuint minsize = minu(BufferSize, Counter); + /* Mix with applying gain steps in aligned multiples of 4. */ + if(minsize-pos > 3) + { + float32x4_t step4; + gain4 = vsetq_lane_f32(gain, gain4, 0); + gain4 = vsetq_lane_f32(gain + step, gain4, 1); + gain4 = vsetq_lane_f32(gain + step + step, gain4, 2); + gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3); + step4 = vdupq_n_f32(step + step + step + step); + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + gain4 = vaddq_f32(gain4, step4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(minsize-pos > 3); + /* NOTE: gain4 now represents the next four gains after the + * last four mixed samples, so the lowest element represents + * the next gain to apply. + */ + gain = vgetq_lane_f32(gain4, 0); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ for(;pos < minsize;pos++) { OutBuffer[c][OutPos+pos] += data[pos]*gain; -- cgit v1.2.3 From 56d3598020f553681ec88b830c21218556a80a84 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Aug 2016 22:31:08 -0700 Subject: Avoid checking DeferUpdates for each source state change --- OpenAL32/alSource.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 0e98f2f5..fb2ada10 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2316,13 +2316,21 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) context->MaxVoices = newcount; } - for(i = 0;i < n;i++) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) { - source = LookupSource(context, sources[i]); - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); source->new_state = AL_PLAYING; - else + } + } + else + { + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); SetSourceState(source, context, AL_PLAYING); + } } UnlockContext(context); @@ -2354,13 +2362,21 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) } LockContext(context); - for(i = 0;i < n;i++) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) { - source = LookupSource(context, sources[i]); - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); source->new_state = AL_PAUSED; - else + } + } + else + { + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); SetSourceState(source, context, AL_PAUSED); + } } UnlockContext(context); -- cgit v1.2.3 From 9a60184bf63640f0b12b9e4a894b98e83212d229 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Aug 2016 20:43:54 -0700 Subject: Set a JACK error message handler when initializing the backend JACK2 will print error messages to stderr if it fails to connect to a server. Users who don't normally use JACK but have the client lib installed will get those messages even though OpenAL Soft will continue on to find a working backend without trouble. So to avoid it, set an error message handler that'll log them as warnings. This isn't that great because there's no way to tell whether the error messages are due to the server not running, or some other problem. And it resets the callback to the default afterward even if it may have been set to something else before. JACK2, which is what needs this workaround in the first place, doesn't export the jack_error_callback pointer to properly save and restore it. --- Alc/backends/jack.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 517f99a4..283df297 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -54,6 +54,7 @@ static const ALCchar jackDevice[] = "JACK Default"; MAGIC(jack_get_ports); \ MAGIC(jack_free); \ MAGIC(jack_get_sample_rate); \ + MAGIC(jack_set_error_function); \ MAGIC(jack_set_process_callback); \ MAGIC(jack_set_buffer_size_callback); \ MAGIC(jack_set_buffer_size); \ @@ -78,6 +79,7 @@ JACK_FUNCS(MAKE_FUNC); #define jack_get_ports pjack_get_ports #define jack_free pjack_free #define jack_get_sample_rate pjack_get_sample_rate +#define jack_set_error_function pjack_set_error_function #define jack_set_process_callback pjack_set_process_callback #define jack_set_buffer_size_callback pjack_set_buffer_size_callback #define jack_set_buffer_size pjack_set_buffer_size @@ -537,6 +539,11 @@ static void ALCjackPlayback_unlock(ALCjackPlayback *self) } +static void jack_msg_handler(const char *message) +{ + WARN("%s\n", message); +} + typedef struct ALCjackBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCjackBackendFactory; @@ -552,7 +559,10 @@ static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self) if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0)) ClientOptions |= JackNoStartServer; + + jack_set_error_function(jack_msg_handler); client = jack_client_open("alsoft", ClientOptions, &status, NULL); + jack_set_error_function(NULL); if(client == NULL) { WARN("jack_client_open() failed, 0x%02x\n", status); -- cgit v1.2.3 From c6c6e3324dd9d5d864b6146ca7a6c6e6369978a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Aug 2016 23:20:35 -0700 Subject: Decode directly from B-Format to HRTF instead of a cube Last time this attempted to average the HRIRs according to their contribution to a given B-Format channel as if they were loudspeakers, as well as averaging the HRIR delays. The latter part resulted in the loss of the ITD (inter-aural time delay), a key component of HRTF. This time, the HRIRs are averaged similar to above, except instead of averaging the delays, they're applied to the resulting coefficients (for example, a delay of 8 would apply the HRIR starting at the 8th sample of the target HRIR). This does roughly double the IR length, as the largest delay is about 35 samples while the filter is normally 32 samples. However, this is still smaller the original data set IR (which was 256 samples), it also only needs to be applied to 4 channels for first-order ambisonics, rather than the 8-channel cube. So it's doing twice as much work per sample, but only working on half the number of samples. Additionally, since the resulting HRIRs no longer rely on an extra delay line, a more efficient HRTF mixing function can be made that doesn't use one. Such a function can also avoid the per-sample stepping parameters the original uses. --- Alc/ALu.c | 2 +- Alc/hrtf.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ Alc/hrtf.h | 7 +++++ Alc/panning.c | 61 ++++++++++++++----------------------- OpenAL32/Include/alMain.h | 5 ++-- 5 files changed, 109 insertions(+), 42 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8b885121..41377eec 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1505,7 +1505,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(lidx != -1 && ridx != -1) { HrtfMixerFunc HrtfMix = SelectHrtfMixer(); - ALuint irsize = device->Hrtf->irSize; + ALuint irsize = device->Hrtf_IrSize; MixHrtfParams hrtfparams; memset(&hrtfparams, 0, sizeof(hrtfparams)); for(c = 0;c < device->Dry.NumChannels;c++) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9e927e4f..ed99554c 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -172,6 +172,82 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi } +ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels) +{ + ALuint total_hrirs = 0; + ALuint max_length = 0; + ALuint eidx, aidx, i, j; + ALfloat scale; + + assert(NumChannels == 4); + + for(eidx = 0;eidx < Hrtf->evCount;++eidx) + { + const ALfloat elev = (ALfloat)eidx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2; + const ALuint evoffset = Hrtf->evOffset[eidx]; + const ALuint azcount = Hrtf->azCount[eidx]; + + for(aidx = 0;aidx < azcount;++aidx) + { + ALfloat ambcoeffs[4]; + const ALshort *fir; + ALuint length, delay; + ALuint lidx, ridx; + ALfloat x, y, z; + ALfloat azi; + + lidx = evoffset + aidx; + ridx = evoffset + ((azcount - aidx) % azcount); + + azi = (ALfloat)aidx/(ALfloat)azcount * -F_TAU; + x = cosf(azi) * cosf(elev); + y = sinf(azi) * cosf(elev); + z = sinf(elev); + + ambcoeffs[0] = 1.0f; + ambcoeffs[1] = y / 1.732050808f; + ambcoeffs[2] = z / 1.732050808f; + ambcoeffs[3] = x / 1.732050808f; + + /* Apply left ear response */ + delay = Hrtf->delays[lidx]; + fir = &Hrtf->coeffs[lidx * Hrtf->irSize]; + length = minu(delay + Hrtf->irSize, HRIR_LENGTH); + for(i = 0;i < NumChannels;++i) + { + for(j = delay;j < length;++j) + coeffs[i][j][0] += fir[j-delay]/32767.0f * ambcoeffs[i]; + } + max_length = maxu(max_length, length); + + /* Apply right ear response */ + delay = Hrtf->delays[ridx]; + fir = &Hrtf->coeffs[ridx * Hrtf->irSize]; + length = minu(delay + Hrtf->irSize, HRIR_LENGTH); + for(i = 0;i < NumChannels;++i) + { + for(j = delay;j < length;++j) + coeffs[i][j][1] += fir[j-delay]/32767.0f * ambcoeffs[i]; + } + max_length = maxu(max_length, length); + + total_hrirs++; + } + } + + scale = (ALfloat)total_hrirs; + for(i = 0;i < NumChannels;++i) + { + for(j = 0;j < max_length;++j) + { + coeffs[i][j][0] /= scale; + coeffs[i][j][1] /= scale; + } + } + return max_length; +} + + static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index e9f04d49..d3ecfc3c 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -42,4 +42,11 @@ void FreeHrtfList(vector_HrtfEntry *list); void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); +/* Produces HRTF filter coefficients for decoding B-Format. The result will + * have ACN ordering with N3D normalization. NumChannels must currently be 4, + * for first-order. Returns the maximum impulse-response length of the + * generated coefficients. + */ +ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels); + #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 2d7502ec..65506303 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -758,52 +758,35 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin static void InitHrtfPanning(ALCdevice *device) { - static const enum Channel CubeChannels[MAX_OUTPUT_CHANNELS] = { - UpperFrontLeft, UpperFrontRight, UpperBackLeft, UpperBackRight, - LowerFrontLeft, LowerFrontRight, LowerBackLeft, LowerBackRight, - InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel, - InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel - }; - static const ChannelMap Cube8Cfg[8] = { - { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } }, - { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } }, - { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } }, - { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } }, - { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } }, - { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } }, - }; - static const struct { - enum Channel Channel; - ALfloat Angle; - ALfloat Elevation; - } CubeInfo[8] = { - { UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) }, - { UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) }, - { UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) }, - { UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) }, - { LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) }, - { LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) }, - { LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) }, - { LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) }, - }; - const ChannelMap *chanmap = Cube8Cfg; - size_t count = COUNTOF(Cube8Cfg); - ALuint i; + ALfloat hrtf_coeffs[4][HRIR_LENGTH][2]; + size_t count = 4; + ALuint i, j; - SetChannelMap(CubeChannels, device->Dry.Ambi.Coeffs, chanmap, count, - &device->Dry.NumChannels, AL_TRUE); - device->Dry.CoeffCount = 4; + for(i = 0;i < count;i++) + { + device->Dry.Ambi.Map[i].Scale = 1.0f; + device->Dry.Ambi.Map[i].Index = i; + } + device->Dry.CoeffCount = 0; + device->Dry.NumChannels = count; device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; + memset(hrtf_coeffs, 0, sizeof(hrtf_coeffs)); + device->Hrtf_IrSize = BuildBFormatHrtf(device->Hrtf, hrtf_coeffs, device->Dry.NumChannels); + + /* Round up to the nearest multiple of 8 */ + device->Hrtf_IrSize = (device->Hrtf_IrSize+7)&~7; for(i = 0;i < device->Dry.NumChannels;i++) { - int chan = GetChannelIndex(CubeChannels, CubeInfo[i].Channel); - GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 0.0f, - device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay); + for(j = 0;j < HRIR_LENGTH;j++) + { + device->Hrtf_Params[i].Coeffs[j][0] = hrtf_coeffs[i][j][0]; + device->Hrtf_Params[i].Coeffs[j][1] = hrtf_coeffs[i][j][1]; + } + device->Hrtf_Params[i].Delay[0] = 0; + device->Hrtf_Params[i].Delay[1] = 0; } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3b6113ef..3d099ca2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -599,9 +599,10 @@ struct ALCdevice_struct ALCenum Hrtf_Status; /* HRTF filter state for dry buffer content */ - HrtfState Hrtf_State[8]; - HrtfParams Hrtf_Params[8]; + HrtfState Hrtf_State[4]; + HrtfParams Hrtf_Params[4]; ALuint Hrtf_Offset; + ALuint Hrtf_IrSize; /* UHJ encoder state */ struct Uhj2Encoder *Uhj_Encoder; -- cgit v1.2.3 From 770e2ff7ed516a41721d6cde931b3cefc07c190e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Aug 2016 05:26:36 -0700 Subject: Use a more specialized mixer function for B-Format to HRTF --- Alc/ALu.c | 19 ++++++++----------- Alc/mixer_c.c | 1 + Alc/mixer_defs.h | 12 ++++++++++++ Alc/mixer_inc.c | 33 +++++++++++++++++++++++++++++++++ Alc/mixer_neon.c | 1 + Alc/mixer_sse.c | 1 + Alc/panning.c | 18 ++++-------------- OpenAL32/Include/alMain.h | 4 ++-- OpenAL32/Include/alu.h | 4 ++++ 9 files changed, 66 insertions(+), 27 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 41377eec..a9f89de0 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -94,18 +94,18 @@ extern inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); -static inline HrtfMixerFunc SelectHrtfMixer(void) +static inline HrtfDirectMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_SSE; + return MixDirectHrtf_SSE; #endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_Neon; + return MixDirectHrtf_Neon; #endif - return MixHrtf_C; + return MixDirectHrtf_C; } @@ -1504,17 +1504,14 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) int ridx = GetChannelIdxByName(device->RealOut, FrontRight); if(lidx != -1 && ridx != -1) { - HrtfMixerFunc HrtfMix = SelectHrtfMixer(); + HrtfDirectMixerFunc HrtfMix = SelectHrtfMixer(); ALuint irsize = device->Hrtf_IrSize; - MixHrtfParams hrtfparams; - memset(&hrtfparams, 0, sizeof(hrtfparams)); for(c = 0;c < device->Dry.NumChannels;c++) { - hrtfparams.Current = &device->Hrtf_Params[c]; - hrtfparams.Target = &device->Hrtf_Params[c]; HrtfMix(device->RealOut.Buffer, lidx, ridx, - device->Dry.Buffer[c], 0, device->Hrtf_Offset, 0, - irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo + device->Dry.Buffer[c], device->Hrtf_Offset, irsize, + device->Hrtf_Coeffs[c], device->Hrtf_Values[c], + SamplesToDo ); } device->Hrtf_Offset += SamplesToDo; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 5b3e7b74..c79d6061 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -166,6 +166,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_C +#define MixDirectHrtf MixDirectHrtf_C #include "mixer_inc.c" #undef MixHrtf diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 8b934c58..be88379b 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -25,6 +25,10 @@ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ri const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); +void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Offset, const ALuint IrSize, + ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); void MixRow_C(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], @@ -35,6 +39,10 @@ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); +void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Offset, const ALuint IrSize, + ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], @@ -78,6 +86,10 @@ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); +void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Offset, const ALuint IrSize, + ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index e9d81c2a..25dc2b58 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -114,3 +114,36 @@ skip_stepping: OutPos += todo; } } + +void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, + const ALfloat *data, ALuint Offset, const ALuint IrSize, + ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALuint BufferSize) +{ + ALfloat out[MAX_UPDATE_SAMPLES][2]; + ALfloat insample; + ALuint pos, i; + + for(pos = 0;pos < BufferSize;) + { + ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES); + + for(i = 0;i < todo;i++) + { + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + insample = *(data++); + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + out[i][0] = Values[Offset&HRIR_MASK][0]; + out[i][1] = Values[Offset&HRIR_MASK][1]; + } + + for(i = 0;i < todo;i++) + OutBuffer[lidx][pos+i] += out[i][0]; + for(i = 0;i < todo;i++) + OutBuffer[ridx][pos+i] += out[i][1]; + pos += todo; + } +} diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 48e41703..fcd0387a 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -70,6 +70,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_Neon +#define MixDirectHrtf MixDirectHrtf_Neon #include "mixer_inc.c" #undef MixHrtf diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 120ac4a0..6914e500 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -186,6 +186,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_SSE +#define MixDirectHrtf MixDirectHrtf_SSE #include "mixer_inc.c" #undef MixHrtf diff --git a/Alc/panning.c b/Alc/panning.c index 65506303..70494547 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -758,9 +758,8 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin static void InitHrtfPanning(ALCdevice *device) { - ALfloat hrtf_coeffs[4][HRIR_LENGTH][2]; size_t count = 4; - ALuint i, j; + ALuint i; for(i = 0;i < count;i++) { @@ -773,21 +772,12 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; - memset(hrtf_coeffs, 0, sizeof(hrtf_coeffs)); - device->Hrtf_IrSize = BuildBFormatHrtf(device->Hrtf, hrtf_coeffs, device->Dry.NumChannels); + memset(device->Hrtf_Coeffs, 0, sizeof(device->Hrtf_Coeffs)); + device->Hrtf_IrSize = BuildBFormatHrtf(device->Hrtf, device->Hrtf_Coeffs, + device->Dry.NumChannels); /* Round up to the nearest multiple of 8 */ device->Hrtf_IrSize = (device->Hrtf_IrSize+7)&~7; - for(i = 0;i < device->Dry.NumChannels;i++) - { - for(j = 0;j < HRIR_LENGTH;j++) - { - device->Hrtf_Params[i].Coeffs[j][0] = hrtf_coeffs[i][j][0]; - device->Hrtf_Params[i].Coeffs[j][1] = hrtf_coeffs[i][j][1]; - } - device->Hrtf_Params[i].Delay[0] = 0; - device->Hrtf_Params[i].Delay[1] = 0; - } } static void InitUhjPanning(ALCdevice *device) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3d099ca2..b173c515 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -599,8 +599,8 @@ struct ALCdevice_struct ALCenum Hrtf_Status; /* HRTF filter state for dry buffer content */ - HrtfState Hrtf_State[4]; - HrtfParams Hrtf_Params[4]; + alignas(16) ALfloat Hrtf_Values[4][HRIR_LENGTH][2]; + alignas(16) ALfloat Hrtf_Coeffs[4][HRIR_LENGTH][2]; ALuint Hrtf_Offset; ALuint Hrtf_IrSize; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 9913a117..1d922881 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -167,6 +167,10 @@ typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize); +typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Offset, + const ALuint IrSize, ALfloat (*restrict Coeffs)[2], + ALfloat (*restrict Values)[2], ALuint BufferSize); #define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ -- cgit v1.2.3 From e13c6bca207d5a7659fca03a9576bcab6ea7728e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 17 Aug 2016 05:34:09 -0700 Subject: Only use the cube points for generating the ambisonic HRTF coefficients Using all the HRIRs seems to have problems with volume balancing, due in part to HRTF data sets not having uniform enough measurements for a simple decoder matrix to work (and generating a proper one that would work better is not that easy). This still maintains the benefits of decoding ambisonics directly to HRTF, namely that it only needs to filter the 4 ambisonic channels and can use more optimized HRTF filtering methods on those channels. It can also be improved further with frequency-dependent processing baked into the generated coefficients, incurring no extra run-time cost for it. --- Alc/hrtf.c | 128 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 56 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index ed99554c..46d814d9 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -174,76 +174,92 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels) { - ALuint total_hrirs = 0; + static const struct { + ALfloat elevation; + ALfloat azimuth; + } CubePoints[8] = { + { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, + { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, + { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, + }; + static const ALfloat CubeMatrix[8][MAX_AMBI_COEFFS] = { + { 0.25f, 0.14425f, 0.14425f, 0.14425f }, + { 0.25f, -0.14425f, 0.14425f, 0.14425f }, + { 0.25f, 0.14425f, 0.14425f, -0.14425f }, + { 0.25f, -0.14425f, 0.14425f, -0.14425f }, + { 0.25f, 0.14425f, -0.14425f, 0.14425f }, + { 0.25f, -0.14425f, -0.14425f, 0.14425f }, + { 0.25f, 0.14425f, -0.14425f, -0.14425f }, + { 0.25f, -0.14425f, -0.14425f, -0.14425f }, + }; + ALuint lidx[8], ridx[8]; + ALuint min_delay = HRTF_HISTORY_LENGTH; ALuint max_length = 0; - ALuint eidx, aidx, i, j; - ALfloat scale; + ALuint i, j, c; assert(NumChannels == 4); - for(eidx = 0;eidx < Hrtf->evCount;++eidx) + for(c = 0;c < 8;c++) { - const ALfloat elev = (ALfloat)eidx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2; - const ALuint evoffset = Hrtf->evOffset[eidx]; - const ALuint azcount = Hrtf->azCount[eidx]; + ALuint evidx[2]; + ALuint evoffset; + ALuint azidx[2]; + ALuint azcount; + ALfloat mu; - for(aidx = 0;aidx < azcount;++aidx) - { - ALfloat ambcoeffs[4]; - const ALshort *fir; - ALuint length, delay; - ALuint lidx, ridx; - ALfloat x, y, z; - ALfloat azi; - - lidx = evoffset + aidx; - ridx = evoffset + ((azcount - aidx) % azcount); - - azi = (ALfloat)aidx/(ALfloat)azcount * -F_TAU; - x = cosf(azi) * cosf(elev); - y = sinf(azi) * cosf(elev); - z = sinf(elev); - - ambcoeffs[0] = 1.0f; - ambcoeffs[1] = y / 1.732050808f; - ambcoeffs[2] = z / 1.732050808f; - ambcoeffs[3] = x / 1.732050808f; - - /* Apply left ear response */ - delay = Hrtf->delays[lidx]; - fir = &Hrtf->coeffs[lidx * Hrtf->irSize]; - length = minu(delay + Hrtf->irSize, HRIR_LENGTH); - for(i = 0;i < NumChannels;++i) - { - for(j = delay;j < length;++j) - coeffs[i][j][0] += fir[j-delay]/32767.0f * ambcoeffs[i]; - } - max_length = maxu(max_length, length); + /* Calculate elevation index. */ + CalcEvIndices(Hrtf->evCount, CubePoints[c].elevation, evidx, &mu); + if(mu >= 0.5f) evidx[0] = evidx[1]; - /* Apply right ear response */ - delay = Hrtf->delays[ridx]; - fir = &Hrtf->coeffs[ridx * Hrtf->irSize]; - length = minu(delay + Hrtf->irSize, HRIR_LENGTH); - for(i = 0;i < NumChannels;++i) - { - for(j = delay;j < length;++j) - coeffs[i][j][1] += fir[j-delay]/32767.0f * ambcoeffs[i]; - } - max_length = maxu(max_length, length); + azcount = Hrtf->azCount[evidx[0]]; + evoffset = Hrtf->evOffset[evidx[0]]; - total_hrirs++; - } + /* Calculate azimuth index for this elevation. */ + CalcAzIndices(azcount, CubePoints[c].azimuth, azidx, &mu); + if(mu >= 0.5f) azidx[0] = azidx[1]; + + /* Calculate indices for left and right channels. */ + lidx[c] = evoffset + azidx[0]; + ridx[c] = evoffset + ((azcount-azidx[0]) % azcount); + + min_delay = minu(min_delay, minu(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); } - scale = (ALfloat)total_hrirs; - for(i = 0;i < NumChannels;++i) + for(c = 0;c < 8;c++) { - for(j = 0;j < max_length;++j) + const ALshort *fir; + ALuint length; + ALuint delay; + + fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; + delay = Hrtf->delays[lidx[c]] - min_delay; + length = minu(delay + Hrtf->irSize, HRIR_LENGTH); + for(i = 0;i < NumChannels;++i) + { + ALuint k = 0; + for(j = delay;j < length;++j) + coeffs[i][j][0] += fir[k++]/32767.0f * CubeMatrix[c][i]; + } + max_length = maxu(max_length, length); + + fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; + delay = Hrtf->delays[ridx[c]] - min_delay; + length = minu(delay + Hrtf->irSize, HRIR_LENGTH); + for(i = 0;i < NumChannels;++i) { - coeffs[i][j][0] /= scale; - coeffs[i][j][1] /= scale; + ALuint k = 0; + for(j = delay;j < length;++j) + coeffs[i][j][1] += fir[k++]/32767.0f * CubeMatrix[c][i]; } + max_length = maxu(max_length, length); } + TRACE("Skipped min delay: %u, new combined length: %u\n", min_delay, max_length); + return max_length; } -- cgit v1.2.3 From d16954c34ebb4bfbd4e7ef27090b01d6f4ff9261 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 18 Aug 2016 23:33:08 -0700 Subject: Fix HRTF index calculations for B-Format coefficients The CalcEvIndices and CalcAzIndices methods were dependent on the FPU being in round-to-zero mode, which is not the case for panning initialization. And since we just need the closest index and don't need to lerp between them, it's better to just directly calculate the index with rounding. --- Alc/hrtf.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 46d814d9..3be30d95 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -206,26 +206,25 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(c = 0;c < 8;c++) { - ALuint evidx[2]; + ALuint evidx, azidx; ALuint evoffset; - ALuint azidx[2]; ALuint azcount; - ALfloat mu; /* Calculate elevation index. */ - CalcEvIndices(Hrtf->evCount, CubePoints[c].elevation, evidx, &mu); - if(mu >= 0.5f) evidx[0] = evidx[1]; + evidx = (ALuint)floorf((F_PI_2 + CubePoints[c].elevation) * + (Hrtf->evCount-1)/F_PI + 0.5f); + evidx = minu(evidx, Hrtf->evCount-1); - azcount = Hrtf->azCount[evidx[0]]; - evoffset = Hrtf->evOffset[evidx[0]]; + azcount = Hrtf->azCount[evidx]; + evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - CalcAzIndices(azcount, CubePoints[c].azimuth, azidx, &mu); - if(mu >= 0.5f) azidx[0] = azidx[1]; + azidx = (ALuint)floorf((F_TAU+CubePoints[c].azimuth) * + azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ - lidx[c] = evoffset + azidx[0]; - ridx[c] = evoffset + ((azcount-azidx[0]) % azcount); + lidx[c] = evoffset + azidx; + ridx[c] = evoffset + ((azcount-azidx) % azcount); min_delay = minu(min_delay, minu(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); } -- cgit v1.2.3 From 846cdd472da81fefefca8ffa113d32824bc297c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Aug 2016 03:05:42 -0700 Subject: Band-split the HRIRs when building the ambisonic decoder filters This allows each HRIR to contribute a frequency-dependent response, essentially acting like a dual-band decoder playing over the cube speaker array. --- Alc/bformatdec.c | 20 +++++++++--------- Alc/bformatdec.h | 15 +++++++++++++ Alc/hrtf.c | 64 +++++++++++++++++++++++++++++++++++++------------------- 3 files changed, 68 insertions(+), 31 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 3c175b33..356423ce 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -10,14 +10,7 @@ #include "almalloc.h" -typedef struct BandSplitter { - ALfloat coeff; - ALfloat lp_z1; - ALfloat lp_z2; - ALfloat hp_z1; -} BandSplitter; - -static void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult) +void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult) { ALfloat w = freq_mult * F_TAU; ALfloat cw = cosf(w); @@ -31,8 +24,15 @@ static void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult) splitter->hp_z1 = 0.0f; } -static void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, - const ALfloat *input, ALuint count) +void bandsplit_clear(BandSplitter *splitter) +{ + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, + const ALfloat *input, ALuint count) { ALfloat coeff, d, x; ALfloat z1, z2; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index be5a69f6..433603dd 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -22,6 +22,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU /* Up-samples a first-order input to the decoder's configuration. */ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); + /* Stand-alone first-order upsampler. Kept here because it shares some stuff * with bformatdec. */ @@ -31,4 +32,18 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); + +/* Band splitter. Splits a signal into two phase-matching frequency bands. */ +typedef struct BandSplitter { + ALfloat coeff; + ALfloat lp_z1; + ALfloat lp_z2; + ALfloat hp_z1; +} BandSplitter; + +void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult); +void bandsplit_clear(BandSplitter *splitter); +void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, + const ALfloat *input, ALuint count); + #endif /* BFORMATDEC_H */ diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3be30d95..b11fb9a8 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -28,6 +28,7 @@ #include "alMain.h" #include "alSource.h" #include "alu.h" +#include "bformatdec.h" #include "hrtf.h" #include "compat.h" @@ -187,20 +188,22 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, }; - static const ALfloat CubeMatrix[8][MAX_AMBI_COEFFS] = { - { 0.25f, 0.14425f, 0.14425f, 0.14425f }, - { 0.25f, -0.14425f, 0.14425f, 0.14425f }, - { 0.25f, 0.14425f, 0.14425f, -0.14425f }, - { 0.25f, -0.14425f, 0.14425f, -0.14425f }, - { 0.25f, 0.14425f, -0.14425f, 0.14425f }, - { 0.25f, -0.14425f, -0.14425f, 0.14425f }, - { 0.25f, 0.14425f, -0.14425f, -0.14425f }, - { 0.25f, -0.14425f, -0.14425f, -0.14425f }, + static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = { + { { 0.25f, 0.14425f, 0.14425f, 0.14425f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, + { { 0.25f, -0.14425f, 0.14425f, 0.14425f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, + { { 0.25f, 0.14425f, 0.14425f, -0.14425f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, + { { 0.25f, -0.14425f, 0.14425f, -0.14425f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, + { { 0.25f, 0.14425f, -0.14425f, 0.14425f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, + { { 0.25f, -0.14425f, -0.14425f, 0.14425f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, + { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, + { { 0.25f, -0.14425f, -0.14425f, -0.14425f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; + BandSplitter splitter; + ALfloat temps[3][HRIR_LENGTH]; ALuint lidx[8], ridx[8]; ALuint min_delay = HRTF_HISTORY_LENGTH; ALuint max_length = 0; - ALuint i, j, c; + ALuint i, j, c, b; assert(NumChannels == 4); @@ -229,33 +232,52 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ min_delay = minu(min_delay, minu(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); } + memset(temps, 0, sizeof(temps)); + bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); for(c = 0;c < 8;c++) { const ALshort *fir; - ALuint length; ALuint delay; + /* Band-split left HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; + for(i = 0;i < Hrtf->irSize;i++) + temps[2][i] = fir[i] / 32767.0f; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + + /* Add to the left output coefficients with the specified delay. */ delay = Hrtf->delays[lidx[c]] - min_delay; - length = minu(delay + Hrtf->irSize, HRIR_LENGTH); for(i = 0;i < NumChannels;++i) { - ALuint k = 0; - for(j = delay;j < length;++j) - coeffs[i][j][0] += fir[k++]/32767.0f * CubeMatrix[c][i]; + for(b = 0;b < 2;b++) + { + ALuint k = 0; + for(j = delay;j < HRIR_LENGTH;++j) + coeffs[i][j][0] += temps[b][k++] * CubeMatrix[c][b][i]; + } } - max_length = maxu(max_length, length); + max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); + /* Band-split right HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; + for(i = 0;i < Hrtf->irSize;i++) + temps[2][i] = fir[i] / 32767.0f; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + + /* Add to the right output coefficients with the specified delay. */ delay = Hrtf->delays[ridx[c]] - min_delay; - length = minu(delay + Hrtf->irSize, HRIR_LENGTH); for(i = 0;i < NumChannels;++i) { - ALuint k = 0; - for(j = delay;j < length;++j) - coeffs[i][j][1] += fir[k++]/32767.0f * CubeMatrix[c][i]; + for(b = 0;b < 2;b++) + { + ALuint k = 0; + for(j = delay;j < HRIR_LENGTH;++j) + coeffs[i][j][1] += temps[b][k++] * CubeMatrix[c][b][i]; + } } - max_length = maxu(max_length, length); + max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); } TRACE("Skipped min delay: %u, new combined length: %u\n", min_delay, max_length); -- cgit v1.2.3 From bd054632e0ba42ad93dd3bcad54042a126a65646 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Aug 2016 23:59:11 -0700 Subject: Remove an unneeded typedef --- Alc/vector.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Alc/vector.h b/Alc/vector.h index b340fe71..4bb92458 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -7,11 +7,6 @@ #include "almalloc.h" -/* "Base" vector type, designed to alias with the actual vector types. */ -typedef struct vector__s { - size_t Capacity; - size_t Size; -} *vector_; #define TYPEDEF_VECTOR(T, N) typedef struct { \ size_t Capacity; \ -- cgit v1.2.3 From dc8b7814c771d08abe61656b745e7763a010a3a3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Aug 2016 18:56:01 -0700 Subject: Avoid resupplying unneeded source updates The source's voice holds a copy of the last properties it received, so listener updates can make sources recalculate internal properties from that stored copy. --- Alc/ALc.c | 4 +-- Alc/ALu.c | 79 +++++++++++++++++++++++++++++---------------- OpenAL32/Include/alSource.h | 71 +++++++++++++++++++++------------------- OpenAL32/alAuxEffectSlot.c | 2 +- OpenAL32/alListener.c | 18 ----------- OpenAL32/alState.c | 9 ------ 6 files changed, 91 insertions(+), 92 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dbda46f1..f5965716 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1602,8 +1602,6 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) { ALsizei pos; - UpdateListenerProps(context); - LockUIntMapRead(&context->SourceMap); V0(device->Backend,lock)(); for(pos = 0;pos < context->SourceMap.size;pos++) @@ -1626,6 +1624,8 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) } V0(device->Backend,unlock)(); UnlockUIntMapRead(&context->SourceMap); + + UpdateListenerProps(context); UpdateAllSourceProps(context); } ReadUnlock(&context->PropLock); diff --git a/Alc/ALu.c b/Alc/ALu.c index a9f89de0..115c9c59 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -228,7 +228,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state) } -static void CalcListenerParams(ALCcontext *Context) +static ALboolean CalcListenerParams(ALCcontext *Context) { ALlistener *Listener = Context->Listener; ALfloat N[3], V[3], U[3], P[3]; @@ -237,7 +237,7 @@ static void CalcListenerParams(ALCcontext *Context) aluVector vel; props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel); - if(!props) return; + if(!props) return AL_FALSE; /* AT then UP */ N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed); @@ -288,6 +288,8 @@ static void CalcListenerParams(ALCcontext *Context) ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, &Listener->FreeList, &first, props) == 0); + + return AL_TRUE; } static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) @@ -1281,7 +1283,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } } -static void CalcSourceParams(ALvoice *voice, ALCcontext *context) +static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean force) { ALsource *source = voice->Source; const ALbufferlistitem *BufferListItem; @@ -1289,33 +1291,54 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context) struct ALsourceProps *props; props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); - if(!props) return; - - BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); - while(BufferListItem != NULL) + if(!props) { - const ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) + if(!force) + return; + BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + while(BufferListItem != NULL) { - if(buffer->FmtChannels == FmtMono) - CalcAttnSourceParams(voice, props, buffer, context); - else - CalcNonAttnSourceParams(voice, props, buffer, context); - break; + const ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + if(buffer->FmtChannels == FmtMono) + CalcAttnSourceParams(voice, &voice->Props, buffer, context); + else + CalcNonAttnSourceParams(voice, &voice->Props, buffer, context); + break; + } + BufferListItem = BufferListItem->next; } - BufferListItem = BufferListItem->next; } - - /* WARNING: A livelock is theoretically possible if another thread keeps - * changing the freelist head without giving this a chance to actually swap - * in the old container (practically impossible with this little code, - * but...). - */ - first = ATOMIC_LOAD(&source->FreeList); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props) == 0); + else + { + BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + while(BufferListItem != NULL) + { + const ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + if(buffer->FmtChannels == FmtMono) + CalcAttnSourceParams(voice, props, buffer, context); + else + CalcNonAttnSourceParams(voice, props, buffer, context); + break; + } + BufferListItem = BufferListItem->next; + } + voice->Props = *props; + + /* WARNING: A livelock is theoretically possible if another thread keeps + * changing the freelist head without giving this a chance to actually swap + * in the old container (practically impossible with this little code, + * but...). + */ + first = ATOMIC_LOAD(&source->FreeList); + do { + ATOMIC_STORE(&props->next, first, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, + &source->FreeList, &first, props) == 0); + } } @@ -1327,7 +1350,7 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) IncrementRef(&ctx->UpdateCount); if(!ATOMIC_LOAD(&ctx->HoldUpdates)) { - CalcListenerParams(ctx); + ALboolean force = CalcListenerParams(ctx); while(slot) { CalcEffectSlotParams(slot, ctx->Device); @@ -1342,7 +1365,7 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) if(source->state != AL_PLAYING && source->state != AL_PAUSED) voice->Source = NULL; else - CalcSourceParams(voice, ctx); + CalcSourceParams(voice, ctx, force); } } IncrementRef(&ctx->UpdateCount); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 74987b34..b288937a 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -22,40 +22,6 @@ typedef struct ALbufferlistitem { } ALbufferlistitem; -typedef struct ALvoice { - struct ALsource *volatile Source; - - /** Current target parameters used for mixing. */ - ALint Step; - - /* If not 'moving', gain/coefficients are set directly without fading. */ - ALboolean Moving; - - ALboolean IsHrtf; - - ALuint Offset; /* Number of output samples mixed since starting. */ - - alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; - - BsincState SincState; - - struct { - ALfloat (*Buffer)[BUFFERSIZE]; - ALuint Channels; - } DirectOut; - - struct { - ALfloat (*Buffer)[BUFFERSIZE]; - ALuint Channels; - } SendOut[MAX_SENDS]; - - struct { - DirectParams Direct; - SendParams Send[MAX_SENDS]; - } Chan[MAX_INPUT_CHANNELS]; -} ALvoice; - - struct ALsourceProps { ATOMIC(ALfloat) Pitch; ATOMIC(ALfloat) Gain; @@ -108,6 +74,43 @@ struct ALsourceProps { ATOMIC(struct ALsourceProps*) next; }; + +typedef struct ALvoice { + struct ALsourceProps Props; + + struct ALsource *volatile Source; + + /** Current target parameters used for mixing. */ + ALint Step; + + /* If not 'moving', gain/coefficients are set directly without fading. */ + ALboolean Moving; + + ALboolean IsHrtf; + + ALuint Offset; /* Number of output samples mixed since starting. */ + + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; + + BsincState SincState; + + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint Channels; + } DirectOut; + + struct { + ALfloat (*Buffer)[BUFFERSIZE]; + ALuint Channels; + } SendOut[MAX_SENDS]; + + struct { + DirectParams Direct; + SendParams Send[MAX_SENDS]; + } Chan[MAX_INPUT_CHANNELS]; +} ALvoice; + + typedef struct ALsource { /** Source properties. */ ALfloat Pitch; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index db084e5a..50f1e5c5 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -210,7 +210,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param slot->AuxSendAuto = value; UpdateEffectSlotProps(slot); if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateAllSourceProps(context); + UpdateListenerProps(context); break; default: diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index c7f4955a..3ea23732 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -52,10 +52,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -93,10 +90,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -149,10 +143,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -174,10 +165,7 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -207,10 +195,7 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); @@ -256,10 +241,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } done: WriteUnlock(&context->PropLock); diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 443ab884..59814a4b 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -557,10 +557,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) WriteLock(&context->PropLock); context->DopplerFactor = value; if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } WriteUnlock(&context->PropLock); done: @@ -580,10 +577,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) WriteLock(&context->PropLock); context->DopplerVelocity = value; if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } WriteUnlock(&context->PropLock); done: @@ -603,10 +597,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) WriteLock(&context->PropLock); context->SpeedOfSound = value; if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { UpdateListenerProps(context); - UpdateAllSourceProps(context); - } WriteUnlock(&context->PropLock); done: -- cgit v1.2.3 From c7eb0b7393231a137c31f75e0654214a08bc51a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Aug 2016 19:17:17 -0700 Subject: Don't pass the context's distance model as the source's --- Alc/ALu.c | 7 ++++++- OpenAL32/Include/alListener.h | 5 +++++ OpenAL32/alListener.c | 3 +++ OpenAL32/alSource.c | 17 +++++++---------- OpenAL32/alState.c | 6 +++--- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 115c9c59..a890f653 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -278,6 +278,9 @@ static ALboolean CalcListenerParams(ALCcontext *Context) Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) * ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed); + Listener->Params.SourceDistanceModel = ATOMIC_LOAD(&props->SourceDistanceModel, almemory_order_relaxed); + Listener->Params.DistanceModel = ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed); + /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap * in the old container (practically impossible with this little code, @@ -939,7 +942,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Attenuation = 1.0f; for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; - switch(ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed)) + switch(Listener->Params.SourceDistanceModel ? + ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed) : + Listener->Params.DistanceModel) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index a10d6728..b89a00e7 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -19,6 +19,8 @@ struct ALlistenerProps { ATOMIC(ALfloat) DopplerFactor; ATOMIC(ALfloat) DopplerVelocity; ATOMIC(ALfloat) SpeedOfSound; + ATOMIC(ALboolean) SourceDistanceModel; + ATOMIC(enum DistanceModel) DistanceModel; ATOMIC(struct ALlistenerProps*) next; }; @@ -49,6 +51,9 @@ typedef struct ALlistener { ALfloat DopplerFactor; ALfloat SpeedOfSound; + + ALboolean SourceDistanceModel; + enum DistanceModel DistanceModel; } Params; } ALlistener; diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 3ea23732..08ece19d 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -496,6 +496,9 @@ void UpdateListenerProps(ALCcontext *context) ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed); ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed); + ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel, almemory_order_relaxed); + ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed); + /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); if(props) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index fb2ada10..891286a2 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -49,7 +49,7 @@ extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static void InitSourceParams(ALsource *Source); static void DeinitSource(ALsource *source); -static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context); +static void UpdateSourceProps(ALsource *source, ALuint num_sends); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); @@ -386,7 +386,7 @@ static ALint Int64ValsByProp(ALenum prop) #define DO_UPDATEPROPS() do { \ if(SourceShouldUpdate(Source, Context)) \ - UpdateSourceProps(Source, device->NumAuxSends, Context); \ + UpdateSourceProps(Source, device->NumAuxSends); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -840,7 +840,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p /* We must force an update if the auxiliary slot changed on a * playing source, in case the slot is about to be deleted. */ - UpdateSourceProps(Source, device->NumAuxSends, Context); + UpdateSourceProps(Source, device->NumAuxSends); } else { @@ -2813,7 +2813,7 @@ static void DeinitSource(ALsource *source) } } -static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *context) +static void UpdateSourceProps(ALsource *source, ALuint num_sends) { struct ALsourceProps *props; size_t i; @@ -2857,10 +2857,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends, ALCcontext *co almemory_order_relaxed); } ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); - ATOMIC_STORE(&props->DistanceModel, - context->SourceDistanceModel ? source->DistanceModel : context->DistanceModel, - almemory_order_relaxed - ); + ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed); ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed); ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed); @@ -2928,7 +2925,7 @@ void UpdateAllSourceProps(ALCcontext *context) ALsource *source = voice->Source; if(source != NULL && (source->state == AL_PLAYING || source->state == AL_PAUSED)) - UpdateSourceProps(source, num_sends, context); + UpdateSourceProps(source, num_sends); } /* Now with all updates declared, let the mixer continue applying them so * they all happen at once. @@ -3037,7 +3034,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } - UpdateSourceProps(Source, device->NumAuxSends, Context); + UpdateSourceProps(Source, device->NumAuxSends); } else if(state == AL_PAUSED) { diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 59814a4b..fa3b190a 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -63,7 +63,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateAllSourceProps(context); + UpdateListenerProps(context); done: WriteUnlock(&context->PropLock); @@ -88,7 +88,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateAllSourceProps(context); + UpdateListenerProps(context); done: WriteUnlock(&context->PropLock); @@ -622,7 +622,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) if(!context->SourceDistanceModel) { if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateAllSourceProps(context); + UpdateListenerProps(context); } WriteUnlock(&context->PropLock); -- cgit v1.2.3 From ea2fb38627a0549c17f2a875dd9a2481712efbe3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Aug 2016 19:37:26 -0700 Subject: Hold updates for both listener and source updates --- Alc/ALc.c | 16 +++++++++++++++- OpenAL32/alSource.c | 11 ----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f5965716..e393a181 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1601,6 +1601,16 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) if(ATOMIC_EXCHANGE(ALenum, &context->DeferUpdates, AL_FALSE)) { ALsizei pos; + uint updates; + + /* Tell the mixer to stop applying updates, then wait for any active + * updating to finish, before providing updates. + */ + ATOMIC_STORE(&context->HoldUpdates, AL_TRUE); + while(((updates=ReadRef(&context->UpdateCount))&1) != 0) + althrd_yield(); + + UpdateListenerProps(context); LockUIntMapRead(&context->SourceMap); V0(device->Backend,lock)(); @@ -1625,8 +1635,12 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) V0(device->Backend,unlock)(); UnlockUIntMapRead(&context->SourceMap); - UpdateListenerProps(context); UpdateAllSourceProps(context); + + /* Now with all updates declared, let the mixer continue applying them + * so they all happen at once. + */ + ATOMIC_STORE(&context->HoldUpdates, AL_FALSE); } ReadUnlock(&context->PropLock); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 891286a2..678654df 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2910,15 +2910,8 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) void UpdateAllSourceProps(ALCcontext *context) { ALuint num_sends = context->Device->NumAuxSends; - uint updates; ALsizei pos; - /* Tell the mixer to stop applying updates, then wait for any active - * updating to finish, before providing source updates. - */ - ATOMIC_STORE(&context->HoldUpdates, AL_TRUE); - while(((updates=ReadRef(&context->UpdateCount))&1) != 0) - althrd_yield(); for(pos = 0;pos < context->VoiceCount;pos++) { ALvoice *voice = &context->Voices[pos]; @@ -2927,10 +2920,6 @@ void UpdateAllSourceProps(ALCcontext *context) source->state == AL_PAUSED)) UpdateSourceProps(source, num_sends); } - /* Now with all updates declared, let the mixer continue applying them so - * they all happen at once. - */ - ATOMIC_STORE(&context->HoldUpdates, AL_FALSE); } -- cgit v1.2.3 From e77de8b12a01bc9385ec0b7b528274b799bac81e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Aug 2016 23:57:55 -0700 Subject: Make a function definition static --- OpenAL32/alSource.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 678654df..f5941729 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3063,7 +3063,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; -- cgit v1.2.3 From 8bf4a22876c30c16db71cd9063b9788c5e6a1aa8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Aug 2016 00:25:28 -0700 Subject: Combine related members into a struct --- Alc/ALc.c | 78 +++++++++++++++++++++++------------------------ Alc/ALu.c | 14 ++++----- Alc/effects/reverb.c | 4 +-- Alc/mixer.c | 2 +- Alc/panning.c | 51 ++++++++++++++++--------------- OpenAL32/Include/alMain.h | 22 +++++++------ 6 files changed, 87 insertions(+), 84 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e393a181..15614dd1 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1923,7 +1923,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /************************************************************************* * Update device format request if HRTF is requested */ - device->Hrtf_Status = ALC_HRTF_DISABLED_SOFT; + device->Hrtf.Status = ALC_HRTF_DISABLED_SOFT; if(device->Type != Loopback) { const char *hrtf; @@ -1939,31 +1939,31 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { - if(VECTOR_SIZE(device->Hrtf_List) == 0) + if(VECTOR_SIZE(device->Hrtf.List) == 0) { - VECTOR_DEINIT(device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->Hrtf.List); + device->Hrtf.List = EnumerateHrtf(device->DeviceName); } - if(VECTOR_SIZE(device->Hrtf_List) > 0) + if(VECTOR_SIZE(device->Hrtf.List) > 0) { device->FmtChans = DevFmtStereo; - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) - device->Frequency = VECTOR_ELEM(device->Hrtf_List, hrtf_id).hrtf->sampleRate; + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf.List)) + device->Frequency = VECTOR_ELEM(device->Hrtf.List, hrtf_id).hrtf->sampleRate; else - device->Frequency = VECTOR_ELEM(device->Hrtf_List, 0).hrtf->sampleRate; + device->Frequency = VECTOR_ELEM(device->Hrtf.List, 0).hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; } else { hrtf_userreq = Hrtf_Default; hrtf_appreq = Hrtf_Disable; - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } } else if(hrtf_appreq == Hrtf_Enable) { - size_t i = VECTOR_SIZE(device->Hrtf_List); + size_t i = VECTOR_SIZE(device->Hrtf.List); /* Loopback device. We don't need to match to a specific HRTF entry * here. If the requested ID matches, we'll pick that later, if not, * we'll try to auto-select one anyway. Just make sure one exists @@ -1971,24 +1971,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ if(device->FmtChans == DevFmtStereo) { - if(VECTOR_SIZE(device->Hrtf_List) == 0) + if(VECTOR_SIZE(device->Hrtf.List) == 0) { - VECTOR_DEINIT(device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->Hrtf.List); + device->Hrtf.List = EnumerateHrtf(device->DeviceName); } - for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++) + for(i = 0;i < VECTOR_SIZE(device->Hrtf.List);i++) { - const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf_List, i).hrtf; + const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf.List, i).hrtf; if(hrtf->sampleRate == device->Frequency) break; } } - if(i == VECTOR_SIZE(device->Hrtf_List)) + if(i == VECTOR_SIZE(device->Hrtf.List)) { ERR("Requested format not HRTF compatible: %s, %uhz\n", DevFmtChannelsString(device->FmtChans), device->Frequency); hrtf_appreq = Hrtf_Disable; - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } @@ -2043,7 +2043,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2)) size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); - else if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) + else if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); else if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) size += 4 * sizeof(device->Dry.Buffer[0]); @@ -2054,7 +2054,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if(device->Hrtf || device->Uhj_Encoder || device->AmbiDecoder) + if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) { device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); @@ -2204,8 +2204,8 @@ static ALCvoid FreeDevice(ALCdevice *device) } ResetUIntMap(&device->FilterMap); - AL_STRING_DEINIT(device->Hrtf_Name); - FreeHrtfList(&device->Hrtf_List); + AL_STRING_DEINIT(device->Hrtf.Name); + FreeHrtfList(&device->Hrtf.List); al_free(device->Bs2b); device->Bs2b = NULL; @@ -2683,7 +2683,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { almtx_lock(&Device->BackendLock); - value = (Device->Hrtf ? al_string_get_cstr(Device->Hrtf_Name) : ""); + value = (Device->Hrtf.Handle ? al_string_get_cstr(Device->Hrtf.Name) : ""); almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } @@ -2824,10 +2824,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = device->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); + values[i++] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->Hrtf_Status; + values[i++] = device->Hrtf.Status; almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -2892,18 +2892,18 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_HRTF_SOFT: - values[0] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); + values[0] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); return 1; case ALC_HRTF_STATUS_SOFT: - values[0] = device->Hrtf_Status; + values[0] = device->Hrtf.Status; return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); - FreeHrtfList(&device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); - values[0] = (ALCint)VECTOR_SIZE(device->Hrtf_List); + FreeHrtfList(&device->Hrtf.List); + device->Hrtf.List = EnumerateHrtf(device->DeviceName); + values[0] = (ALCint)VECTOR_SIZE(device->Hrtf.List); almtx_unlock(&device->BackendLock); return 1; @@ -2994,10 +2994,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = device->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); + values[i++] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->Hrtf_Status; + values[i++] = device->Hrtf.Status; clock = V0(device->Backend,getClockLatency)(); values[i++] = ALC_DEVICE_CLOCK_SOFT; @@ -3403,8 +3403,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Flags = 0; device->Bs2b = NULL; device->Uhj_Encoder = NULL; - VECTOR_INIT(device->Hrtf_List); - AL_STRING_INIT(device->Hrtf_Name); + VECTOR_INIT(device->Hrtf.List); + AL_STRING_INIT(device->Hrtf.Name); device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; @@ -3683,8 +3683,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Connected = ALC_TRUE; device->Type = Capture; - VECTOR_INIT(device->Hrtf_List); - AL_STRING_INIT(device->Hrtf_Name); + VECTOR_INIT(device->Hrtf.List); + AL_STRING_INIT(device->Hrtf.Name); AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; @@ -3878,8 +3878,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); device->Flags = 0; - VECTOR_INIT(device->Hrtf_List); - AL_STRING_INIT(device->Hrtf_Name); + VECTOR_INIT(device->Hrtf.List); + AL_STRING_INIT(device->Hrtf.Name); device->Bs2b = NULL; device->Uhj_Encoder = NULL; device->Render_Mode = NormalRender; @@ -4065,8 +4065,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum else switch(paramName) { case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && (size_t)index < VECTOR_SIZE(device->Hrtf_List)) - str = al_string_get_cstr(VECTOR_ELEM(device->Hrtf_List, index).name); + if(index >= 0 && (size_t)index < VECTOR_SIZE(device->Hrtf.List)) + str = al_string_get_cstr(VECTOR_ELEM(device->Hrtf.List, index).name); else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/ALu.c b/Alc/ALu.c index a890f653..54905ebd 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -649,7 +649,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } /* Get the static HRIR coefficients and delays for this channel. */ - GetLerpedHrtfCoeffs(Device->Hrtf, + GetLerpedHrtfCoeffs(Device->Hrtf.Handle, chans[c].elevation, chans[c].angle, 0.0f, DryGain, voice->Chan[c].Direct.Hrtf.Target.Coeffs, voice->Chan[c].Direct.Hrtf.Target.Delay @@ -1165,7 +1165,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro spread = asinf(radius / Distance) * 2.0f; /* Get the HRIR coefficients and delays. */ - GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, spread, DryGain, + GetLerpedHrtfCoeffs(Device->Hrtf.Handle, ev, az, spread, DryGain, voice->Chan[0].Direct.Hrtf.Target.Coeffs, voice->Chan[0].Direct.Hrtf.Target.Delay); @@ -1526,23 +1526,23 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) V0(device->Backend,unlock)(); IncrementRef(&device->MixCount); - if(device->Hrtf) + if(device->Hrtf.Handle) { int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(device->RealOut, FrontRight); if(lidx != -1 && ridx != -1) { HrtfDirectMixerFunc HrtfMix = SelectHrtfMixer(); - ALuint irsize = device->Hrtf_IrSize; + ALuint irsize = device->Hrtf.IrSize; for(c = 0;c < device->Dry.NumChannels;c++) { HrtfMix(device->RealOut.Buffer, lidx, ridx, - device->Dry.Buffer[c], device->Hrtf_Offset, irsize, - device->Hrtf_Coeffs[c], device->Hrtf_Values[c], + device->Dry.Buffer[c], device->Hrtf.Offset, irsize, + device->Hrtf.Coeffs[c], device->Hrtf.Values[c], SamplesToDo ); } - device->Hrtf_Offset += SamplesToDo; + device->Hrtf.Offset += SamplesToDo; } } else if(device->AmbiDecoder) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 71c39f8c..e6a9e05a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -391,7 +391,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev return AL_FALSE; /* HRTF and UHJ will mix to the real output for ambient output. */ - if(Device->Hrtf || Device->Uhj_Encoder) + if(Device->Hrtf.Handle || Device->Uhj_Encoder) { State->ExtraOut = Device->RealOut.Buffer; State->ExtraChannels = Device->RealOut.NumChannels; @@ -956,7 +956,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf || Device->Uhj_Encoder) + if(Device->Hrtf.Handle || Device->Uhj_Encoder) UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, diff --git a/Alc/mixer.c b/Alc/mixer.c index 9f6ec9d1..bbf70153 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -393,7 +393,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam SampleSize = Source->SampleSize; increment = voice->Step; - IrSize = (Device->Hrtf ? Device->Hrtf->irSize : 0); + IrSize = (Device->Hrtf.Handle ? Device->Hrtf.Handle->irSize : 0); Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : ResampleSamples); diff --git a/Alc/panning.c b/Alc/panning.c index 70494547..172861da 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -772,12 +772,13 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; - memset(device->Hrtf_Coeffs, 0, sizeof(device->Hrtf_Coeffs)); - device->Hrtf_IrSize = BuildBFormatHrtf(device->Hrtf, device->Hrtf_Coeffs, - device->Dry.NumChannels); + memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs)); + device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle, + device->Hrtf.Coeffs, device->Dry.NumChannels + ); /* Round up to the nearest multiple of 8 */ - device->Hrtf_IrSize = (device->Hrtf_IrSize+7)&~7; + device->Hrtf.IrSize = (device->Hrtf.IrSize+7)&~7; } static void InitUhjPanning(ALCdevice *device) @@ -805,8 +806,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf int bs2blevel; size_t i; - device->Hrtf = NULL; - al_string_clear(&device->Hrtf_Name); + device->Hrtf.Handle = NULL; + al_string_clear(&device->Hrtf.Name); device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); @@ -820,7 +821,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf AmbDecConf conf, *pconf = NULL; if(hrtf_appreq == Hrtf_Enable) - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; ambdec_init(&conf); @@ -920,48 +921,48 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf (hrtf_appreq == Hrtf_Enable); if(!usehrtf) goto no_hrtf; - device->Hrtf_Status = ALC_HRTF_ENABLED_SOFT; + device->Hrtf.Status = ALC_HRTF_ENABLED_SOFT; if(headphones && hrtf_appreq != Hrtf_Disable) - device->Hrtf_Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + device->Hrtf.Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; } else { if(hrtf_userreq != Hrtf_Enable) { if(hrtf_appreq == Hrtf_Enable) - device->Hrtf_Status = ALC_HRTF_DENIED_SOFT; + device->Hrtf.Status = ALC_HRTF_DENIED_SOFT; goto no_hrtf; } - device->Hrtf_Status = ALC_HRTF_REQUIRED_SOFT; + device->Hrtf.Status = ALC_HRTF_REQUIRED_SOFT; } - if(VECTOR_SIZE(device->Hrtf_List) == 0) + if(VECTOR_SIZE(device->Hrtf.List) == 0) { - VECTOR_DEINIT(device->Hrtf_List); - device->Hrtf_List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->Hrtf.List); + device->Hrtf.List = EnumerateHrtf(device->DeviceName); } - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf.List)) { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, hrtf_id); if(entry->hrtf->sampleRate == device->Frequency) { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); + device->Hrtf.Handle = entry->hrtf; + al_string_copy(&device->Hrtf.Name, entry->name); } } - for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) + for(i = 0;!device->Hrtf.Handle && i < VECTOR_SIZE(device->Hrtf.List);i++) { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, i); if(entry->hrtf->sampleRate == device->Frequency) { - device->Hrtf = entry->hrtf; - al_string_copy(&device->Hrtf_Name, entry->name); + device->Hrtf.Handle = entry->hrtf; + al_string_copy(&device->Hrtf.Name, entry->name); } } - if(device->Hrtf) + if(device->Hrtf.Handle) { device->Render_Mode = HrtfRender; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) @@ -974,11 +975,11 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ERR("Unexpected hrtf-mode: %s\n", mode); } - TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); + TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf.Name)); InitHrtfPanning(device); return; } - device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; no_hrtf: TRACE("HRTF disabled\n"); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b173c515..56bfa0b0 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -593,16 +593,18 @@ struct ALCdevice_struct UIntMap FilterMap; /* HRTF filter tables */ - vector_HrtfEntry Hrtf_List; - al_string Hrtf_Name; - const struct Hrtf *Hrtf; - ALCenum Hrtf_Status; - - /* HRTF filter state for dry buffer content */ - alignas(16) ALfloat Hrtf_Values[4][HRIR_LENGTH][2]; - alignas(16) ALfloat Hrtf_Coeffs[4][HRIR_LENGTH][2]; - ALuint Hrtf_Offset; - ALuint Hrtf_IrSize; + struct { + vector_HrtfEntry List; + al_string Name; + ALCenum Status; + const struct Hrtf *Handle; + + /* HRTF filter state for dry buffer content */ + alignas(16) ALfloat Values[4][HRIR_LENGTH][2]; + alignas(16) ALfloat Coeffs[4][HRIR_LENGTH][2]; + ALuint Offset; + ALuint IrSize; + } Hrtf; /* UHJ encoder state */ struct Uhj2Encoder *Uhj_Encoder; -- cgit v1.2.3 From 849f85549d47a4e1aecdfbdd3300c866fb288fca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Aug 2016 02:17:55 -0700 Subject: Consolidate duplicate code --- Alc/ALu.c | 62 +++++++++++++++++++++++--------------------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 54905ebd..80a031fc 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1296,54 +1296,38 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc struct ALsourceProps *props; props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); - if(!props) - { - if(!force) - return; - BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); - while(BufferListItem != NULL) - { - const ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - if(buffer->FmtChannels == FmtMono) - CalcAttnSourceParams(voice, &voice->Props, buffer, context); - else - CalcNonAttnSourceParams(voice, &voice->Props, buffer, context); - break; - } - BufferListItem = BufferListItem->next; - } - } - else + if(!props && !force) return; + + if(props) { - BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); - while(BufferListItem != NULL) - { - const ALbuffer *buffer; - if((buffer=BufferListItem->buffer) != NULL) - { - if(buffer->FmtChannels == FmtMono) - CalcAttnSourceParams(voice, props, buffer, context); - else - CalcNonAttnSourceParams(voice, props, buffer, context); - break; - } - BufferListItem = BufferListItem->next; - } voice->Props = *props; - /* WARNING: A livelock is theoretically possible if another thread keeps - * changing the freelist head without giving this a chance to actually swap - * in the old container (practically impossible with this little code, - * but...). - */ + /* WARNING: A livelock is theoretically possible if another thread + * keeps changing the freelist head without giving this a chance to + * actually swap in the old container (practically impossible with this + * little code, but...). + */ first = ATOMIC_LOAD(&source->FreeList); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, &source->FreeList, &first, props) == 0); } + + BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + while(BufferListItem != NULL) + { + const ALbuffer *buffer; + if((buffer=BufferListItem->buffer) != NULL) + { + if(buffer->FmtChannels == FmtMono) + CalcAttnSourceParams(voice, &voice->Props, buffer, context); + else + CalcNonAttnSourceParams(voice, &voice->Props, buffer, context); + break; + } + BufferListItem = BufferListItem->next; + } } -- cgit v1.2.3 From d8e9b3c621762e3d9e2b81034e19aa0d671247ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Aug 2016 03:49:45 -0700 Subject: Also rotate stereo sounds in the alhrtf example --- examples/alhrtf.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 2e6e7148..23d60a74 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -113,6 +113,7 @@ static ALuint LoadSound(const char *filename) int main(int argc, char **argv) { ALCdevice *device; + ALboolean has_angle_ext; ALuint source, buffer; const char *soundname; const char *hrtfname; @@ -157,6 +158,12 @@ int main(int argc, char **argv) LOAD_PROC(device, alcResetDeviceSOFT); #undef LOAD_PROC + /* Check for the AL_EXT_STEREO_ANGLES extension to be able to also rotate + * stereo sources. + */ + has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES"); + printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not"); + /* Enumerate available HRTFs, and reset the device using one. */ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); if(!num_hrtf) @@ -232,12 +239,25 @@ int main(int argc, char **argv) do { al_nssleep(10000000); - /* Rotate the source around the listener by about 1/4 cycle per second. - * Only affects mono sounds. + /* Rotate the source around the listener by about 1/4 cycle per second, + * and keep it within -pi...+pi. */ angle += 0.01 * M_PI * 0.5; + if(angle > M_PI) + angle -= M_PI*2.0; + + /* This only rotates mono sounds. */ alSource3f(source, AL_POSITION, (ALfloat)sin(angle), 0.0f, -(ALfloat)cos(angle)); + if(has_angle_ext) + { + /* This rotates stereo sounds with the AL_EXT_STEREO_ANGLES + * extension. Angles are specified counter-clockwise in radians. + */ + ALfloat angles[2] = { (ALfloat)(M_PI/6.0 - angle), (ALfloat)(-M_PI/6.0 - angle) }; + alSourcefv(source, AL_STEREO_ANGLES, angles); + } + alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); -- cgit v1.2.3 From 0fbf34fb4592aa29fcbf4e725719cb253e7d3a78 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Aug 2016 03:42:43 -0700 Subject: Add a ref count to ALeffectState This is mostly just reorganizing the effects to call the Construct method which initializes the ref count. --- Alc/effects/chorus.c | 37 ++++--- Alc/effects/compressor.c | 32 +++--- Alc/effects/dedicated.c | 30 ++++-- Alc/effects/distortion.c | 28 ++++-- Alc/effects/echo.c | 40 +++++--- Alc/effects/equalizer.c | 41 +++++--- Alc/effects/flanger.c | 37 ++++--- Alc/effects/modulator.c | 37 ++++--- Alc/effects/null.c | 37 ++++--- Alc/effects/reverb.c | 193 +++++++++++++++++++------------------ OpenAL32/Include/alAuxEffectSlot.h | 2 + OpenAL32/Include/alMain.h | 6 ++ OpenAL32/alAuxEffectSlot.c | 8 ++ 13 files changed, 325 insertions(+), 203 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 7877ff6f..63d0ca01 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -55,11 +55,34 @@ typedef struct ALchorusState { ALfloat feedback; } ALchorusState; +static ALvoid ALchorusState_Destruct(ALchorusState *state); +static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); +static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALchorusState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); + + +static void ALchorusState_Construct(ALchorusState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALchorusState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBuffer[0] = NULL; + state->SampleBuffer[1] = NULL; + state->offset = 0; + state->lfo_range = 1; + state->waveform = CWF_Triangle; +} + static ALvoid ALchorusState_Destruct(ALchorusState *state) { al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } @@ -246,10 +269,6 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co } } -DECLARE_DEFAULT_ALLOCATORS(ALchorusState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); - typedef struct ALchorusStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -259,16 +278,8 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f { ALchorusState *state; - state = ALchorusState_New(sizeof(*state)); + NEW_OBJ0(state, ALchorusState)(); 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; - state->waveform = CWF_Triangle; return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 6329d3f1..1426ea70 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -40,6 +40,26 @@ typedef struct ALcompressorState { ALfloat GainCtrl; } ALcompressorState; +static ALvoid ALcompressorState_Destruct(ALcompressorState *state); +static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); +static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); + + +static void ALcompressorState_Construct(ALcompressorState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALcompressorState, ALeffectState, state); + + state->Enabled = AL_TRUE; + state->AttackRate = 0.0f; + state->ReleaseRate = 0.0f; + state->GainCtrl = 1.0f; +} + static ALvoid ALcompressorState_Destruct(ALcompressorState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -165,10 +185,6 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples } } -DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); - typedef struct ALcompressorStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -178,14 +194,8 @@ static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory * { ALcompressorState *state; - state = ALcompressorState_New(sizeof(*state)); + NEW_OBJ0(state, ALcompressorState)(); 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); } diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 98dd560b..818cbb6b 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -35,6 +35,25 @@ typedef struct ALdedicatedState { ALfloat gains[MAX_OUTPUT_CHANNELS]; } ALdedicatedState; +static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); +static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); +static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); + + +static void ALdedicatedState_Construct(ALdedicatedState *state) +{ + ALsizei s; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALdedicatedState, ALeffectState, state); + + for(s = 0;s < MAX_OUTPUT_CHANNELS;s++) + state->gains[s] = 0.0f; +} static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) { @@ -103,10 +122,6 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesTo } } -DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); - typedef struct ALdedicatedStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -115,14 +130,9 @@ typedef struct ALdedicatedStateFactory { ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory)) { ALdedicatedState *state; - ALsizei s; - state = ALdedicatedState_New(sizeof(*state)); + NEW_OBJ0(state, ALdedicatedState)(); if(!state) return NULL; - SET_VTABLE2(ALdedicatedState, ALeffectState, state); - - for(s = 0;s < MAX_OUTPUT_CHANNELS;s++) - state->gains[s] = 0.0f; return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index eabf8a5d..bc1e7d84 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -43,6 +43,24 @@ typedef struct ALdistortionState { ALfloat edge_coeff; } ALdistortionState; +static ALvoid ALdistortionState_Destruct(ALdistortionState *state); +static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); +static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); + + +static void ALdistortionState_Construct(ALdistortionState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALdistortionState, ALeffectState, state); + + ALfilterState_clear(&state->lowpass); + ALfilterState_clear(&state->bandpass); +} + static ALvoid ALdistortionState_Destruct(ALdistortionState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -161,10 +179,6 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples } } -DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); - typedef struct ALdistortionStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -174,12 +188,8 @@ static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory * { ALdistortionState *state; - state = ALdistortionState_New(sizeof(*state)); + NEW_OBJ0(state, ALdistortionState)(); if(!state) return NULL; - SET_VTABLE2(ALdistortionState, ALeffectState, state); - - ALfilterState_clear(&state->lowpass); - ALfilterState_clear(&state->bandpass); return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 4d2fd6f4..3ad1e975 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -50,6 +50,30 @@ typedef struct ALechoState { ALfilterState Filter; } ALechoState; +static ALvoid ALechoState_Destruct(ALechoState *state); +static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); +static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALechoState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); + + +static void ALechoState_Construct(ALechoState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + 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); +} + static ALvoid ALechoState_Destruct(ALechoState *state) { al_free(state->SampleBuffer); @@ -184,10 +208,6 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const state->Offset = offset; } -DECLARE_DEFAULT_ALLOCATORS(ALechoState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); - typedef struct ALechoStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -197,18 +217,8 @@ ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory)) { ALechoState *state; - state = ALechoState_New(sizeof(*state)); + NEW_OBJ0(state, ALechoState)(); 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); } diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 96676d34..2b59cb37 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -87,6 +87,31 @@ typedef struct ALequalizerState { ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES]; } ALequalizerState; +static ALvoid ALequalizerState_Destruct(ALequalizerState *state); +static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); +static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); + + +static void ALequalizerState_Construct(ALequalizerState *state) +{ + int it, ft; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + 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++) + { + for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) + ALfilterState_clear(&state->filter[it][ft]); + } +} + static ALvoid ALequalizerState_Destruct(ALequalizerState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -223,10 +248,6 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo } } -DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); - typedef struct ALequalizerStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -235,19 +256,9 @@ typedef struct ALequalizerStateFactory { ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory)) { ALequalizerState *state; - int it, ft; - state = ALequalizerState_New(sizeof(*state)); + NEW_OBJ0(state, ALequalizerState)(); 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++) - { - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_clear(&state->filter[it][ft]); - } return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index f18b2b0f..1575212b 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -55,11 +55,34 @@ typedef struct ALflangerState { ALfloat feedback; } ALflangerState; +static ALvoid ALflangerState_Destruct(ALflangerState *state); +static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device); +static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALflangerState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); + + +static void ALflangerState_Construct(ALflangerState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALflangerState, ALeffectState, state); + + state->BufferLength = 0; + state->SampleBuffer[0] = NULL; + state->SampleBuffer[1] = NULL; + state->offset = 0; + state->lfo_range = 1; + state->waveform = FWF_Triangle; +} + static ALvoid ALflangerState_Destruct(ALflangerState *state) { al_free(state->SampleBuffer[0]); state->SampleBuffer[0] = NULL; state->SampleBuffer[1] = NULL; + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } @@ -246,10 +269,6 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, } } -DECLARE_DEFAULT_ALLOCATORS(ALflangerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); - typedef struct ALflangerStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -259,16 +278,8 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor { ALflangerState *state; - state = ALflangerState_New(sizeof(*state)); + NEW_OBJ0(state, ALflangerState)(); 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; - state->waveform = FWF_Triangle; return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7e3e89b2..08f3d5eb 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -43,6 +43,15 @@ typedef struct ALmodulatorState { ALfilterState Filter[MAX_EFFECT_CHANNELS]; } ALmodulatorState; +static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); +static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); +static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); + + #define WAVEFORM_FRACBITS 24 #define WAVEFORM_FRACONE (1<index = 0; + state->step = 1; + + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ALfilterState_clear(&state->Filter[i]); +} + static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) { ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); @@ -175,10 +198,6 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesTo state->index = index; } -DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); - typedef struct ALmodulatorStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -187,17 +206,9 @@ typedef struct ALmodulatorStateFactory { static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory)) { ALmodulatorState *state; - ALuint i; - state = ALmodulatorState_New(sizeof(*state)); + NEW_OBJ0(state, ALmodulatorState)(); if(!state) return NULL; - SET_VTABLE2(ALmodulatorState, ALeffectState, state); - - state->index = 0; - state->step = 1; - - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_clear(&state->Filter[i]); return STATIC_CAST(ALeffectState, state); } diff --git a/Alc/effects/null.c b/Alc/effects/null.c index a135b194..bff00b56 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -13,6 +13,27 @@ typedef struct ALnullState { DERIVE_FROM_TYPE(ALeffectState); } ALnullState; +/* Forward-declare "virtual" functions to define the vtable with. */ +static ALvoid ALnullState_Destruct(ALnullState *state); +static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); +static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALnullState_process(ALnullState *state, ALuint samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALuint NumChannels); +static void *ALnullState_New(size_t size); +static void ALnullState_Delete(void *ptr); + +/* Define the ALeffectState vtable for this type. */ +DEFINE_ALEFFECTSTATE_VTABLE(ALnullState); + + +/* This constructs the effect state. It's called when the object is first + * created. Make sure to call the parent Construct function first, and set the + * vtable! + */ +static void ALnullState_Construct(ALnullState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALnullState, ALeffectState, state); +} /* This destructs (not free!) the effect state. It's called only when the * effect slot is no longer used. Make sure to call the parent Destruct @@ -48,24 +69,21 @@ static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samp } /* This allocates memory to store the object, before it gets constructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method. + * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. */ static void *ALnullState_New(size_t size) { - return malloc(size); + return al_malloc(16, size); } /* This frees the memory used by the object, after it has been destructed. - * DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method. + * DECLARE_DEFAULT_ALLOCATORS can be used to declare a default method. */ static void ALnullState_Delete(void *ptr) { - free(ptr); + al_free(ptr); } -/* Define the forwards and the ALeffectState vtable for this type. */ -DEFINE_ALEFFECTSTATE_VTABLE(ALnullState); - typedef struct ALnullStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); @@ -76,10 +94,8 @@ ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory)) { ALnullState *state; - state = ALnullState_New(sizeof(*state)); + NEW_OBJ0(state, ALnullState)(); if(!state) return NULL; - /* Set vtables for inherited types. */ - SET_VTABLE2(ALnullState, ALeffectState, state); return STATIC_CAST(ALeffectState, state); } @@ -90,7 +106,6 @@ DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory); ALeffectStateFactory *ALnullStateFactory_getFactory(void) { static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &NullFactory); } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index e6a9e05a..0ffff585 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -168,22 +168,112 @@ typedef struct ALreverbState { ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4]; } ALreverbState; -static ALvoid ALreverbState_Destruct(ALreverbState *State) -{ - al_free(State->SampleBuffer); - State->SampleBuffer = NULL; - ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); -} - +static ALvoid ALreverbState_Destruct(ALreverbState *State); static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALreverbState) DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); + +static void ALreverbState_Construct(ALreverbState *state) +{ + ALuint index, l; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALreverbState, ALeffectState, state); + + state->IsEax = AL_FALSE; + state->ExtraChannels = 0; + + state->TotalSamples = 0; + state->SampleBuffer = NULL; + + ALfilterState_clear(&state->LpFilter); + ALfilterState_clear(&state->HpFilter); + + 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->Delay.Mask = 0; + state->Delay.Line = NULL; + state->DelayTap[0] = 0; + state->DelayTap[1] = 0; + + 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->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; + 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; + } + + for(l = 0;l < 4;l++) + { + for(index = 0;index < MAX_OUTPUT_CHANNELS;index++) + { + state->Early.PanGain[l][index] = 0.0f; + state->Late.PanGain[l][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.0f; + + state->Offset = 0; +} + +static ALvoid ALreverbState_Destruct(ALreverbState *State) +{ + al_free(State->SampleBuffer); + State->SampleBuffer = NULL; + + ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); +} + /* This is a user config option for modifying the overall output of the reverb * effect. */ @@ -1427,92 +1517,9 @@ typedef struct ALreverbStateFactory { static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory)) { ALreverbState *state; - ALuint index, l; - state = ALreverbState_New(sizeof(*state)); + NEW_OBJ0(state, ALreverbState)(); if(!state) return NULL; - SET_VTABLE2(ALreverbState, ALeffectState, state); - - state->IsEax = AL_FALSE; - state->ExtraChannels = 0; - - state->TotalSamples = 0; - state->SampleBuffer = NULL; - - ALfilterState_clear(&state->LpFilter); - ALfilterState_clear(&state->HpFilter); - - 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->Delay.Mask = 0; - state->Delay.Line = NULL; - state->DelayTap[0] = 0; - state->DelayTap[1] = 0; - - 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->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; - 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; - } - - for(l = 0;l < 4;l++) - { - for(index = 0;index < MAX_OUTPUT_CHANNELS;index++) - { - state->Early.PanGain[l][index] = 0.0f; - state->Late.PanGain[l][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.0f; - - state->Offset = 0; return STATIC_CAST(ALeffectState, state); } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index d0c7c76c..363d2467 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -14,12 +14,14 @@ struct ALeffectStateVtable; struct ALeffectslot; typedef struct ALeffectState { + RefCount Ref; const struct ALeffectStateVtable *vtbl; ALfloat (*OutBuffer)[BUFFERSIZE]; ALuint OutChannels; } ALeffectState; +void ALeffectState_Construct(ALeffectState *state); void ALeffectState_Destruct(ALeffectState *state); struct ALeffectStateVtable { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 56bfa0b0..e0e1b835 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -285,6 +285,12 @@ static void T##_Delete(void *ptr) { al_free(ptr); } { \ memset(_res, 0, sizeof(T)); \ T##_Construct(_res, EXTRACT_NEW_ARGS +#define NEW_OBJ0(_res, T) do { \ + _res = T##_New(sizeof(T)); \ + if(_res) \ + { \ + memset(_res, 0, sizeof(T)); \ + T##_Construct(_res EXTRACT_NEW_ARGS #ifdef __cplusplus diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 50f1e5c5..1a20952b 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -523,6 +523,14 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e } +void ALeffectState_Construct(ALeffectState *state) +{ + InitRef(&state->Ref, 1); + + state->OutBuffer = NULL; + state->OutChannels = 0; +} + void ALeffectState_Destruct(ALeffectState *UNUSED(state)) { } -- cgit v1.2.3 From 4e4e597fa54cc3498ae28bea9c2684e1fee05389 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Aug 2016 04:57:58 -0700 Subject: Track all references for effect states This allows us to not have to play around with trying to avoid duplicate state pointers, since the reference count will ensure they're deleted as appropriate. The only caveat is that the mixer is not allowed to decrement references, since that can cause the object to be freed (which the mixer code is not allowed to do). --- Alc/ALu.c | 15 ++++------ OpenAL32/alAuxEffectSlot.c | 68 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 80a031fc..d2aa381c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -319,18 +319,15 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; } - state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); - /* If the state object is changed, exchange it with the current one so it - * remains in the freelist and isn't leaked. + /* Swap effect states. No need to play with the ref counts since they keep + * the same number of refs. */ - if(state != slot->Params.EffectState) - { - ATOMIC_STORE(&props->State, slot->Params.EffectState, almemory_order_relaxed); - slot->Params.EffectState = state; - } + state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Params.EffectState, + almemory_order_relaxed); + slot->Params.EffectState = state; - V(slot->Params.EffectState,update)(device, slot, &props->Props); + V(state,update)(device, slot, &props->Props); /* WARNING: A livelock is theoretically possible if another thread keeps * changing the freelist head without giving this a chance to actually swap diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 1a20952b..85be5c6d 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -44,7 +44,6 @@ extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot); - static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) { @@ -54,6 +53,9 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) return NULL; } +static void ALeffectState_IncRef(ALeffectState *state); +static void ALeffectState_DecRef(ALeffectState *state); + AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { @@ -86,7 +88,9 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(err != AL_NO_ERROR) { FreeThunkEntry(slot->id); - DELETE_OBJ(slot->Params.EffectState); + ALeffectState_DecRef(slot->Effect.State); + if(slot->Params.EffectState) + ALeffectState_DecRef(slot->Params.EffectState); al_free(slot); alDeleteAuxiliaryEffectSlots(cur, effectslots); @@ -469,11 +473,12 @@ void DeinitEffectFactoryMap(void) ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); - ALeffectStateFactory *factory; + struct ALeffectslotProps *props; + ALeffectState *State; if(newtype != EffectSlot->Effect.Type) { - ALeffectState *State; + ALeffectStateFactory *factory; FPUCtl oldMode; factory = getFactoryByType(newtype); @@ -493,7 +498,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e { almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); - DELETE_OBJ(State); + ALeffectState_DecRef(State); return AL_OUT_OF_MEMORY; } almtx_unlock(&Device->BackendLock); @@ -510,6 +515,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e EffectSlot->Effect.Props = effect->Props; } + ALeffectState_DecRef(EffectSlot->Effect.State); EffectSlot->Effect.State = State; UpdateEffectSlotProps(EffectSlot); } @@ -519,10 +525,35 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e UpdateEffectSlotProps(EffectSlot); } + /* Remove state references from old effect slot property updates. */ + props = ATOMIC_LOAD(&EffectSlot->FreeList); + while(props) + { + State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); + if(State) ALeffectState_DecRef(State); + ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } + return AL_NO_ERROR; } +static void ALeffectState_IncRef(ALeffectState *state) +{ + uint ref; + ref = IncrementRef(&state->Ref); + TRACEREF("%p increasing refcount to %u\n", state, ref); +} + +static void ALeffectState_DecRef(ALeffectState *state) +{ + uint ref; + ref = DecrementRef(&state->Ref); + TRACEREF("%p decreasing refcount to %u\n", state, ref); + if(ref == 0) DELETE_OBJ(state); +} + + void ALeffectState_Construct(ALeffectState *state) { InitRef(&state->Ref, 1); @@ -555,6 +586,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.Gain = 1.0f; slot->Params.AuxSendAuto = AL_TRUE; + ALeffectState_IncRef(slot->Effect.State); slot->Params.EffectState = slot->Effect.State; slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; @@ -575,8 +607,7 @@ void DeinitEffectSlot(ALeffectslot *slot) if(props) { state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); - if(state != slot->Params.EffectState) - DELETE_OBJ(state); + if(state) ALeffectState_DecRef(state); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } @@ -586,14 +617,16 @@ void DeinitEffectSlot(ALeffectslot *slot) struct ALeffectslotProps *next; state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - DELETE_OBJ(state); + if(state) ALeffectState_DecRef(state); al_free(props); props = next; ++count; } TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - DELETE_OBJ(slot->Params.EffectState); + ALeffectState_DecRef(slot->Effect.State); + if(slot->Params.EffectState) + ALeffectState_DecRef(slot->Params.EffectState); } void UpdateEffectSlotProps(ALeffectslot *slot) @@ -602,17 +635,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) ALeffectState *oldstate; props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL); - if(props) - { - /* If there was an unapplied update, check if its state object is the - * same as the current in-use one, or the one that will be set. If - * neither, delete it. - */ - oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); - if(oldstate != slot->Params.EffectState && oldstate != slot->Effect.State) - DELETE_OBJ(oldstate); - } - else + if(!props) { /* Get an unused property container, or allocate a new one as needed. */ props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); @@ -638,6 +661,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* Swap out any stale effect state object there may be in the container, to * delete it. */ + if(slot->Effect.State) + ALeffectState_IncRef(slot->Effect.State); oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, almemory_order_relaxed); @@ -656,7 +681,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot) &slot->FreeList, &first, props) == 0); } - DELETE_OBJ(oldstate); + if(oldstate) + ALeffectState_DecRef(oldstate); } ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) -- cgit v1.2.3 From a16739f7651afb7653387b1e79b2985058d76e90 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Aug 2016 06:17:36 -0700 Subject: Properly defer effect slot changes Note that this now also causes all playing sources to update when an effect slot is updated. This is a bit wasteful, as it should only need to re-update sources that are using the effect slot (and only when a relevant property is changed), but it's good enough. Especially with deferring since all playing sources are going to get updated on the process call anyway. --- Alc/ALc.c | 1 + Alc/ALu.c | 8 +++++--- OpenAL32/Include/alAuxEffectSlot.h | 3 +++ OpenAL32/alAuxEffectSlot.c | 39 +++++++++++++++++++++++++++----------- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 15614dd1..b95c90f8 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1611,6 +1611,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) althrd_yield(); UpdateListenerProps(context); + UpdateAllEffectSlotProps(context); LockUIntMapRead(&context->SourceMap); V0(device->Backend,lock)(); diff --git a/Alc/ALu.c b/Alc/ALu.c index d2aa381c..eafb082c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -295,14 +295,14 @@ static ALboolean CalcListenerParams(ALCcontext *Context) return AL_TRUE; } -static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) +static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) { struct ALeffectslotProps *first; struct ALeffectslotProps *props; ALeffectState *state; props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); - if(!props) return; + if(!props) return AL_FALSE; slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); @@ -339,6 +339,8 @@ static void CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, &slot->FreeList, &first, props) == 0); + + return AL_TRUE; } @@ -1339,7 +1341,7 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) ALboolean force = CalcListenerParams(ctx); while(slot) { - CalcEffectSlotParams(slot, ctx->Device); + force |= CalcEffectSlotParams(slot, ctx->Device); slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 363d2467..70fcac5c 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -88,6 +88,8 @@ struct ALeffectslotProps { typedef struct ALeffectslot { + ALboolean NeedsUpdate; + ALfloat Gain; ALboolean AuxSendAuto; @@ -152,6 +154,7 @@ inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); void UpdateEffectSlotProps(ALeffectslot *slot); +void UpdateAllEffectSlotProps(ALCcontext *context); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 85be5c6d..fb8c27f4 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -56,6 +56,13 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) static void ALeffectState_IncRef(ALeffectState *state); static void ALeffectState_DecRef(ALeffectState *state); +#define DO_UPDATEPROPS() do { \ + if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ + UpdateEffectSlotProps(slot); \ + else \ + slot->NeedsUpdate = AL_TRUE; \ +} while(0) + AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { @@ -212,14 +219,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!(value == AL_TRUE || value == AL_FALSE)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); slot->AuxSendAuto = value; - UpdateEffectSlotProps(slot); - if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - UpdateListenerProps(context); break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + DO_UPDATEPROPS(); done: UnlockEffectSlotsRead(context); @@ -279,7 +284,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } - UpdateEffectSlotProps(slot); + DO_UPDATEPROPS(); done: UnlockEffectSlotsRead(context); @@ -517,13 +522,9 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e ALeffectState_DecRef(EffectSlot->Effect.State); EffectSlot->Effect.State = State; - UpdateEffectSlotProps(EffectSlot); } else if(effect) - { EffectSlot->Effect.Props = effect->Props; - UpdateEffectSlotProps(EffectSlot); - } /* Remove state references from old effect slot property updates. */ props = ATOMIC_LOAD(&EffectSlot->FreeList); @@ -531,7 +532,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e { State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); if(State) ALeffectState_DecRef(State); - ATOMIC_LOAD(&props->next, almemory_order_relaxed); + props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } return AL_NO_ERROR; @@ -577,6 +578,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) if(!(slot->Effect.State=V0(factory,create)())) return AL_OUT_OF_MEMORY; + slot->NeedsUpdate = AL_FALSE; slot->Gain = 1.0; slot->AuxSendAuto = AL_TRUE; InitRef(&slot->ref, 0); @@ -661,8 +663,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* Swap out any stale effect state object there may be in the container, to * delete it. */ - if(slot->Effect.State) - ALeffectState_IncRef(slot->Effect.State); + ALeffectState_IncRef(slot->Effect.State); oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, almemory_order_relaxed); @@ -685,6 +686,22 @@ void UpdateEffectSlotProps(ALeffectslot *slot) ALeffectState_DecRef(oldstate); } +void UpdateAllEffectSlotProps(ALCcontext *context) +{ + ALeffectslot *slot; + + LockEffectSlotsRead(context); + slot = ATOMIC_LOAD(&context->ActiveAuxSlotList); + while(slot) + { + if(slot->NeedsUpdate) + UpdateEffectSlotProps(slot); + slot->NeedsUpdate = AL_FALSE; + slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); + } + UnlockEffectSlotsRead(context); +} + ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) { ALsizei pos; -- cgit v1.2.3 From ef03de39814486a1d91949cfff8b6a33bd137f91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Aug 2016 18:19:13 -0700 Subject: Avoid directly replacing the effect slot Update pointer --- OpenAL32/alAuxEffectSlot.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index fb8c27f4..479646b1 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -636,22 +636,18 @@ void UpdateEffectSlotProps(ALeffectslot *slot) struct ALeffectslotProps *props; ALeffectState *oldstate; - props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL); + /* Get an unused property container, or allocate a new one as needed. */ + props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); if(!props) + props = al_calloc(16, sizeof(*props)); + else { - /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); - if(!props) - props = al_calloc(16, sizeof(*props)); - else - { - struct ALeffectslotProps *next; - do { - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, - &slot->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_consume) == 0); - } + struct ALeffectslotProps *next; + do { + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + &slot->FreeList, &props, next, almemory_order_seq_cst, + almemory_order_consume) == 0); } /* Copy in current property values. */ -- cgit v1.2.3 From 4b153dade82b0558c96d54828bd2f9f86dc808fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Aug 2016 19:46:46 -0700 Subject: Allow sources to play while alcSuspendContext is in effect This appears to be how Creative's Windows drivers handle it, and is necessary for at least the Windows version of UT2k4 (otherwise it tries to play a source while suspended, checks and sees it's stopped, then kills it before it's given a chance to start playing). Consequently, the internal properties it gets mixed with are determined by what the source properties are at the time of the play call, and the listener properties at the time of the suspend call. This does not change alDeferUpdatesSOFT, which will still hold the play state change until alProcessUpdatesSOFT. --- Alc/ALc.c | 6 +++--- OpenAL32/Include/alMain.h | 8 +++++++- OpenAL32/alSource.c | 2 +- OpenAL32/alState.c | 17 +++++++++++------ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b95c90f8..26cdc771 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1584,9 +1584,9 @@ extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS * does *NOT* stop mixing, but rather prevents certain property changes from * taking effect. */ -void ALCcontext_DeferUpdates(ALCcontext *context) +void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type) { - ATOMIC_STORE(&context->DeferUpdates, AL_TRUE); + ATOMIC_STORE(&context->DeferUpdates, type); } /* ALCcontext_ProcessUpdates @@ -2545,7 +2545,7 @@ ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) alcSetError(NULL, ALC_INVALID_CONTEXT); else { - ALCcontext_DeferUpdates(context); + ALCcontext_DeferUpdates(context, DeferAllowPlay); ALCcontext_DecRef(context); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e0e1b835..74f967ae 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -772,7 +772,7 @@ void AppendCaptureDeviceList(const ALCchar *name); void ALCdevice_Lock(ALCdevice *device); void ALCdevice_Unlock(ALCdevice *device); -void ALCcontext_DeferUpdates(ALCcontext *context); +void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type); void ALCcontext_ProcessUpdates(ALCcontext *context); inline void LockContext(ALCcontext *context) @@ -781,6 +781,12 @@ inline void LockContext(ALCcontext *context) inline void UnlockContext(ALCcontext *context) { ALCdevice_Unlock(context->Device); } +enum { + DeferOff = AL_FALSE, + DeferAll, + DeferAllowPlay +}; + typedef struct { #ifdef HAVE_FENV_H diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f5941729..a7d7f35c 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2316,7 +2316,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) context->MaxVoices = newcount; } - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) { for(i = 0;i < n;i++) { diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index fa3b190a..330d7fe2 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -150,7 +150,8 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + value = AL_TRUE; break; default: @@ -190,7 +191,8 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALdouble)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + value = (ALdouble)AL_TRUE; break; default: @@ -230,7 +232,8 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALfloat)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + value = (ALfloat)AL_TRUE; break; default: @@ -270,7 +273,8 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALint)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + value = (ALint)AL_TRUE; break; default: @@ -310,7 +314,8 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - value = (ALint64SOFT)ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + value = (ALint64SOFT)AL_TRUE; break; default: @@ -638,7 +643,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) context = GetContextRef(); if(!context) return; - ALCcontext_DeferUpdates(context); + ALCcontext_DeferUpdates(context, DeferAll); ALCcontext_DecRef(context); } -- cgit v1.2.3 From 3d59021702c2f6ea4dbdf5d2f6231fd945370e27 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Aug 2016 06:28:04 -0700 Subject: Clamp the maximum mixing gain boost to 16 The combined source and listener gains now can't exceed a multiplier of 16 (~24dB). This is to avoid mixes getting out of control with large volume boosts, which reduces the effective precision given by floating-point. --- Alc/ALu.c | 21 +++++++++++---------- OpenAL32/Include/alu.h | 2 ++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index eafb082c..fc49c60f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -452,13 +452,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); - DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain = minf(DryGain, GAIN_MIX_MAX); DryGainHF = ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); DryGainLF = ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); for(i = 0;i < NumSends;i++) { - WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); - WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); + WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); WetGainHF[i] = ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); WetGainLF[i] = ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); } @@ -1086,18 +1088,17 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } } - /* Clamp to Min/Max Gain */ - DryGain = clampf(DryGain, MinVolume, MaxVolume); - for(i = 0;i < NumSends;i++) - WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); - /* Apply gain and frequency filters */ - DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain = clampf(DryGain, MinVolume, MaxVolume); + DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain = minf(DryGain, GAIN_MIX_MAX); DryGainHF *= ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); DryGainLF *= ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); for(i = 0;i < NumSends;i++) { - WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); + WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); WetGainHF[i] *= ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); WetGainLF[i] *= ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 1d922881..70ce7059 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -173,6 +173,8 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict Values)[2], ALuint BufferSize); +#define GAIN_MIX_MAX (16.0f) /* +24dB */ + #define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */ #define SPEEDOFSOUNDMETRESPERSEC (343.3f) -- cgit v1.2.3 From 5bf0c6425868c2cd581786cfb0b74b96d4c07992 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Aug 2016 18:21:09 -0700 Subject: Add a query for the maximum source gain limit --- Alc/ALc.c | 1 + OpenAL32/Include/alMain.h | 5 +++++ OpenAL32/alState.c | 26 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 26cdc771..61036585 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -552,6 +552,7 @@ static const ALCenums enumeration[] = { DECL(AL_SPEED_OF_SOUND), DECL(AL_SOURCE_DISTANCE_MODEL), DECL(AL_DEFERRED_UPDATES_SOFT), + DECL(AL_GAIN_LIMIT_SOFT), DECL(AL_INVERSE_DISTANCE), DECL(AL_INVERSE_DISTANCE_CLAMPED), diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 74f967ae..c6b816d9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -127,6 +127,11 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif #endif +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 330d7fe2..c25aa63e 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -154,6 +154,11 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) value = AL_TRUE; break; + case AL_GAIN_LIMIT_SOFT: + if(GAIN_MIX_MAX != 0.0f) + value = AL_TRUE; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -195,6 +200,10 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) value = (ALdouble)AL_TRUE; break; + case AL_GAIN_LIMIT_SOFT: + value = (ALdouble)GAIN_MIX_MAX; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -236,6 +245,10 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) value = (ALfloat)AL_TRUE; break; + case AL_GAIN_LIMIT_SOFT: + value = GAIN_MIX_MAX; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -277,6 +290,10 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) value = (ALint)AL_TRUE; break; + case AL_GAIN_LIMIT_SOFT: + value = (ALint)GAIN_MIX_MAX; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -318,6 +335,10 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) value = (ALint64SOFT)AL_TRUE; break; + case AL_GAIN_LIMIT_SOFT: + value = (ALint64SOFT)GAIN_MIX_MAX; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -341,6 +362,7 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: values[0] = alGetBoolean(pname); return; } @@ -374,6 +396,7 @@ 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_GAIN_LIMIT_SOFT: values[0] = alGetDouble(pname); return; } @@ -407,6 +430,7 @@ 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_GAIN_LIMIT_SOFT: values[0] = alGetFloat(pname); return; } @@ -440,6 +464,7 @@ 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_GAIN_LIMIT_SOFT: values[0] = alGetInteger(pname); return; } @@ -471,6 +496,7 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: values[0] = alGetInteger64SOFT(pname); return; } -- cgit v1.2.3 From 54649851fa8769c2290741c63e2255b13eec3824 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Aug 2016 01:53:52 -0700 Subject: Remove the upper limit from AL_MIN_GAIN and AL_MAX_GAIN As per the current AL_SOFT_gain_clamp_ex proposal. --- Alc/ALc.c | 4 ++-- OpenAL32/alSource.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 61036585..7759393b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -715,8 +715,8 @@ static const ALchar alExtList[] = "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " "AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES " "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels AL_SOFT_loop_points AL_SOFT_MSADPCM " - "AL_SOFT_source_latency AL_SOFT_source_length"; + "AL_SOFT_direct_channels AL_SOFTX_gain_clamp_ex AL_SOFT_loop_points " + "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a7d7f35c..f20498f4 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -453,14 +453,14 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); + CHECKVAL(*values >= 0.0f); Source->MinGain = *values; DO_UPDATEPROPS(); return AL_TRUE; case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); + CHECKVAL(*values >= 0.0f); Source->MaxGain = *values; DO_UPDATEPROPS(); -- cgit v1.2.3 From 4859984e33bafa242f068da44d9eb5ca73c39632 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Aug 2016 01:55:44 -0700 Subject: Add an option to alffplay to toggle AL_DIRECT_CHANNELS_SOFT Using the 'd' key will toggle the playback source's AL_DIRECT_CHANNELS_SOFT property. Although there is no visual feedback showing when it's on or off. --- examples/alffplay.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/examples/alffplay.c b/examples/alffplay.c index b9acbb8e..16684c5e 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -33,6 +33,7 @@ #include "AL/alext.h" +static bool has_direct_out = false; static bool has_latency_check = false; static LPALGETSOURCEDVSOFT alGetSourcedvSOFT; @@ -140,6 +141,7 @@ typedef struct MovieState { volatile bool seek_req; int64_t seek_pos; + volatile bool direct_req; int av_sync_type; @@ -750,6 +752,17 @@ static int audio_thread(void *userdata) } SDL_Delay(AUDIO_BUFFER_TIME); + if(movState->direct_req) + { + if(has_direct_out) + { + alGetSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, &state); + alSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, + state ? AL_FALSE : AL_TRUE); + } + movState->direct_req = false; + } + almtx_lock(&movState->audio.src_mutex); } almtx_unlock(&movState->audio.src_mutex); @@ -1397,6 +1410,11 @@ int main(int argc, char *argv[]) return 1; } + if(!alIsExtensionPresent("AL_SOFT_direct_channels")) + fprintf(stderr, "AL_SOFT_direct_channels not supported.\n"); + else + has_direct_out = true; + if(!alIsExtensionPresent("AL_SOFT_source_latency")) fprintf(stderr, "AL_SOFT_source_latency not supported, audio may be a bit laggy.\n"); else @@ -1475,6 +1493,10 @@ int main(int argc, char *argv[]) stream_seek(movState, -30.0); break; + case SDLK_d: + movState->direct_req = true; + break; + default: break; } -- cgit v1.2.3 From 6d7f9aacd6b7bb3941ffdab21664765ee9db7d9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Aug 2016 22:18:44 -0700 Subject: Print whether direct channels are off or on to stdout in alffplay --- examples/alffplay.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index 16684c5e..2d38216f 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -757,8 +757,11 @@ static int audio_thread(void *userdata) if(has_direct_out) { alGetSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, &state); + state = !state; alSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, - state ? AL_FALSE : AL_TRUE); + state ? AL_TRUE : AL_FALSE); + printf("Direct channels %s\n", state ? "on" : "off"); + fflush(stdout); } movState->direct_req = false; } -- cgit v1.2.3 From 8d3a2865775e1747cb7f2905635bb95a43d5d0ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Aug 2016 04:21:57 -0700 Subject: Simplify the ambisonic up-sampler It still behaves the same, although now combines the separate decode+encode matrices into a transcode matrix (one per frequency band). --- Alc/bformatdec.c | 164 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 65 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 356423ce..20e19bb6 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -122,6 +122,12 @@ enum FreqBand { FB_Max }; +static const ALfloat SquarePoints[4][3] = { + { -0.707106781f, 0.0f, -0.707106781f }, + { 0.707106781f, 0.0f, -0.707106781f }, + { -0.707106781f, 0.0f, 0.707106781f }, + { 0.707106781f, 0.0f, 0.707106781f }, +}; static const ALfloat SquareMatrix[4][FB_Max][MAX_AMBI_COEFFS] = { { { 0.353553f, 0.204094f, 0.0f, 0.204094f }, { 0.25f, 0.204094f, 0.0f, 0.204094f } }, { { 0.353553f, -0.204094f, 0.0f, 0.204094f }, { 0.25f, -0.204094f, 0.0f, 0.204094f } }, @@ -180,12 +186,9 @@ static void init_bformatdec(void) for(i = 0;i < COUNTOF(CubePoints);i++) CalcDirectionCoeffs(CubePoints[i], 0.0f, CubeEncoder[i]); - CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[0]); - CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[1]); - CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[2]); - CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[3]); - - for(i = 0;i < 4;i++) + for(i = 0;i < COUNTOF(SquarePoints);i++) + CalcDirectionCoeffs(SquarePoints[i], 0.0f, SquareEncoder[i]); + for(i = 0;i < COUNTOF(SquarePoints);i++) { /* Remove the skipped height-related coefficients for 2D rendering. */ SquareEncoder[i][2] = SquareEncoder[i][3]; @@ -227,9 +230,7 @@ typedef struct BFormatDec { struct { BandSplitter XOver[4]; - const ALfloat (*restrict Matrix)[FB_Max][MAX_AMBI_COEFFS]; - const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS]; - ALuint NumChannels; + ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max]; } UpSampler; ALuint NumChannels; @@ -282,7 +283,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, const ALfloat *coeff_scale = UnitScale; ALfloat distgain[MAX_OUTPUT_CHANNELS]; ALfloat maxdist, ratio; - ALuint i; + ALuint i, j, k; al_free(dec->Samples); dec->Samples = NULL; @@ -307,18 +308,42 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ratio = 400.0f / (ALfloat)srate; for(i = 0;i < 4;i++) bandsplit_init(&dec->UpSampler.XOver[i], ratio); + memset(dec->UpSampler.Gains, 0, sizeof(dec->UpSampler.Gains)); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - dec->UpSampler.Matrix = CubeMatrix; - dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder; - dec->UpSampler.NumChannels = 8; + /* Combine the matrices that do the in->virt and virt->out conversions + * so we get a single in->out conversion. + */ + for(i = 0;i < 4;i++) + { + for(j = 0;j < dec->NumChannels;j++) + { + ALfloat *gains = dec->UpSampler.Gains[i][j]; + for(k = 0;k < COUNTOF(CubeMatrix);k++) + { + gains[FB_HighFreq] += CubeMatrix[k][FB_HighFreq][i]*CubeEncoder[k][j]; + gains[FB_LowFreq] += CubeMatrix[k][FB_LowFreq][i]*CubeEncoder[k][j]; + } + } + } + dec->Periphonic = AL_TRUE; } else { - dec->UpSampler.Matrix = SquareMatrix; - dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder; - dec->UpSampler.NumChannels = 4; + for(i = 0;i < 4;i++) + { + for(j = 0;j < dec->NumChannels;j++) + { + ALfloat *gains = dec->UpSampler.Gains[i][j]; + for(k = 0;k < COUNTOF(SquareMatrix);k++) + { + gains[FB_HighFreq] += SquareMatrix[k][FB_HighFreq][i]*SquareEncoder[k][j]; + gains[FB_LowFreq] += SquareMatrix[k][FB_LowFreq][i]*SquareEncoder[k][j]; + } + } + } + dec->Periphonic = AL_FALSE; } @@ -559,51 +584,48 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) { - ALuint i, j, k; - - /* First, split the first-order components into low and high frequency - * bands. This assumes SamplesHF and SamplesLF have enough space for first- - * order content (to which, this up-sampler is only used with second-order - * or higher decoding, so it will). - */ - for(i = 0;i < InChannels;i++) - bandsplit_process(&dec->UpSampler.XOver[i], dec->SamplesHF[i], dec->SamplesLF[i], - InSamples[i], SamplesToDo); + ALuint in, i, j, k; /* This up-sampler is very simplistic. It essentially decodes the first- * order content to a square channel array (or cube if height is desired), - * then encodes those points onto the higher order soundfield. + * then encodes those points onto the higher order soundfield. The decoder + * and encoder matrices have been combined to directly convert each input + * channel to the output, without the need for storing the virtual channel + * array. */ - for(k = 0;k < dec->UpSampler.NumChannels;k++) + for(in = 0;in < InChannels;in++) { - memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->UpSampler.Matrix[k][FB_HighFreq], - dec->SamplesHF, InChannels, SamplesToDo); - MixMatrixRow(dec->ChannelMix, dec->UpSampler.Matrix[k][FB_LowFreq], - dec->SamplesLF, InChannels, SamplesToDo); - + /* First, split the first-order components into low and high frequency + * bands. + */ + bandsplit_process(&dec->UpSampler.XOver[in], + dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq], + InSamples[in], SamplesToDo + ); + + /* Now write each band to the output. */ for(j = 0;j < dec->NumChannels;j++) { - ALfloat gain = dec->UpSampler.Encoder[k][j]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(i = 0;i < SamplesToDo;i++) - OutBuffer[j][i] += dec->ChannelMix[i] * gain; + for(k = 0;k < FB_Max;k++) + { + ALfloat gain = dec->UpSampler.Gains[in][j][k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < SamplesToDo;i++) + OutBuffer[j][i] += dec->Samples[k][i] * gain; + } } } } typedef struct AmbiUpsampler { - alignas(16) ALfloat SamplesHF[4][BUFFERSIZE]; - alignas(16) ALfloat SamplesLF[4][BUFFERSIZE]; - - alignas(16) ALfloat ChannelMix[BUFFERSIZE]; + alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE]; BandSplitter XOver[4]; - ALfloat Gains[8][MAX_OUTPUT_CHANNELS]; - ALuint NumChannels; + ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max]; } AmbiUpsampler; AmbiUpsampler *ambiup_alloc() @@ -619,41 +641,53 @@ void ambiup_free(struct AmbiUpsampler *ambiup) void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { + ALfloat gains[8][MAX_OUTPUT_CHANNELS]; ALfloat ratio; - ALuint i; + ALuint i, j, k; ratio = 400.0f / (ALfloat)device->Frequency; for(i = 0;i < 4;i++) bandsplit_init(&ambiup->XOver[i], ratio); - ambiup->NumChannels = COUNTOF(CubePoints); - for(i = 0;i < ambiup->NumChannels;i++) - ComputePanningGains(device->Dry, CubeEncoder[i], 1.0f, ambiup->Gains[i]); + for(i = 0;i < COUNTOF(CubePoints);i++) + ComputePanningGains(device->Dry, CubeEncoder[i], 1.0f, gains[i]); + + memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); + for(i = 0;i < 4;i++) + { + for(j = 0;j < device->Dry.NumChannels;j++) + { + for(k = 0;k < COUNTOF(CubePoints);k++) + { + ambiup->Gains[i][j][FB_HighFreq] += CubeMatrix[k][FB_HighFreq][i]*gains[k][j]; + ambiup->Gains[i][j][FB_LowFreq] += CubeMatrix[k][FB_LowFreq][i]*gains[k][j]; + } + } + } } void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { - ALuint i, j, k; + ALuint in, i, j, k; - for(i = 0;i < 4;i++) - bandsplit_process(&ambiup->XOver[i], ambiup->SamplesHF[i], ambiup->SamplesLF[i], - InSamples[i], SamplesToDo); - - for(k = 0;k < ambiup->NumChannels;k++) + for(in = 0;in < 4;in++) { - memset(ambiup->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(ambiup->ChannelMix, CubeMatrix[k][FB_HighFreq], - ambiup->SamplesHF, 4, SamplesToDo); - MixMatrixRow(ambiup->ChannelMix, CubeMatrix[k][FB_LowFreq], - ambiup->SamplesLF, 4, SamplesToDo); + bandsplit_process(&ambiup->XOver[in], + ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq], + InSamples[in], SamplesToDo + ); for(j = 0;j < OutChannels;j++) { - ALfloat gain = ambiup->Gains[k][j]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(i = 0;i < SamplesToDo;i++) - OutBuffer[j][i] += ambiup->ChannelMix[i] * gain; + for(k = 0;k < FB_Max;k++) + { + ALfloat gain = ambiup->Gains[in][j][k]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < SamplesToDo;i++) + OutBuffer[j][i] += ambiup->Samples[k][i] * gain; + } } } } -- cgit v1.2.3 From f791b8c517732adf3dfc50b5b6086400b720960b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Aug 2016 22:33:33 -0700 Subject: Add a compile-time macro to use dual-band ambisonic HRTF processing Use single-band processing for now, to see if dual-band is causing a drop in quality at all. --- Alc/hrtf.c | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index b11fb9a8..d0511083 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -198,6 +198,11 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, { { 0.25f, -0.14425f, -0.14425f, -0.14425f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; +/* Change this to 2 for dual-band HRTF processing. May require a higher quality + * band-splitter, or better calculation of the new IR length to deal with the + * tail generated by the filter. + */ +#define NUM_BANDS 1 BandSplitter splitter; ALfloat temps[3][HRIR_LENGTH]; ALuint lidx[8], ridx[8]; @@ -239,18 +244,27 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ const ALshort *fir; ALuint delay; - /* Band-split left HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); + /* Convert the left FIR from shorts to float */ fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; - for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i] / 32767.0f; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + if(NUM_BANDS == 1) + { + for(i = 0;i < Hrtf->irSize;i++) + temps[0][i] = fir[i] / 32767.0f; + } + else + { + /* Band-split left HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); + for(i = 0;i < Hrtf->irSize;i++) + temps[2][i] = fir[i] / 32767.0f; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + } /* Add to the left output coefficients with the specified delay. */ delay = Hrtf->delays[lidx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { - for(b = 0;b < 2;b++) + for(b = 0;b < NUM_BANDS;b++) { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) @@ -259,18 +273,27 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ } max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); - /* Band-split right HRIR into low and high frequency responses. */ - bandsplit_clear(&splitter); + /* Convert the right FIR from shorts to float */ fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; - for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i] / 32767.0f; - bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + if(NUM_BANDS == 1) + { + for(i = 0;i < Hrtf->irSize;i++) + temps[0][i] = fir[i] / 32767.0f; + } + else + { + /* Band-split right HRIR into low and high frequency responses. */ + bandsplit_clear(&splitter); + for(i = 0;i < Hrtf->irSize;i++) + temps[2][i] = fir[i] / 32767.0f; + bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + } /* Add to the right output coefficients with the specified delay. */ delay = Hrtf->delays[ridx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { - for(b = 0;b < 2;b++) + for(b = 0;b < NUM_BANDS;b++) { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) @@ -280,6 +303,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); } TRACE("Skipped min delay: %u, new combined length: %u\n", min_delay, max_length); +#undef NUM_BANDS return max_length; } -- cgit v1.2.3 From ccf90df07215b4317e2842641a8915d757868e8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Aug 2016 04:56:10 -0700 Subject: Initialize some enums to dummy values --- OpenAL32/alBuffer.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index c52924a9..f9093cb7 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -139,8 +139,8 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) { - enum UserFmtChannels srcchannels; - enum UserFmtType srctype; + enum UserFmtChannels srcchannels = UserFmtMono; + enum UserFmtType srctype = UserFmtByte; ALCdevice *device; ALCcontext *context; ALbuffer *albuf; @@ -288,8 +288,8 @@ done: AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) { - enum UserFmtChannels srcchannels; - enum UserFmtType srctype; + enum UserFmtChannels srcchannels = UserFmtMono; + enum UserFmtType srctype = UserFmtByte; ALCdevice *device; ALCcontext *context; ALbuffer *albuf; @@ -981,13 +981,14 @@ done: */ ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc) { + enum FmtChannels DstChannels = FmtMono; + enum FmtType DstType = FmtByte; ALuint NewChannels, NewBytes; - enum FmtChannels DstChannels; - enum FmtType DstType; ALuint64 newsize; - if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE || - (long)SrcChannels != (long)DstChannels) + if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE) + return AL_INVALID_ENUM; + if((long)SrcChannels != (long)DstChannels) return AL_INVALID_ENUM; NewChannels = ChannelsFromFmt(DstChannels); -- cgit v1.2.3 From e01c33792108e3f0026c29a63ce38096d232aa51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Aug 2016 08:14:50 -0700 Subject: Add some helper wrappers to mmap files --- Alc/compat.h | 13 +++++++ Alc/helpers.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/Alc/compat.h b/Alc/compat.h index 0443692a..114fc655 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -25,6 +25,19 @@ FILE *al_fopen(const char *fname, const char *mode); #endif +struct FileMapping { +#ifdef _WIN32 + HANDLE file; + HANDLE fmap; +#else + int fd; +#endif + void *ptr; + size_t len; +}; +struct FileMapping MapFileToMem(const char *fname); +void UnmapFileMem(const struct FileMapping *mapping); + al_string GetProcPath(void); #ifdef HAVE_DYNLOAD diff --git a/Alc/helpers.c b/Alc/helpers.c index 2a059c68..9d7d564f 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -89,6 +89,10 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x #endif #ifndef _WIN32 +#include +#include +#include +#include #include #elif defined(_WIN32_IE) #include @@ -598,6 +602,68 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) return results; } + +struct FileMapping MapFileToMem(const char *fname) +{ + struct FileMapping ret = { NULL, NULL, NULL, 0 }; + MEMORY_BASIC_INFORMATION meminfo; + HANDLE file, fmap; + WCHAR *wname; + void *ptr; + + wname = FromUTF8(fname); + + file = CreateFileW(wname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(file == INVALID_HANDLE_VALUE) + { + ERR("Failed to open %s: %lu\n", fname, GetLastError()); + free(wname); + return ret; + } + free(wname); + wname = NULL; + + fmap = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL); + if(!fmap) + { + ERR("Failed to create map for %s: %lu\n", fname, GetLastError()); + CloseHandle(file); + return ret; + } + + ptr = MapViewOfFile(fmap, FILE_MAP_READ, 0, 0, 0); + if(!ptr) + { + ERR("Failed to map %s: %lu\n", fname, GetLastError()); + CloseHandle(fmap); + CloseHandle(file); + return ret; + } + + if(VirtualQuery(ptr, &meminfo, sizeof(meminfo)) != sizeof(meminfo)) + { + ERR("Failed to get map size for %s: %lu\n", fname, GetLastError()); + UnmapViewOfFile(ptr); + CloseHandle(fmap); + CloseHandle(file); + return ret; + } + + ret.file = file; + ret.fmap = fmap; + ret.ptr = ptr; + ret.len = meminfo.RegionSize; + return ret; +} + +void UnmapFileMem(const struct FileMapping *mapping) +{ + UnmapViewOfFile(mapping->ptr); + CloseHandle(mapping->fmap); + CloseHandle(mapping->file); +} + #else al_string GetProcPath(void) @@ -810,6 +876,47 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) return results; } + +struct FileMapping MapFileToMem(const char *fname) +{ + struct FileMapping ret = { -1, NULL, 0 }; + struct stat sbuf; + void *ptr; + int fd; + + fd = open(fname, O_RDONLY, 0); + if(fd == -1) + { + ERR("Failed to open %s: (%d) %s\n", fname, errno, strerror(errno)); + return ret; + } + if(fstat(fd, &sbuf) == -1) + { + ERR("Failed to stat %s: (%d) %s\n", fname, errno, strerror(errno)); + close(fd); + return ret; + } + + ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if(ptr == MAP_FAILED) + { + ERR("Failed to map %s: (%d) %s\n", fname, errno, strerror(errno)); + close(fd); + return ret; + } + + ret.fd = fd; + ret.ptr = ptr; + ret.len = sbuf.st_size; + return ret; +} + +void UnmapFileMem(const struct FileMapping *mapping) +{ + munmap(mapping->ptr, mapping->len); + close(mapping->fd); +} + #endif -- cgit v1.2.3 From 566d449e536e2e1a21efe4c837d79d52792b39a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Aug 2016 08:16:49 -0700 Subject: Always load HRTF files through memory pointers --- Alc/hrtf.c | 395 +++++++++++++++++++++---------------------------------------- 1 file changed, 134 insertions(+), 261 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d0511083..d189ad35 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -309,7 +309,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ } -static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) +static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; @@ -320,21 +320,32 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - ALubyte *delays = NULL; + const ALubyte *delays = NULL; ALuint i, j; - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; + if(datalen < 9) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", + al_string_get_cstr(filename), 9, datalen); + return NULL; + } + + rate = *(data++); + rate |= *(data++)<<8; + rate |= *(data++)<<16; + rate |= *(data++)<<24; + datalen -= 4; - irCount = fgetc(f); - irCount |= fgetc(f)<<8; + irCount = *(data++); + irCount |= *(data++)<<8; + datalen -= 2; - irSize = fgetc(f); - irSize |= fgetc(f)<<8; + irSize = *(data++); + irSize |= *(data++)<<8; + datalen -= 2; - evCount = fgetc(f); + evCount = *(data++); + datalen -= 1; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -348,10 +359,16 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) evCount, MIN_EV_COUNT, MAX_EV_COUNT); failed = AL_TRUE; } - if(failed) return NULL; + if(datalen < evCount*2) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", + al_string_get_cstr(filename), evCount*2, datalen); + return NULL; + } + azCount = malloc(sizeof(azCount[0])*evCount); evOffset = malloc(sizeof(evOffset[0])*evCount); if(azCount == NULL || evOffset == NULL) @@ -362,12 +379,14 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) if(!failed) { - evOffset[0] = fgetc(f); - evOffset[0] |= fgetc(f)<<8; + evOffset[0] = *(data++); + evOffset[0] |= *(data++)<<8; + datalen -= 2; for(i = 1;i < evCount;i++) { - evOffset[i] = fgetc(f); - evOffset[i] |= fgetc(f)<<8; + evOffset[i] = *(data++); + evOffset[i] |= *(data++)<<8; + datalen -= 2; if(evOffset[i] <= evOffset[i-1]) { ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", @@ -402,41 +421,47 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) if(!failed) { coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) + if(coeffs == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; } } + if(!failed) + { + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n", + al_string_get_cstr(filename), reqsize, datalen); + failed = AL_TRUE; + } + } + if(!failed) { for(i = 0;i < irCount*irSize;i+=irSize) { for(j = 0;j < irSize;j++) { - ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; - coeffs[i+j] = coeff; + coeffs[i+j] = *(data++); + coeffs[i+j] |= *(data++)<<8; + datalen -= 2; } } + + delays = data; + data += irCount; + datalen -= irCount; for(i = 0;i < irCount;i++) { - delays[i] = fgetc(f); if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); failed = AL_TRUE; } } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } } if(!failed) @@ -478,31 +503,40 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) free(azCount); free(evOffset); free(coeffs); - free(delays); return Hrtf; } -static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) +static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; ALuint rate = 0, irCount = 0; ALubyte irSize = 0, evCount = 0; - ALubyte *azCount = NULL; + const ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - ALubyte *delays = NULL; + const ALubyte *delays = NULL; ALuint i, j; - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; + if(datalen < 6) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), 6, datalen); + return NULL; + } + + rate = *(data++); + rate |= *(data++)<<8; + rate |= *(data++)<<16; + rate |= *(data++)<<24; + datalen -= 4; - irSize = fgetc(f); + irSize = *(data++); + datalen -= 1; - evCount = fgetc(f); + evCount = *(data++); + datalen -= 1; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -516,11 +550,20 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) evCount, MIN_EV_COUNT, MAX_EV_COUNT); failed = AL_TRUE; } - if(failed) return NULL; - azCount = malloc(sizeof(azCount[0])*evCount); + if(datalen < evCount) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), evCount, datalen); + return NULL; + } + + azCount = data; + data += evCount; + datalen -= evCount; + evOffset = malloc(sizeof(evOffset[0])*evCount); if(azCount == NULL || evOffset == NULL) { @@ -532,7 +575,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) { for(i = 0;i < evCount;i++) { - azCount[i] = fgetc(f); if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) { ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", @@ -553,14 +595,24 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) } coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) + if(coeffs == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; } } + if(!failed) + { + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", + al_string_get_cstr(filename), reqsize, datalen); + failed = AL_TRUE; + } + } + if(!failed) { for(i = 0;i < irCount*irSize;i+=irSize) @@ -568,26 +620,24 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) for(j = 0;j < irSize;j++) { ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; + coeff = *(data++); + coeff |= *(data++)<<8; + datalen -= 2; coeffs[i+j] = coeff; } } + + delays = data; + data += irCount; + datalen -= irCount; for(i = 0;i < irCount;i++) { - delays[i] = fgetc(f); if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); failed = AL_TRUE; } } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } } if(!failed) @@ -626,10 +676,8 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); } - free(azCount); free(evOffset); free(coeffs); - free(delays); return Hrtf; } @@ -638,10 +686,9 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; struct Hrtf *hrtf = NULL; const HrtfEntry *iter; + struct FileMapping fmap; const char *name; const char *ext; - ALchar magic[8]; - FILE *f; int i; name = strrchr(al_string_get_cstr(*filename), '/'); @@ -670,31 +717,32 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) } TRACE("Loading %s...\n", al_string_get_cstr(*filename)); - f = al_fopen(al_string_get_cstr(*filename), "rb"); - if(f == NULL) + fmap = MapFileToMem(al_string_get_cstr(*filename)); + if(fmap.ptr == NULL) { ERR("Could not open %s\n", al_string_get_cstr(*filename)); goto done; } - if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) - ERR("Failed to read header from %s\n", al_string_get_cstr(*filename)); - else + if(fmap.len < sizeof(magicMarker01)) + ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), fmap.len); + else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) { - if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(f, *filename); - } - else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(f, *filename); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), magic); + TRACE("Detected data set format v1\n"); + hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), + fmap.len-sizeof(magicMarker01), *filename + ); } - fclose(f); + else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), + fmap.len-sizeof(magicMarker00), *filename + ); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), (const char*)fmap.ptr); + UnmapFileMem(&fmap); if(!hrtf) { @@ -740,189 +788,8 @@ done: al_string_deinit(filename); } - -/* Unfortunate that we have to duplicate LoadHrtf01 like this, to take a memory - * buffer for input instead of a FILE*, but there's no portable way to access a - * memory buffer through the standard FILE* I/O API (POSIX 2008 has fmemopen, - * and Windows doesn't seem to have anything). - */ -static struct Hrtf *LoadBuiltInHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) -{ - const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; - ALubyte irSize = 0, evCount = 0; - const ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - const ALubyte *delays = NULL; - ALuint i, j; - - if(datalen < 6) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), 6, datalen); - return NULL; - } - - rate = *(data++); - rate |= *(data++)<<8; - rate |= *(data++)<<16; - rate |= *(data++)<<24; - datalen -= 4; - - irSize = *(data++); - datalen -= 1; - - evCount = *(data++); - datalen -= 1; - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - if(datalen < evCount) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), evCount, datalen); - return NULL; - } - - azCount = data; - data += evCount; - datalen -= evCount; - - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - for(i = 0;i < evCount;i++) - { - if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - if(coeffs == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - al_string_get_cstr(filename), reqsize, datalen); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount*irSize;i+=irSize) - { - for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = *(data++); - coeff |= *(data++)<<8; - datalen -= 2; - coeffs[i+j] = coeff; - } - } - - delays = data; - data += irCount; - datalen -= irCount; - for(i = 0;i < irCount;i++) - { - if(delays[i] > maxDelay) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - size_t total = sizeof(struct Hrtf); - total += sizeof(azCount[0])*evCount; - total += sizeof(evOffset[0])*evCount; - total += sizeof(coeffs[0])*irSize*irCount; - total += sizeof(delays[0])*irCount; - total += al_string_length(filename)+1; - - Hrtf = al_calloc(16, total); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(Hrtf+1)); - Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); - Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); - Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); - Hrtf->filename = ((char*)(Hrtf->delays + irCount)); - Hrtf->next = NULL; - - memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); - memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); - memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); - memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); - memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); - } - - free(evOffset); - free(coeffs); - return Hrtf; -} - -/* Another unfortunate duplication, this time of AddFileEntry to take a memory - * buffer for input instead of opening the given filename. +/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer + * for input instead of opening the given filename. */ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename) { @@ -961,9 +828,15 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - hrtf = LoadBuiltInHrtf01( - data+sizeof(magicMarker01), datalen-sizeof(magicMarker01), - *filename + hrtf = LoadHrtf01(data+sizeof(magicMarker01), + datalen-sizeof(magicMarker01), *filename + ); + } + else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00(data+sizeof(magicMarker00), + datalen-sizeof(magicMarker00), *filename ); } else -- cgit v1.2.3 From 7a140b6912123a3ae127f6fadc229b2bb1c24939 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Aug 2016 08:27:57 -0700 Subject: Reorganize sample type conversion functions To help avoid redundant manual definitions. --- OpenAL32/sample_cvt.c | 415 ++++++++++++++++---------------------------------- 1 file changed, 129 insertions(+), 286 deletions(-) diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index a02b217e..aff3de83 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -541,297 +541,128 @@ static inline ALubyte3 EncodeUByte3(ALint val) } -static inline ALbyte Conv_ALbyte_ALbyte(ALbyte val) -{ return val; } -static inline ALbyte Conv_ALbyte_ALubyte(ALubyte val) -{ return val-128; } -static inline ALbyte Conv_ALbyte_ALshort(ALshort val) -{ return val>>8; } -static inline ALbyte Conv_ALbyte_ALushort(ALushort val) -{ return (val>>8)-128; } -static inline ALbyte Conv_ALbyte_ALint(ALint val) -{ return val>>24; } -static inline ALbyte Conv_ALbyte_ALuint(ALuint val) -{ return (val>>24)-128; } -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) -{ - 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) -{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); } -static inline ALbyte Conv_ALbyte_ALalaw(ALalaw val) -{ return Conv_ALbyte_ALshort(DecodeALaw(val)); } -static inline ALbyte Conv_ALbyte_ALbyte3(ALbyte3 val) -{ return DecodeByte3(val)>>16; } -static inline ALbyte Conv_ALbyte_ALubyte3(ALubyte3 val) -{ return (DecodeUByte3(val)>>16)-128; } - -static inline ALubyte Conv_ALubyte_ALbyte(ALbyte val) -{ return val+128; } -static inline ALubyte Conv_ALubyte_ALubyte(ALubyte val) -{ return val; } -static inline ALubyte Conv_ALubyte_ALshort(ALshort val) -{ return (val>>8)+128; } -static inline ALubyte Conv_ALubyte_ALushort(ALushort val) -{ return val>>8; } -static inline ALubyte Conv_ALubyte_ALint(ALint val) -{ return (val>>24)+128; } -static inline ALubyte Conv_ALubyte_ALuint(ALuint val) -{ return val>>24; } -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) -{ - 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) -{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); } -static inline ALubyte Conv_ALubyte_ALalaw(ALalaw val) -{ return Conv_ALubyte_ALshort(DecodeALaw(val)); } -static inline ALubyte Conv_ALubyte_ALbyte3(ALbyte3 val) -{ return (DecodeByte3(val)>>16)+128; } -static inline ALubyte Conv_ALubyte_ALubyte3(ALubyte3 val) -{ return DecodeUByte3(val)>>16; } - -static inline ALshort Conv_ALshort_ALbyte(ALbyte val) -{ return val<<8; } -static inline ALshort Conv_ALshort_ALubyte(ALubyte val) -{ return (val-128)<<8; } -static inline ALshort Conv_ALshort_ALshort(ALshort val) -{ return val; } -static inline ALshort Conv_ALshort_ALushort(ALushort val) -{ return val-32768; } -static inline ALshort Conv_ALshort_ALint(ALint val) -{ return val>>16; } -static inline ALshort Conv_ALshort_ALuint(ALuint val) -{ return (val>>16)-32768; } -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) -{ - 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) -{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); } -static inline ALshort Conv_ALshort_ALalaw(ALalaw val) -{ return Conv_ALshort_ALshort(DecodeALaw(val)); } -static inline ALshort Conv_ALshort_ALbyte3(ALbyte3 val) -{ return DecodeByte3(val)>>8; } -static inline ALshort Conv_ALshort_ALubyte3(ALubyte3 val) -{ return (DecodeUByte3(val)>>8)-32768; } - -static inline ALushort Conv_ALushort_ALbyte(ALbyte val) -{ return (val+128)<<8; } -static inline ALushort Conv_ALushort_ALubyte(ALubyte val) -{ return val<<8; } -static inline ALushort Conv_ALushort_ALshort(ALshort val) -{ return val+32768; } -static inline ALushort Conv_ALushort_ALushort(ALushort val) -{ return val; } -static inline ALushort Conv_ALushort_ALint(ALint val) -{ return (val>>16)+32768; } -static inline ALushort Conv_ALushort_ALuint(ALuint val) -{ return val>>16; } -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) -{ - 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) -{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); } -static inline ALushort Conv_ALushort_ALalaw(ALalaw val) -{ return Conv_ALushort_ALshort(DecodeALaw(val)); } -static inline ALushort Conv_ALushort_ALbyte3(ALbyte3 val) -{ return (DecodeByte3(val)>>8)+32768; } -static inline ALushort Conv_ALushort_ALubyte3(ALubyte3 val) -{ return DecodeUByte3(val)>>8; } - -static inline ALint Conv_ALint_ALbyte(ALbyte val) -{ return val<<24; } -static inline ALint Conv_ALint_ALubyte(ALubyte val) -{ return (val-128)<<24; } -static inline ALint Conv_ALint_ALshort(ALshort val) -{ return val<<16; } -static inline ALint Conv_ALint_ALushort(ALushort val) -{ return (val-32768)<<16; } -static inline ALint Conv_ALint_ALint(ALint val) -{ return val; } -static inline ALint Conv_ALint_ALuint(ALuint val) -{ return val-2147483648u; } -static inline ALint Conv_ALint_ALfloat(ALfloat val) -{ - if(val > 1.0f) return 2147483647; - if(val < -1.0f) return -2147483647-1; - return (ALint)(val*16777215.0f) << 7; -} -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) -{ return Conv_ALint_ALshort(DecodeMuLaw(val)); } -static inline ALint Conv_ALint_ALalaw(ALalaw val) -{ return Conv_ALint_ALshort(DecodeALaw(val)); } -static inline ALint Conv_ALint_ALbyte3(ALbyte3 val) -{ return DecodeByte3(val)<<8; } -static inline ALint Conv_ALint_ALubyte3(ALubyte3 val) -{ return (DecodeUByte3(val)-8388608)<<8; } - -static inline ALuint Conv_ALuint_ALbyte(ALbyte val) -{ return (val+128)<<24; } -static inline ALuint Conv_ALuint_ALubyte(ALubyte val) -{ return val<<24; } -static inline ALuint Conv_ALuint_ALshort(ALshort val) -{ return (val+32768)<<16; } -static inline ALuint Conv_ALuint_ALushort(ALushort val) -{ return val<<16; } -static inline ALuint Conv_ALuint_ALint(ALint val) -{ return val+2147483648u; } -static inline ALuint Conv_ALuint_ALuint(ALuint val) -{ return val; } -static inline ALuint Conv_ALuint_ALfloat(ALfloat val) -{ - if(val > 1.0f) return 4294967295u; - if(val < -1.0f) return 0; - return ((ALint)(val*16777215.0f)<<7) + 2147483648u; -} -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) -{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); } -static inline ALuint Conv_ALuint_ALalaw(ALalaw val) -{ return Conv_ALuint_ALshort(DecodeALaw(val)); } -static inline ALuint Conv_ALuint_ALbyte3(ALbyte3 val) -{ return (DecodeByte3(val)+8388608)<<8; } -static inline ALuint Conv_ALuint_ALubyte3(ALubyte3 val) -{ return DecodeUByte3(val)<<8; } - -static inline ALfloat Conv_ALfloat_ALbyte(ALbyte val) -{ return val * (1.0f/127.0f); } -static inline ALfloat Conv_ALfloat_ALubyte(ALubyte val) -{ return (val-128) * (1.0f/127.0f); } -static inline ALfloat Conv_ALfloat_ALshort(ALshort val) -{ return val * (1.0f/32767.0f); } -static inline ALfloat Conv_ALfloat_ALushort(ALushort val) -{ return (val-32768) * (1.0f/32767.0f); } -static inline ALfloat Conv_ALfloat_ALint(ALint val) -{ return (ALfloat)(val>>7) * (1.0f/16777215.0f); } -static inline ALfloat Conv_ALfloat_ALuint(ALuint val) -{ return (ALfloat)((ALint)(val>>7)-16777216) * (1.0f/16777215.0f); } +/* Define same-type pass-through sample conversion functions (excludes ADPCM, + * which are block-based). */ +#define DECL_TEMPLATE(T) \ +static inline T Conv_##T##_##T(T val) { return val; } + +DECL_TEMPLATE(ALbyte); +DECL_TEMPLATE(ALubyte); +DECL_TEMPLATE(ALshort); +DECL_TEMPLATE(ALushort); +DECL_TEMPLATE(ALint); +DECL_TEMPLATE(ALuint); +DECL_TEMPLATE(ALbyte3); +DECL_TEMPLATE(ALubyte3); +DECL_TEMPLATE(ALalaw); +DECL_TEMPLATE(ALmulaw); + +/* Slightly special handling for floats and doubles (converts NaN to 0, and + * allows float<->double pass-through). + */ static inline ALfloat Conv_ALfloat_ALfloat(ALfloat val) { return (val==val) ? val : 0.0f; } static inline ALfloat Conv_ALfloat_ALdouble(ALdouble val) { return (val==val) ? (ALfloat)val : 0.0f; } -static inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val) -{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); } -static inline ALfloat Conv_ALfloat_ALalaw(ALalaw val) -{ return Conv_ALfloat_ALshort(DecodeALaw(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) -{ return (ALfloat)((DecodeUByte3(val)-8388608) * (1.0/8388607.0)); } - -static inline ALdouble Conv_ALdouble_ALbyte(ALbyte val) -{ return val * (1.0/127.0); } -static inline ALdouble Conv_ALdouble_ALubyte(ALubyte val) -{ return (val-128) * (1.0/127.0); } -static inline ALdouble Conv_ALdouble_ALshort(ALshort val) -{ return val * (1.0/32767.0); } -static inline ALdouble Conv_ALdouble_ALushort(ALushort val) -{ return (val-32768) * (1.0/32767.0); } -static inline ALdouble Conv_ALdouble_ALint(ALint val) -{ return val * (1.0/2147483647.0); } -static inline ALdouble Conv_ALdouble_ALuint(ALuint val) -{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); } static inline ALdouble Conv_ALdouble_ALfloat(ALfloat val) -{ return (val==val) ? val : 0.0f; } +{ return (val==val) ? (ALdouble)val : 0.0; } static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val) { return (val==val) ? val : 0.0; } -static inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val) -{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); } -static inline ALdouble Conv_ALdouble_ALalaw(ALalaw val) -{ return Conv_ALdouble_ALshort(DecodeALaw(val)); } -static inline ALdouble Conv_ALdouble_ALbyte3(ALbyte3 val) -{ return DecodeByte3(val) * (1.0/8388607.0); } -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) \ -{ return EncodeMuLaw(Conv_ALshort_##T(val)); } +#undef DECL_TEMPLATE -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -static inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val) -{ return val; } -DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) +/* Define alternate-sign functions. */ +#define DECL_TEMPLATE(T1, T2, O) \ +static inline T1 Conv_##T1##_##T2(T2 val) { return (T1)val - O; } \ +static inline T2 Conv_##T2##_##T1(T1 val) { return (T2)val + O; } + +DECL_TEMPLATE(ALbyte, ALubyte, 128); +DECL_TEMPLATE(ALshort, ALushort, 32768); +DECL_TEMPLATE(ALint, ALuint, 2147483648u); #undef DECL_TEMPLATE -#define DECL_TEMPLATE(T) \ -static inline ALalaw Conv_ALalaw_##T(T val) \ -{ return EncodeALaw(Conv_ALshort_##T(val)); } +/* Define int-type to int-type functions */ +#define DECL_TEMPLATE(T, ST, UT, SH) \ +static inline T Conv_##T##_##ST(ST val){ return val >> SH; } \ +static inline T Conv_##T##_##UT(UT val){ return Conv_##ST##_##UT(val) >> SH; }\ +static inline ST Conv_##ST##_##T(T val){ return val << SH; } \ +static inline UT Conv_##UT##_##T(T val){ return Conv_##UT##_##ST(val << SH); } -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -static inline ALalaw Conv_ALalaw_ALalaw(ALalaw val) -{ return val; } -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) +#define DECL_TEMPLATE2(T1, T2, SH) \ +DECL_TEMPLATE(AL##T1, AL##T2, ALu##T2, SH) \ +DECL_TEMPLATE(ALu##T1, ALu##T2, AL##T2, SH) + +DECL_TEMPLATE2(byte, short, 8) +DECL_TEMPLATE2(short, int, 16) +DECL_TEMPLATE2(byte, int, 24) +#undef DECL_TEMPLATE2 #undef DECL_TEMPLATE -#define DECL_TEMPLATE(T) \ -static inline ALbyte3 Conv_ALbyte3_##T(T val) \ -{ return EncodeByte3(Conv_ALint_##T(val)>>8); } +/* Define int-type to fp functions */ +#define DECL_TEMPLATE(T, ST, UT, OP) \ +static inline T Conv_##T##_##ST(ST val) { return (T)val * OP; } \ +static inline T Conv_##T##_##UT(UT val) { return (T)Conv_##ST##_##UT(val) * OP; } + +#define DECL_TEMPLATE2(T1, T2, OP) \ +DECL_TEMPLATE(T1, AL##T2, ALu##T2, OP) + +DECL_TEMPLATE2(ALfloat, byte, (1.0f/127.0f)) +DECL_TEMPLATE2(ALdouble, byte, (1.0/127.0)) +DECL_TEMPLATE2(ALfloat, short, (1.0f/32767.0f)) +DECL_TEMPLATE2(ALdouble, short, (1.0/32767.0)) +DECL_TEMPLATE2(ALdouble, int, (1.0/2147483647.0)) + +/* Special handling for int32 to float32, since it would overflow. */ +static inline ALfloat Conv_ALfloat_ALint(ALint val) +{ return (ALfloat)(val>>7) * (1.0f/16777215.0f); } +static inline ALfloat Conv_ALfloat_ALuint(ALuint val) +{ return (ALfloat)(Conv_ALint_ALuint(val)>>7) * (1.0f/16777215.0f); } + +#undef DECL_TEMPLATE2 +#undef DECL_TEMPLATE + +/* Define fp to int-type functions */ +#define DECL_TEMPLATE(FT, T, smin, smax) \ +static inline AL##T Conv_AL##T##_##FT(FT val) \ +{ \ + if(val > 1.0f) return smax; \ + if(val < -1.0f) return smin; \ + return (AL##T)(val * (FT)smax); \ +} \ +static inline ALu##T Conv_ALu##T##_##FT(FT val) \ +{ return Conv_ALu##T##_AL##T(Conv_AL##T##_##FT(val)); } + +DECL_TEMPLATE(ALfloat, byte, -128, 127) +DECL_TEMPLATE(ALdouble, byte, -128, 127) +DECL_TEMPLATE(ALfloat, short, -32768, 32767) +DECL_TEMPLATE(ALdouble, short, -32768, 32767) +DECL_TEMPLATE(ALdouble, int, -2147483647-1, 2147483647) + +/* Special handling for float32 to int32, since it would overflow. */ +static inline ALint Conv_ALint_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 2147483647; + if(val < -1.0f) return -2147483647-1; + return (ALint)(val * 16777215.0f) << 7; +} +static inline ALuint Conv_ALuint_ALfloat(ALfloat val) +{ return Conv_ALuint_ALint(Conv_ALint_ALfloat(val)); } + +#undef DECL_TEMPLATE + +/* Define byte3 and ubyte3 functions (goes through int and uint functions). */ +#define DECL_TEMPLATE(T) \ +static inline ALbyte3 Conv_ALbyte3_##T(T val) \ +{ return EncodeByte3(Conv_ALint_##T(val)>>8); } \ +static inline T Conv_##T##_ALbyte3(ALbyte3 val) \ +{ return Conv_##T##_ALint(DecodeByte3(val)<<8); } \ + \ +static inline ALubyte3 Conv_ALubyte3_##T(T val) \ +{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); } \ +static inline T Conv_##T##_ALubyte3(ALubyte3 val) \ +{ return Conv_##T##_ALuint(DecodeUByte3(val)<<8); } DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) @@ -841,17 +672,26 @@ DECL_TEMPLATE(ALint) DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) -static inline ALbyte3 Conv_ALbyte3_ALbyte3(ALbyte3 val) -{ return val; } -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE +/* Define byte3 <-> ubyte3 functions. */ +static inline ALbyte3 Conv_ALbyte3_ALubyte3(ALubyte3 val) +{ return EncodeByte3(DecodeUByte3(val)-8388608); } +static inline ALubyte3 Conv_ALubyte3_ALbyte3(ALbyte3 val) +{ return EncodeUByte3(DecodeByte3(val)+8388608); } + +/* Define muLaw and aLaw functions (goes through short functions). */ #define DECL_TEMPLATE(T) \ -static inline ALubyte3 Conv_ALubyte3_##T(T val) \ -{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); } +static inline ALmulaw Conv_ALmulaw_##T(T val) \ +{ return EncodeMuLaw(Conv_ALshort_##T(val)); } \ +static inline T Conv_##T##_ALmulaw(ALmulaw val) \ +{ return Conv_##T##_ALshort(DecodeMuLaw(val)); } \ + \ +static inline ALalaw Conv_ALalaw_##T(T val) \ +{ return EncodeALaw(Conv_ALshort_##T(val)); } \ +static inline T Conv_##T##_ALalaw(ALalaw val) \ +{ return Conv_##T##_ALshort(DecodeALaw(val)); } DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) @@ -861,14 +701,17 @@ DECL_TEMPLATE(ALint) DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) DECL_TEMPLATE(ALbyte3) -static inline ALubyte3 Conv_ALubyte3_ALubyte3(ALubyte3 val) -{ return val; } +DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE +/* Define muLaw <-> aLaw functions. */ +static inline ALalaw Conv_ALalaw_ALmulaw(ALmulaw val) +{ return EncodeALaw(DecodeMuLaw(val)); } +static inline ALmulaw Conv_ALmulaw_ALalaw(ALalaw val) +{ return EncodeMuLaw(DecodeALaw(val)); } + #define DECL_TEMPLATE(T1, T2) \ static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint numchans, \ -- cgit v1.2.3 From 6fb634c3e12fffca56aed9417a1c8233c67839ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Aug 2016 09:26:57 -0700 Subject: Remove unnecessary consts They were causing GCC's built-in atomic cmpxchg to complain. --- OpenAL32/alAuxEffectSlot.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 479646b1..b860b2b0 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -42,7 +42,7 @@ extern inline void UnlockEffectSlotsWrite(ALCcontext *context); extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); -static void RemoveEffectSlotList(ALCcontext *Context, const ALeffectslot *slot); +static void RemoveEffectSlotList(ALCcontext *Context, ALeffectslot *slot); static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) @@ -430,16 +430,16 @@ done: } -static void RemoveEffectSlotList(ALCcontext *context, const ALeffectslot *slot) +static void RemoveEffectSlotList(ALCcontext *context, ALeffectslot *slot) { ALCdevice *device = context->Device; - const ALeffectslot *root, *next; + ALeffectslot *root, *next; root = slot; next = ATOMIC_LOAD(&slot->next); if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &context->ActiveAuxSlotList, &root, next)) { - const ALeffectslot *cur; + ALeffectslot *cur; do { cur = root; root = slot; -- cgit v1.2.3 From 7428636071f0977f7479ed5a03b5786c64850105 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Sep 2016 07:08:52 -0700 Subject: Use MixMatrixRow to upsample the split frequency bands to the output --- Alc/bformatdec.c | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 20e19bb6..70a6b3fd 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -584,7 +584,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) { - ALuint in, i, j, k; + ALuint i, j; /* This up-sampler is very simplistic. It essentially decodes the first- * order content to a square channel array (or cube if height is desired), @@ -593,29 +593,20 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B * channel to the output, without the need for storing the virtual channel * array. */ - for(in = 0;in < InChannels;in++) + for(i = 0;i < InChannels;i++) { /* First, split the first-order components into low and high frequency * bands. */ - bandsplit_process(&dec->UpSampler.XOver[in], + bandsplit_process(&dec->UpSampler.XOver[i], dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq], - InSamples[in], SamplesToDo + InSamples[i], SamplesToDo ); /* Now write each band to the output. */ for(j = 0;j < dec->NumChannels;j++) - { - for(k = 0;k < FB_Max;k++) - { - ALfloat gain = dec->UpSampler.Gains[in][j][k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < SamplesToDo;i++) - OutBuffer[j][i] += dec->Samples[k][i] * gain; - } - } + MixMatrixRow(OutBuffer[j], dec->UpSampler.Gains[i][j], + dec->Samples, FB_Max, SamplesToDo); } } @@ -668,26 +659,17 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { - ALuint in, i, j, k; + ALuint i, j; - for(in = 0;in < 4;in++) + for(i = 0;i < 4;i++) { - bandsplit_process(&ambiup->XOver[in], + bandsplit_process(&ambiup->XOver[i], ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq], - InSamples[in], SamplesToDo + InSamples[i], SamplesToDo ); for(j = 0;j < OutChannels;j++) - { - for(k = 0;k < FB_Max;k++) - { - ALfloat gain = ambiup->Gains[in][j][k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < SamplesToDo;i++) - OutBuffer[j][i] += ambiup->Samples[k][i] * gain; - } - } + MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j], + ambiup->Samples, FB_Max, SamplesToDo); } } -- cgit v1.2.3 From 17636a0c1c6cc7916d2b3f659b5a701266bcab36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Sep 2016 21:05:24 -0700 Subject: Calculate a variable closer to where it's used --- Alc/hrtf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d189ad35..19829034 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -691,11 +691,6 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) const char *ext; int i; - name = strrchr(al_string_get_cstr(*filename), '/'); - if(!name) name = strrchr(al_string_get_cstr(*filename), '\\'); - if(!name) name = al_string_get_cstr(*filename); - else ++name; - #define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); if(iter != VECTOR_END(*list)) @@ -759,6 +754,11 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ + name = strrchr(al_string_get_cstr(*filename), '/'); + if(!name) name = strrchr(al_string_get_cstr(*filename), '\\'); + if(!name) name = al_string_get_cstr(*filename); + else ++name; + ext = strrchr(name, '.'); i = 0; -- cgit v1.2.3 From cf0ef500ec6e999e744d4ad54e26e0c74c8c53b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Sep 2016 00:29:46 -0700 Subject: Rename MatrixMixerFunc to RowMixerFunc --- Alc/bformatdec.c | 4 ++-- Alc/mixer_c.c | 4 ++-- Alc/mixer_defs.h | 6 +++--- Alc/mixer_neon.c | 4 ++-- Alc/mixer_sse.c | 4 ++-- OpenAL32/Include/alu.h | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 70a6b3fd..180170d9 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -159,7 +159,7 @@ static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; -static inline MatrixMixerFunc SelectMixer(void) +static inline RowMixerFunc SelectMixer(void) { #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) @@ -172,7 +172,7 @@ static inline MatrixMixerFunc SelectMixer(void) return MixRow_C; } -static MatrixMixerFunc MixMatrixRow = MixRow_C; +static RowMixerFunc MixMatrixRow = MixRow_C; static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index c79d6061..c74729a8 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -208,13 +208,13 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B * transform. And as the matrices are more or less static once set up, no * stepping is necessary. */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) { ALuint c, i; for(c = 0;c < InChans;c++) { - ALfloat gain = Mtx[c]; + ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index be88379b..1572ac36 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -31,7 +31,7 @@ void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALu ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize); /* SSE mixers */ @@ -45,7 +45,7 @@ void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, A ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize); /* SSE resamplers */ @@ -92,7 +92,7 @@ void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index fcd0387a..73395aeb 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -144,7 +144,7 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer } } -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) { float32x4_t gain4; ALuint c; @@ -152,7 +152,7 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data for(c = 0;c < InChans;c++) { ALuint pos = 0; - ALfloat gain = Mtx[c]; + ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 6914e500..1ac78f9c 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -262,7 +262,7 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) } } -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) { __m128 gain4; ALuint c; @@ -270,7 +270,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Mtx, ALfloat (*restrict data) for(c = 0;c < InChans;c++) { ALuint pos = 0; - ALfloat gain = Mtx[c]; + ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 70ce7059..9a92dc50 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -160,9 +160,9 @@ typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -typedef void (*MatrixMixerFunc)(ALfloat *OutBuffer, const ALfloat *Mtx, - ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint BufferSize); +typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, + ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint BufferSize); typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const MixHrtfParams *hrtfparams, -- cgit v1.2.3 From 42452b7f796a317a8d1159d16c5b84f8defd5e80 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Sep 2016 00:38:41 -0700 Subject: Correct a comment about B-Format conversion --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index fc49c60f..d50582ad 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -540,7 +540,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * aluCrossproduct(N, V, U); aluNormalize(U); - /* Build a rotate + conversion matrix (B-Format -> N3D). */ + /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). */ scale = 1.732050808f; aluMatrixfSet(&matrix, 1.414213562f, 0.0f, 0.0f, 0.0f, -- cgit v1.2.3 From 8a64f071213f387c4675012ec1df51b9295564b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Sep 2016 02:02:14 -0700 Subject: Use a predefined identity matrix --- Alc/ALu.c | 7 +++++++ Alc/effects/compressor.c | 12 ++---------- Alc/effects/equalizer.c | 12 ++---------- Alc/effects/modulator.c | 12 ++---------- OpenAL32/Include/alu.h | 1 + 5 files changed, 14 insertions(+), 30 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d50582ad..f93781df 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -93,6 +93,13 @@ extern inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); +const aluMatrixf IdentityMatrixf = {{ + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +}}; + static inline HrtfDirectMixerFunc SelectHrtfMixer(void) { diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 1426ea70..ab0a4216 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -78,23 +78,15 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props) { - aluMatrixf matrix; ALuint i; state->Enabled = props->Compressor.OnOff; - aluMatrixfSet(&matrix, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain, - state->Gain[i]); + ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i], + slot->Params.Gain, state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 2b59cb37..61932ffb 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -126,21 +126,13 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * { ALfloat frequency = (ALfloat)device->Frequency; ALfloat gain, freq_mult; - aluMatrixf matrix; ALuint i; - aluMatrixfSet(&matrix, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->FOAOut, matrix.m[i], slot->Params.Gain, - state->Gain[i]); + ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i], + slot->Params.Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 08f3d5eb..5ca37f4f 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -117,7 +117,6 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { - aluMatrixf matrix; ALfloat cw, a; ALuint i; @@ -146,18 +145,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter[i].process = ALfilterState_processC; } - aluMatrixfSet(&matrix, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, matrix.m[i], Slot->Params.Gain, - state->Gain[i]); + ComputeFirstOrderGains(Device->FOAOut, IdentityMatrixf.m[i], + Slot->Params.Gain, state->Gain[i]); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 9a92dc50..d236c58b 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -79,6 +79,7 @@ inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALf typedef union aluMatrixf { alignas(16) ALfloat m[4][4]; } aluMatrixf; +const aluMatrixf IdentityMatrixf; inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) -- cgit v1.2.3 From a20576bbd747bdcfef2a7e6b09e9ba3039185ae5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Sep 2016 05:30:27 -0700 Subject: Do multiple samples at once for reverb modulation --- Alc/effects/reverb.c | 87 +++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0ffff585..3bdf9b91 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1080,43 +1080,52 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) Delay->Line[offset&Delay->Mask] = in; } -// Given an input sample, this function produces modulation for the late +// Given some input samples, this function produces modulation for the late // reverb. -static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat in) +static void EAXModulation(ALreverbState *State, ALuint offset, ALfloat*restrict dst, const ALfloat*restrict src, ALuint todo) { ALfloat sinus, frac, fdelay; ALfloat out0, out1; - ALuint delay; + ALuint delay, i; - // 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_TAU * State->Mod.Index / State->Mod.Range); + for(i = 0;i < todo;i++) + { + /* 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_TAU * State->Mod.Index / State->Mod.Range); - // Step the modulation index forward, keeping it bound to its range. - State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + /* Step the modulation index forward, keeping it bound to its range. */ + State->Mod.Index = (State->Mod.Index + 1) % 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 - // small parameter changes. - State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, - State->Mod.Coeff); + /* 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 + * small parameter changes. + */ + State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, + State->Mod.Coeff); - // Calculate the read offset and fraction between it and the next sample. - frac = modff(State->Mod.Filter*sinus, &fdelay); - delay = fastf2u(fdelay); + /* Calculate the read offset and fraction between it and the next + * sample. + */ + frac = modff(State->Mod.Filter*sinus, &fdelay); + delay = fastf2u(fdelay); - /* Add the incoming sample to the delay line first, so a 0 delay gets the - * incoming sample. - */ - DelayLineIn(&State->Mod.Delay, offset, in); - /* Get the two samples crossed by the offset delay */ - out0 = DelayLineOut(&State->Mod.Delay, offset - delay); - out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); - - // The output is obtained by linearly interpolating the two samples that - // were acquired above. - return lerp(out0, out1, frac); + /* Add the incoming sample to the delay line first, so a 0 delay gets + * the incoming sample. + */ + DelayLineIn(&State->Mod.Delay, offset, src[i]); + /* Get the two samples crossed by the offset delay */ + out0 = DelayLineOut(&State->Mod.Delay, offset - delay); + out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); + offset++; + + /* The output is obtained by linearly interpolating the two samples + * that were acquired above. + */ + dst[i] = lerp(out0, out1, frac); + } } // Given some input sample, this function produces four-channel outputs for the @@ -1371,18 +1380,20 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa // Band-pass and modulate the incoming samples (use the early buffer as temp storage). ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); - ALfilterState_process(&State->HpFilter, &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo); + ALfilterState_process(&State->HpFilter, + &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo + ); + // Perform any modulation on the input. + EAXModulation(State, State->Offset, + &early[MAX_UPDATE_SAMPLES*2/4][0], &early[MAX_UPDATE_SAMPLES/4][0], + todo + ); + // Feed the initial delay line. for(i = 0;i < todo;i++) - { - ALfloat sample = early[(MAX_UPDATE_SAMPLES/4)+(i>>2)][i&3]; - - // Perform any modulation on the input. - sample = EAXModulation(State, State->Offset+i, sample); - - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset+i, sample); - } + DelayLineIn(&State->Delay, State->Offset+i, + early[(MAX_UPDATE_SAMPLES*2/4)+(i>>2)][i&3] + ); // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); -- cgit v1.2.3 From 564030ffa4f8507efc64d468942012e12519e05e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Sep 2016 10:33:52 -0700 Subject: Use more correct cube decoder matrices --- Alc/bformatdec.c | 16 ++++++++-------- Alc/hrtf.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 180170d9..29207338 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -147,14 +147,14 @@ static const ALfloat CubePoints[8][3] = { { 0.577350269f, -0.577350269f, 0.577350269f }, }; static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { - { { 0.25f, 0.14425f, 0.14425f, 0.14425f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, - { { 0.25f, -0.14425f, 0.14425f, 0.14425f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, - { { 0.25f, 0.14425f, 0.14425f, -0.14425f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, - { { 0.25f, -0.14425f, 0.14425f, -0.14425f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, - { { 0.25f, 0.14425f, -0.14425f, 0.14425f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, - { { 0.25f, -0.14425f, -0.14425f, 0.14425f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, - { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, - { { 0.25f, -0.14425f, -0.14425f, -0.14425f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, + { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, + { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, + { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, + { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, + { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, + { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, + { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, + { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 19829034..16db0c33 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -189,14 +189,14 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, }; static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = { - { { 0.25f, 0.14425f, 0.14425f, 0.14425f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, - { { 0.25f, -0.14425f, 0.14425f, 0.14425f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, - { { 0.25f, 0.14425f, 0.14425f, -0.14425f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, - { { 0.25f, -0.14425f, 0.14425f, -0.14425f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, - { { 0.25f, 0.14425f, -0.14425f, 0.14425f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, - { { 0.25f, -0.14425f, -0.14425f, 0.14425f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, - { { 0.25f, 0.14425f, -0.14425f, -0.14425f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, - { { 0.25f, -0.14425f, -0.14425f, -0.14425f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, + { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, + { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, + { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, + { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, + { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, + { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, + { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, + { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the -- cgit v1.2.3 From b1f70b5b786e7f00d104ba96bc9c4812c57f5793 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 03:10:38 -0700 Subject: Rename some variables for clarity --- Alc/bformatdec.c | 58 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 29207338..056eb7f5 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -122,21 +122,23 @@ enum FreqBand { FB_Max }; -static const ALfloat SquarePoints[4][3] = { +/* These points are in AL coordinates! */ +static const ALfloat Ambi2DPoints[4][3] = { { -0.707106781f, 0.0f, -0.707106781f }, { 0.707106781f, 0.0f, -0.707106781f }, { -0.707106781f, 0.0f, 0.707106781f }, { 0.707106781f, 0.0f, 0.707106781f }, }; -static const ALfloat SquareMatrix[4][FB_Max][MAX_AMBI_COEFFS] = { +static const ALfloat Ambi2DDecoder[4][FB_Max][MAX_AMBI_COEFFS] = { { { 0.353553f, 0.204094f, 0.0f, 0.204094f }, { 0.25f, 0.204094f, 0.0f, 0.204094f } }, { { 0.353553f, -0.204094f, 0.0f, 0.204094f }, { 0.25f, -0.204094f, 0.0f, 0.204094f } }, { { 0.353553f, 0.204094f, 0.0f, -0.204094f }, { 0.25f, 0.204094f, 0.0f, -0.204094f } }, { { 0.353553f, -0.204094f, 0.0f, -0.204094f }, { 0.25f, -0.204094f, 0.0f, -0.204094f } }, }; -static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS]; +static ALfloat Ambi2DEncoder[4][MAX_AMBI_COEFFS]; -static const ALfloat CubePoints[8][3] = { +/* These points are in AL coordinates! */ +static const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, 0.577350269f, -0.577350269f }, { 0.577350269f, 0.577350269f, -0.577350269f }, { -0.577350269f, 0.577350269f, 0.577350269f }, @@ -146,7 +148,7 @@ static const ALfloat CubePoints[8][3] = { { -0.577350269f, -0.577350269f, 0.577350269f }, { 0.577350269f, -0.577350269f, 0.577350269f }, }; -static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { +static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, @@ -156,7 +158,7 @@ static const ALfloat CubeMatrix[8][FB_Max][MAX_AMBI_COEFFS] = { { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; -static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS]; +static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS]; static inline RowMixerFunc SelectMixer(void) @@ -183,21 +185,21 @@ static void init_bformatdec(void) MixMatrixRow = SelectMixer(); - for(i = 0;i < COUNTOF(CubePoints);i++) - CalcDirectionCoeffs(CubePoints[i], 0.0f, CubeEncoder[i]); + for(i = 0;i < COUNTOF(Ambi3DPoints);i++) + CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoder[i]); - for(i = 0;i < COUNTOF(SquarePoints);i++) - CalcDirectionCoeffs(SquarePoints[i], 0.0f, SquareEncoder[i]); - for(i = 0;i < COUNTOF(SquarePoints);i++) + for(i = 0;i < COUNTOF(Ambi2DPoints);i++) { + CalcDirectionCoeffs(Ambi2DPoints[i], 0.0f, Ambi2DEncoder[i]); + /* Remove the skipped height-related coefficients for 2D rendering. */ - SquareEncoder[i][2] = SquareEncoder[i][3]; - SquareEncoder[i][3] = SquareEncoder[i][4]; - SquareEncoder[i][4] = SquareEncoder[i][8]; - SquareEncoder[i][5] = SquareEncoder[i][9]; - SquareEncoder[i][6] = SquareEncoder[i][15]; + Ambi2DEncoder[i][2] = Ambi2DEncoder[i][3]; + Ambi2DEncoder[i][3] = Ambi2DEncoder[i][4]; + Ambi2DEncoder[i][4] = Ambi2DEncoder[i][8]; + Ambi2DEncoder[i][5] = Ambi2DEncoder[i][9]; + Ambi2DEncoder[i][6] = Ambi2DEncoder[i][15]; for(j = 7;j < MAX_AMBI_COEFFS;j++) - SquareEncoder[i][j] = 0.0f; + Ambi2DEncoder[i][j] = 0.0f; } } @@ -319,10 +321,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, for(j = 0;j < dec->NumChannels;j++) { ALfloat *gains = dec->UpSampler.Gains[i][j]; - for(k = 0;k < COUNTOF(CubeMatrix);k++) + for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) { - gains[FB_HighFreq] += CubeMatrix[k][FB_HighFreq][i]*CubeEncoder[k][j]; - gains[FB_LowFreq] += CubeMatrix[k][FB_LowFreq][i]*CubeEncoder[k][j]; + gains[FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*Ambi3DEncoder[k][j]; + gains[FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*Ambi3DEncoder[k][j]; } } } @@ -336,10 +338,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, for(j = 0;j < dec->NumChannels;j++) { ALfloat *gains = dec->UpSampler.Gains[i][j]; - for(k = 0;k < COUNTOF(SquareMatrix);k++) + for(k = 0;k < COUNTOF(Ambi2DDecoder);k++) { - gains[FB_HighFreq] += SquareMatrix[k][FB_HighFreq][i]*SquareEncoder[k][j]; - gains[FB_LowFreq] += SquareMatrix[k][FB_LowFreq][i]*SquareEncoder[k][j]; + gains[FB_HighFreq] += Ambi2DDecoder[k][FB_HighFreq][i]*Ambi2DEncoder[k][j]; + gains[FB_LowFreq] += Ambi2DDecoder[k][FB_LowFreq][i]*Ambi2DEncoder[k][j]; } } } @@ -640,18 +642,18 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) for(i = 0;i < 4;i++) bandsplit_init(&ambiup->XOver[i], ratio); - for(i = 0;i < COUNTOF(CubePoints);i++) - ComputePanningGains(device->Dry, CubeEncoder[i], 1.0f, gains[i]); + for(i = 0;i < COUNTOF(Ambi3DEncoder);i++) + ComputePanningGains(device->Dry, Ambi3DEncoder[i], 1.0f, gains[i]); memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); for(i = 0;i < 4;i++) { for(j = 0;j < device->Dry.NumChannels;j++) { - for(k = 0;k < COUNTOF(CubePoints);k++) + for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) { - ambiup->Gains[i][j][FB_HighFreq] += CubeMatrix[k][FB_HighFreq][i]*gains[k][j]; - ambiup->Gains[i][j][FB_LowFreq] += CubeMatrix[k][FB_LowFreq][i]*gains[k][j]; + ambiup->Gains[i][j][FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*gains[k][j]; + ambiup->Gains[i][j][FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*gains[k][j]; } } } -- cgit v1.2.3 From 1541ff24b87a3baee834fa8d8782d10eadb18c8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 07:02:17 -0700 Subject: Do reverb modulation before band-pass filtering Ideally the band-pass should probably happen closer to output, like gain is. However, doing that would require 16 filters (4 early + 4 late channels, each with a low-pass and high-pass filter), compared to the two needed to do it on input. --- Alc/effects/reverb.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 3bdf9b91..c10cd8f0 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1378,15 +1378,14 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa { ALuint i; - // Band-pass and modulate the incoming samples (use the early buffer as temp storage). - ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); - ALfilterState_process(&State->HpFilter, + /* Perform any modulation on the input (use the early buffer as temp storage). */ + EAXModulation(State, State->Offset, &early[0][0], input, todo); + /* Band-pass the incoming samples */ + ALfilterState_process(&State->LpFilter, &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo ); - // Perform any modulation on the input. - EAXModulation(State, State->Offset, - &early[MAX_UPDATE_SAMPLES*2/4][0], &early[MAX_UPDATE_SAMPLES/4][0], - todo + ALfilterState_process(&State->HpFilter, + &early[MAX_UPDATE_SAMPLES*2/4][0], &early[MAX_UPDATE_SAMPLES/4][0], todo ); // Feed the initial delay line. -- cgit v1.2.3 From a758cc82433ad4fd47aeac7e626dff4bd1fa739f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 09:09:25 -0700 Subject: Remove use of DECL_CONST No idea if it was really gaining us anything, but removing it fixes a crash I was getting with libs built with Clang. --- Alc/ALc.c | 8 ++++---- Alc/panning.c | 2 +- OpenAL32/Include/alBuffer.h | 8 ++++---- OpenAL32/Include/alMain.h | 10 ++++------ OpenAL32/alBuffer.c | 8 ++++---- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7759393b..c4eb0462 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1334,8 +1334,8 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) return 0; } -DECL_CONST static ALboolean DecomposeDevFormat(ALenum format, - enum DevFmtChannels *chans, enum DevFmtType *type) +static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans, + enum DevFmtType *type) { static const struct { ALenum format; @@ -1381,7 +1381,7 @@ DECL_CONST static ALboolean DecomposeDevFormat(ALenum format, return AL_FALSE; } -DECL_CONST static ALCboolean IsValidALCType(ALCenum type) +static ALCboolean IsValidALCType(ALCenum type) { switch(type) { @@ -1397,7 +1397,7 @@ DECL_CONST static ALCboolean IsValidALCType(ALCenum type) return ALC_FALSE; } -DECL_CONST static ALCboolean IsValidALCChannels(ALCenum channels) +static ALCboolean IsValidALCChannels(ALCenum channels) { switch(channels) { diff --git a/Alc/panning.c b/Alc/panning.c index 172861da..1162bbbc 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -290,7 +290,7 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, c } -DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) +static inline const char *GetLabelFromChannel(enum Channel channel) { switch(channel) { diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 351c81bc..e99af050 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -36,8 +36,8 @@ enum UserFmtChannels { UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */ }; -ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST; -ALuint ChannelsFromUserFmt(enum UserFmtChannels chans) DECL_CONST; +ALuint BytesFromUserFmt(enum UserFmtType type); +ALuint ChannelsFromUserFmt(enum UserFmtChannels chans); inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type) { return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); @@ -63,8 +63,8 @@ enum FmtChannels { }; #define MAX_INPUT_CHANNELS (8) -ALuint BytesFromFmt(enum FmtType type) DECL_CONST; -ALuint ChannelsFromFmt(enum FmtChannels chans) DECL_CONST; +ALuint BytesFromFmt(enum FmtType type); +ALuint ChannelsFromFmt(enum FmtChannels chans); inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) { return ChannelsFromFmt(chans) * BytesFromFmt(type); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c6b816d9..d7975cea 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -163,10 +163,8 @@ typedef ALuint64SOFT ALuint64; #endif #ifdef __GNUC__ -#define DECL_CONST __attribute__((const)) #define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) #else -#define DECL_CONST #define DECL_FORMAT(x, y, z) #endif @@ -467,8 +465,8 @@ enum DevFmtChannels { }; #define MAX_OUTPUT_CHANNELS (16) -ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST; -ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST; +ALuint BytesFromDevFmt(enum DevFmtType type); +ALuint ChannelsFromDevFmt(enum DevFmtChannels chans); inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type) { return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); @@ -842,8 +840,8 @@ void SetRTPriority(void); void SetDefaultChannelOrder(ALCdevice *device); void SetDefaultWFXChannelOrder(ALCdevice *device); -const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST; -const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST; +const ALCchar *DevFmtTypeString(enum DevFmtType type); +const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); /** * GetChannelIdxByName diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index f9093cb7..193cfeaa 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,10 +45,10 @@ 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 ALboolean IsValidType(ALenum type) DECL_CONST; -static ALboolean IsValidChannels(ALenum channels) DECL_CONST; -static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type) DECL_CONST; -static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type) DECL_CONST; +static ALboolean IsValidType(ALenum type); +static ALboolean IsValidChannels(ALenum channels); +static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); +static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type); static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align); -- cgit v1.2.3 From 0558869d942e60c18be4d68404f943e52949a71f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 11:07:45 -0700 Subject: Use deinterlaced buffers for the intermediate reverb storage --- Alc/effects/reverb.c | 256 +++++++++++++++++++++++++++------------------------ 1 file changed, 137 insertions(+), 119 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c10cd8f0..ef21e5fd 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -164,8 +164,8 @@ typedef struct ALreverbState { ALuint Offset; /* Temporary storage used when processing. */ - ALfloat ReverbSamples[MAX_UPDATE_SAMPLES][4]; - ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4]; + ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; + ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; } ALreverbState; static ALvoid ALreverbState_Destruct(ALreverbState *State); @@ -1130,7 +1130,7 @@ static void EAXModulation(ALreverbState *State, ALuint offset, ALfloat*restrict // Given some input sample, this function produces four-channel outputs for the // early reflections. -static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) +static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat d[4], v, f[4]; ALuint i; @@ -1175,10 +1175,10 @@ static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat /* Output the results of the junction for all four channels with a * constant attenuation of 0.5. */ - out[i][0] = f[0] * 0.5f; - out[i][1] = f[1] * 0.5f; - out[i][2] = f[2] * 0.5f; - out[i][3] = f[3] * 0.5f; + out[0][i] = f[0] * 0.5f; + out[1][i] = f[1] * 0.5f; + out[2][i] = f[2] * 0.5f; + out[3][i] = f[3] * 0.5f; } } @@ -1216,123 +1216,140 @@ static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALflo // Given four decorrelated input samples, this function produces four-channel // output for the late reverb. -static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) +static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat d[4], f[4]; - ALuint i; + ALuint offset; + ALuint base, i; // Feed the decorrelator from the energy-attenuated output of the second // delay tap. + offset = State->Offset; for(i = 0;i < todo;i++) { - ALuint offset = State->Offset+i; ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * State->Late.DensityGain; DelayLineIn(&State->Decorrelator, offset, sample); + offset++; } - for(i = 0;i < todo;i++) + offset = State->Offset; + for(base = 0;base < todo;) { - ALuint offset = State->Offset+i; + ALfloat tmp[MAX_UPDATE_SAMPLES/4][4]; + ALuint tmp_todo = minu(todo, MAX_UPDATE_SAMPLES/4); - /* Obtain four decorrelated input samples. */ - f[0] = DelayLineOut(&State->Decorrelator, offset); - f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); - f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); - f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); + for(i = 0;i < tmp_todo;i++) + { + /* Obtain four decorrelated input samples. */ + f[0] = DelayLineOut(&State->Decorrelator, offset); + f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); + f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); + f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); + + /* Add the decayed results of the cyclical delay lines, then pass + * the results through the low-pass filters. + */ + f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; + f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; + f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; + f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; + + /* This is where the feed-back cycles from line 0 to 1 to 3 to 2 + * and back to 0. + */ + d[0] = LateLowPassInOut(State, 2, f[2]); + d[1] = LateLowPassInOut(State, 0, f[0]); + d[2] = LateLowPassInOut(State, 3, f[3]); + d[3] = LateLowPassInOut(State, 1, f[1]); + + /* To help increase diffusion, run each line through an all-pass + * filter. When there is no diffusion, the shortest all-pass filter + * will feed the shortest delay line. + */ + d[0] = LateAllPassInOut(State, offset, 0, d[0]); + d[1] = LateAllPassInOut(State, offset, 1, d[1]); + d[2] = LateAllPassInOut(State, offset, 2, d[2]); + d[3] = LateAllPassInOut(State, offset, 3, d[3]); + + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. Each output feeds + * a different input to form a circlular feed cycle. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix + * derived using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is + * thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied + * with the cyclical delay line coefficients. Thus only the y + * coefficient is applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + + /* Re-feed the cyclical delay lines. */ + DelayLineIn(&State->Late.Delay[0], offset, f[0]); + DelayLineIn(&State->Late.Delay[1], offset, f[1]); + DelayLineIn(&State->Late.Delay[2], offset, f[2]); + DelayLineIn(&State->Late.Delay[3], offset, f[3]); + offset++; + + /* Output the results of the matrix for all four channels, + * attenuated by the late reverb gain (which is attenuated by the + * 'x' mix coefficient). + */ + tmp[i][0] = State->Late.Gain * f[0]; + tmp[i][1] = State->Late.Gain * f[1]; + tmp[i][2] = State->Late.Gain * f[2]; + tmp[i][3] = State->Late.Gain * f[3]; + } - /* Add the decayed results of the cyclical delay lines, then pass the - * results through the low-pass filters. - */ - f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; - f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; - f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; - f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; - - // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and - // back to 0. - d[0] = LateLowPassInOut(State, 2, f[2]); - d[1] = LateLowPassInOut(State, 0, f[0]); - d[2] = LateLowPassInOut(State, 3, f[3]); - d[3] = LateLowPassInOut(State, 1, f[1]); - - // To help increase diffusion, run each line through an all-pass filter. - // When there is no diffusion, the shortest all-pass filter will feed - // the shortest delay line. - d[0] = LateAllPassInOut(State, offset, 0, d[0]); - d[1] = LateAllPassInOut(State, offset, 1, d[1]); - d[2] = LateAllPassInOut(State, offset, 2, d[2]); - d[3] = LateAllPassInOut(State, offset, 3, d[3]); - - /* Late reverb is done with a modified feed-back delay network (FDN) - * topology. Four input lines are each fed through their own all-pass - * filter and then into the mixing matrix. The four outputs of the - * mixing matrix are then cycled back to the inputs. Each output feeds - * a different input to form a circlular feed cycle. - * - * The mixing matrix used is a 4D skew-symmetric rotation matrix - * derived using a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y - * with differing signs, and d is the coefficient x. The matrix is - * thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * To reduce the number of multiplies, the x coefficient is applied - * with the cyclical delay line coefficients. Thus only the y - * coefficient is applied when mixing, and is modified to be: y / x. - */ - f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); - f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); - f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); - f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); - - // Output the results of the matrix for all four channels, attenuated by - // the late reverb gain (which is attenuated by the 'x' mix coefficient). - out[i][0] = State->Late.Gain * f[0]; - out[i][1] = State->Late.Gain * f[1]; - out[i][2] = State->Late.Gain * f[2]; - out[i][3] = State->Late.Gain * f[3]; - - // Re-feed the cyclical delay lines. - DelayLineIn(&State->Late.Delay[0], offset, f[0]); - DelayLineIn(&State->Late.Delay[1], offset, f[1]); - DelayLineIn(&State->Late.Delay[2], offset, f[2]); - DelayLineIn(&State->Late.Delay[3], offset, f[3]); + /* Deinterlace to output */ + for(i = 0;i < tmp_todo;i++) out[0][base+i] = tmp[i][0]; + for(i = 0;i < tmp_todo;i++) out[1][base+i] = tmp[i][1]; + for(i = 0;i < tmp_todo;i++) out[2][base+i] = tmp[i][2]; + for(i = 0;i < tmp_todo;i++) out[3][base+i] = tmp[i][3]; + + base += tmp_todo; } } // Given an input sample, this function mixes echo into the four-channel late // reverb. -static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4]) +static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALfloat out, feed; + ALfloat out[MAX_UPDATE_SAMPLES]; + ALfloat feed; + ALuint offset; ALuint i; + offset = State->Offset; for(i = 0;i < todo;i++) { - ALuint offset = State->Offset+i; - // Get the latest attenuated echo sample for output. feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) * State->Echo.Coeff; - // Mix the output into the late reverb channels. - out = State->Echo.MixCoeff * feed; - late[i][0] += out; - late[i][1] += out; - late[i][2] += out; - late[i][3] += out; + // Write the output. + out[i] = State->Echo.MixCoeff * feed; // Mix the energy-attenuated input with the output and pass it through // the echo low-pass filter. @@ -1348,19 +1365,26 @@ static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restri // Feed the delay with the mixed and filtered sample. DelayLineIn(&State->Echo.Delay, offset, feed); + offset++; } + + // Mix the output into the late reverb channels. + for(i = 0;i < todo;i++) late[0][i] += out[i]; + for(i = 0;i < todo;i++) late[1][i] += out[i]; + for(i = 0;i < todo;i++) late[2][i] += out[i]; + for(i = 0;i < todo;i++) late[3][i] += out[i]; } // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) +static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALuint i; // Low-pass filter the incoming samples (use the early buffer as temp storage). ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, early[i>>2][i&3]); + DelayLineIn(&State->Delay, State->Offset+i, early[0][i]); // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); @@ -1374,25 +1398,19 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat * // Perform the EAX reverb pass on a given input sample, resulting in four- // channel output. -static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) +static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALuint i; /* Perform any modulation on the input (use the early buffer as temp storage). */ EAXModulation(State, State->Offset, &early[0][0], input, todo); /* Band-pass the incoming samples */ - ALfilterState_process(&State->LpFilter, - &early[MAX_UPDATE_SAMPLES/4][0], &early[0][0], todo - ); - ALfilterState_process(&State->HpFilter, - &early[MAX_UPDATE_SAMPLES*2/4][0], &early[MAX_UPDATE_SAMPLES/4][0], todo - ); + ALfilterState_process(&State->LpFilter, &early[1][0], &early[0][0], todo); + ALfilterState_process(&State->HpFilter, &early[2][0], &early[1][0], todo); // Feed the initial delay line. for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, - early[(MAX_UPDATE_SAMPLES*2/4)+(i>>2)][i&3] - ); + DelayLineIn(&State->Delay, State->Offset+i, early[2][i]); // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); @@ -1409,8 +1427,8 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - ALfloat (*restrict early)[4] = State->EarlySamples; - ALfloat (*restrict late)[4] = State->ReverbSamples; + ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; + ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; ALuint index, c, i, l; ALfloat gain; @@ -1429,13 +1447,13 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[i][l]; + SamplesOut[c][index+i] += gain*early[l][i]; } gain = State->Late.PanGain[l][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[i][l]; + SamplesOut[c][index+i] += gain*late[l][i]; } } for(c = 0;c < State->ExtraChannels;c++) @@ -1444,13 +1462,13 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*early[i][l]; + State->ExtraOut[c][index+i] += gain*early[l][i]; } gain = State->Late.PanGain[l][NumChannels+c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*late[i][l]; + State->ExtraOut[c][index+i] += gain*late[l][i]; } } } @@ -1461,8 +1479,8 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - ALfloat (*restrict early)[4] = State->EarlySamples; - ALfloat (*restrict late)[4] = State->ReverbSamples; + ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; + ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; ALuint index, c, i, l; ALfloat gain; @@ -1481,13 +1499,13 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[i][l]; + SamplesOut[c][index+i] += gain*early[l][i]; } gain = State->Late.PanGain[l][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[i][l]; + SamplesOut[c][index+i] += gain*late[l][i]; } } for(c = 0;c < State->ExtraChannels;c++) @@ -1496,13 +1514,13 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*early[i][l]; + State->ExtraOut[c][index+i] += gain*early[l][i]; } gain = State->Late.PanGain[l][NumChannels+c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*late[i][l]; + State->ExtraOut[c][index+i] += gain*late[l][i]; } } } -- cgit v1.2.3 From 9cbe02fd850b9ecc4a227c7553004ca3203a5ed0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 12:16:49 -0700 Subject: Use the optimized mixing functions for reverb output --- Alc/effects/reverb.c | 200 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 83 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ef21e5fd..bdb7ae73 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -30,12 +30,37 @@ #include "alEffect.h" #include "alFilter.h" #include "alError.h" +#include "mixer_defs.h" /* This is the maximum number of samples processed for each inner loop * iteration. */ #define MAX_UPDATE_SAMPLES 256 +static MixerFunc MixSamples = Mix_C; + +static inline MixerFunc SelectMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_SSE; +#endif +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_Neon; +#endif + + return Mix_C; +} + + +static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT; +static void init_mixfunc(void) +{ + MixSamples = SelectMixer(); +} + + typedef struct DelayLine { // The delay lines use sample lengths that are powers of 2 to allow the @@ -90,11 +115,8 @@ typedef struct ALreverbState { ALuint Offset[4]; // The gain for each output channel based on 3D panning. - // NOTE: With certain output modes, we may be rendering to the dry - // buffer and the "real" buffer. The two combined may be using more - // than the max output channels, so we need some extra for the real - // output too. - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2]; + ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; } Early; // Decorrelator delay line. @@ -132,8 +154,8 @@ typedef struct ALreverbState { ALfloat LpSample[4]; // The gain for each output channel based on 3D panning. - // NOTE: Add some extra in case (see note about early pan). - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS*2]; + ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; } Late; struct { @@ -164,8 +186,8 @@ typedef struct ALreverbState { ALuint Offset; /* Temporary storage used when processing. */ - ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; - ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; } ALreverbState; static ALvoid ALreverbState_Destruct(ALreverbState *State); @@ -1425,55 +1447,74 @@ static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloa State->Offset += todo; } +static void DoMix(const ALfloat *restrict src, ALfloat (*dst)[BUFFERSIZE], ALuint num_chans, + const ALfloat *restrict target_gains, ALfloat *restrict current_gains, + ALfloat delta, ALuint offset, ALuint total_rem, ALuint todo) +{ + MixGains gains[MAX_OUTPUT_CHANNELS]; + ALuint c; + + for(c = 0;c < num_chans;c++) + { + ALfloat diff; + gains[c].Target = target_gains[c]; + gains[c].Current = current_gains[c]; + diff = gains[c].Target - gains[c].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + gains[c].Step = diff * delta; + else + { + gains[c].Current = gains[c].Target; + gains[c].Step = 0.0f; + } + } + + MixSamples(src, num_chans, dst, gains, total_rem, offset, todo); + + for(c = 0;c < num_chans;c++) + current_gains[c] = gains[c].Current; +} + static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint index, c, i, l; - ALfloat gain; + ALuint base, c; /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;) + for(base = 0;base < SamplesToDo;) { - ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); + const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); + ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - VerbPass(State, todo, &SamplesIn[index], early, late); + VerbPass(State, todo, &SamplesIn[base], early, late); - for(l = 0;l < 4;l++) + for(c = 0;c < 4;c++) + { + DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], + State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo + ); + if(State->ExtraChannels > 0) + DoMix(early[c], SamplesOut, State->ExtraChannels, + State->Early.PanGain[c]+NumChannels, + State->Early.CurrentGain[c]+NumChannels, delta, base, + SamplesToDo-base, todo + ); + } + for(c = 0;c < 4;c++) { - for(c = 0;c < NumChannels;c++) - { - gain = State->Early.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[l][i]; - } - gain = State->Late.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[l][i]; - } - } - for(c = 0;c < State->ExtraChannels;c++) - { - gain = State->Early.PanGain[l][NumChannels+c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*early[l][i]; - } - gain = State->Late.PanGain[l][NumChannels+c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*late[l][i]; - } - } + DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], + State->Late.CurrentGain[c], delta, base, SamplesToDo, todo + ); + if(State->ExtraChannels > 0) + DoMix(late[c], SamplesOut, State->ExtraChannels, + State->Late.PanGain[c]+NumChannels, + State->Late.CurrentGain[c]+NumChannels, delta, base, + SamplesToDo-base, todo + ); } - index += todo; + base += todo; } } @@ -1481,51 +1522,42 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, { ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint index, c, i, l; - ALfloat gain; + ALuint base, c; /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;) + for(base = 0;base < SamplesToDo;) { - ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); + const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); + ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - EAXVerbPass(State, todo, &SamplesIn[index], early, late); + EAXVerbPass(State, todo, &SamplesIn[base], early, late); - for(l = 0;l < 4;l++) + for(c = 0;c < 4;c++) { - for(c = 0;c < NumChannels;c++) - { - gain = State->Early.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*early[l][i]; - } - gain = State->Late.PanGain[l][c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - SamplesOut[c][index+i] += gain*late[l][i]; - } - } - for(c = 0;c < State->ExtraChannels;c++) - { - gain = State->Early.PanGain[l][NumChannels+c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*early[l][i]; - } - gain = State->Late.PanGain[l][NumChannels+c]; - if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) - { - for(i = 0;i < todo;i++) - State->ExtraOut[c][index+i] += gain*late[l][i]; - } - } + DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], + State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo + ); + if(State->ExtraChannels > 0) + DoMix(early[c], SamplesOut, State->ExtraChannels, + State->Early.PanGain[c]+NumChannels, + State->Early.CurrentGain[c]+NumChannels, delta, base, + SamplesToDo-base, todo + ); + } + for(c = 0;c < 4;c++) + { + DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], + State->Late.CurrentGain[c], delta, base, SamplesToDo, todo + ); + if(State->ExtraChannels > 0) + DoMix(late[c], SamplesOut, State->ExtraChannels, + State->Late.PanGain[c]+NumChannels, + State->Late.CurrentGain[c]+NumChannels, delta, base, + SamplesToDo-base, todo + ); } - index += todo; + base += todo; } } @@ -1546,6 +1578,8 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f { ALreverbState *state; + alcall_once(&mixfunc_inited, init_mixfunc); + NEW_OBJ0(state, ALreverbState)(); if(!state) return NULL; -- cgit v1.2.3 From 6387933f8b7511b7b8078245511fc99525d8d0fd Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Tue, 6 Sep 2016 21:35:34 +0200 Subject: Use GNUInstallDirs to place the build artifacts properly CMake 2.8.5 added the GNUInstallDirs module, which provides various variables following the CMAKE_INSTALL_*DIR pattern to allow users a more flexible installation setup and to provide sensible defaults while respecting distribution specific install locations like lib64 for RPM based linux distributions or debian multiarch tuples. --- CMakeLists.txt | 51 ++++++++++++++++++++++---------------- utils/alsoft-config/CMakeLists.txt | 6 ++--- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8f15153..5a75db44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # CMake build file list for OpenAL -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5) PROJECT(OpenAL) @@ -24,6 +24,7 @@ INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckTypeSize) include(CheckFileOffsetBits) +include(GNUInstallDirs) SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) @@ -44,8 +45,14 @@ OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON) OPTION(ALSOFT_AMBDEC_PRESETS "Install AmbDec preset files" ON) OPTION(ALSOFT_INSTALL "Install headers and libraries" ON) +if(DEFINED SHARE_INSTALL_DIR) + message(WARNING "SHARE_INSTALL_DIR is deprecated. Use the variables provided by the GNUInstallDirs module instead") + set(CMAKE_INSTALL_DATADIR "${SHARE_INSTALL_DIR}") +endif() -set(SHARE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share" CACHE STRING "The share install dir") +if(DEFINED LIB_SUFFIX) + message(WARNING "LIB_SUFFIX is deprecated. Use the variables provided by the GNUInstallDirs module instead") +endif() IF(NOT WIN32) @@ -1204,9 +1211,9 @@ TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS}) IF(ALSOFT_INSTALL) # Add an install target here INSTALL(TARGETS ${LIBNAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) INSTALL(FILES include/AL/al.h include/AL/alc.h @@ -1214,10 +1221,10 @@ IF(ALSOFT_INSTALL) include/AL/efx.h include/AL/efx-creative.h include/AL/efx-presets.h - DESTINATION include/AL + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/AL ) INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc" - DESTINATION "lib${LIB_SUFFIX}/pkgconfig") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") ENDIF() @@ -1245,7 +1252,7 @@ endif() # Install alsoft.conf configuration file IF(ALSOFT_CONFIG) INSTALL(FILES alsoftrc.sample - DESTINATION ${SHARE_INSTALL_DIR}/openal + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal ) MESSAGE(STATUS "Installing sample configuration") MESSAGE(STATUS "") @@ -1255,7 +1262,7 @@ ENDIF() IF(ALSOFT_HRTF_DEFS) INSTALL(FILES hrtf/default-44100.mhr hrtf/default-48000.mhr - DESTINATION ${SHARE_INSTALL_DIR}/openal/hrtf + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/hrtf ) MESSAGE(STATUS "Installing HRTF definitions") MESSAGE(STATUS "") @@ -1269,7 +1276,7 @@ IF(ALSOFT_AMBDEC_PRESETS) presets/rectangle.ambdec presets/square.ambdec presets/presets.txt - DESTINATION ${SHARE_INSTALL_DIR}/openal/presets + DESTINATION ${CMAKE_INSTALL_DATADIR}/openal/presets ) MESSAGE(STATUS "Installing AmbDec presets") MESSAGE(STATUS "") @@ -1294,9 +1301,9 @@ IF(ALSOFT_UTILS) IF(ALSOFT_INSTALL) INSTALL(TARGETS openal-info makehrtf bsincgen - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() @@ -1317,9 +1324,9 @@ IF(ALSOFT_TESTS) IF(ALSOFT_INSTALL) INSTALL(TARGETS altonegen - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() @@ -1372,9 +1379,9 @@ IF(ALSOFT_EXAMPLES) IF(ALSOFT_INSTALL) INSTALL(TARGETS alstream alreverb allatency alloopback alhrtf - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() @@ -1411,9 +1418,9 @@ IF(ALSOFT_EXAMPLES) IF(ALSOFT_INSTALL) INSTALL(TARGETS alffplay - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() MESSAGE(STATUS "Building SDL and FFmpeg example programs") diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 99d68ad5..578273a5 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -23,8 +23,8 @@ if(QT4_FOUND) 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}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() -- cgit v1.2.3 From 3481cf6fbae3f49e9f6e60d7610459dad319e5d1 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Tue, 6 Sep 2016 21:35:34 +0200 Subject: Use GNUInstallDirs for generated pkg-config file Continuation of 6387933 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a75db44..f85fb14f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1118,9 +1118,9 @@ ENDIF() # Needed for openal.pc.in SET(prefix ${CMAKE_INSTALL_PREFIX}) SET(exec_prefix "\${prefix}") -SET(libdir "\${exec_prefix}/lib${LIB_SUFFIX}") -SET(bindir "\${exec_prefix}/bin") -SET(includedir "\${prefix}/include") +SET(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") +SET(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}") +SET(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") SET(PACKAGE_VERSION "${LIB_VERSION}") # End configuration -- cgit v1.2.3 From 27916ce3db023454a0295ee63ea196fbc246674c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 6 Sep 2016 22:19:14 +0200 Subject: Build NEON code with -mfpu=neon The ARM-specific NEON code needs to be built with -mfpu=neon to avoid build failures when a difference FPU is used by default by the compiler. Fixes issue #54. Signed-off-by: Thomas Petazzoni --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8f15153..d92bbb7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -767,6 +767,7 @@ IF(HAVE_ARM_NEON_H) SET(HAVE_NEON 1) SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_neon.c) SET(CPU_EXTS "${CPU_EXTS}, Neon") + SET_SOURCE_FILES_PROPERTIES(Alc/mixer_neon.c PROPERTIES COMPILE_FLAGS -mfpu=neon) ENDIF() ENDIF() IF(ALSOFT_REQUIRE_NEON AND NOT HAVE_NEON) -- cgit v1.2.3 From 1d9d1958db4b14da654a3bc3f362582829596c75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Sep 2016 13:21:11 -0700 Subject: Make the SelectMixer function sharable --- Alc/bformatdec.c | 4 ++-- Alc/effects/reverb.c | 16 +--------------- Alc/mixer.c | 18 +++++++++--------- OpenAL32/Include/alu.h | 2 ++ 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 056eb7f5..0722c061 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -161,7 +161,7 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS]; -static inline RowMixerFunc SelectMixer(void) +static inline RowMixerFunc SelectRowMixer(void) { #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) @@ -183,7 +183,7 @@ static void init_bformatdec(void) { ALuint i, j; - MixMatrixRow = SelectMixer(); + MixMatrixRow = SelectRowMixer(); for(i = 0;i < COUNTOF(Ambi3DPoints);i++) CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoder[i]); diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index bdb7ae73..ef25c076 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -37,22 +37,8 @@ * iteration. */ #define MAX_UPDATE_SAMPLES 256 -static MixerFunc MixSamples = Mix_C; - -static inline MixerFunc SelectMixer(void) -{ -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; -#endif -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_Neon; -#endif - - return Mix_C; -} +static MixerFunc MixSamples = Mix_C; static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT; static void init_mixfunc(void) diff --git a/Alc/mixer.c b/Alc/mixer.c index bbf70153..2736920e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -61,36 +61,36 @@ static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!"); static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!"); -static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; static MixerFunc MixSamples = Mix_C; +static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; static ResamplerFunc ResampleSamples = Resample_point32_C; -static inline HrtfMixerFunc SelectHrtfMixer(void) +MixerFunc SelectMixer(void) { #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_SSE; + return Mix_SSE; #endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_Neon; + return Mix_Neon; #endif - return MixHrtf_C; + return Mix_C; } -static inline MixerFunc SelectMixer(void) +static inline HrtfMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; + return MixHrtf_SSE; #endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_Neon; + return MixHrtf_Neon; #endif - return Mix_C; + return MixHrtf_C; } static inline ResamplerFunc SelectResampler(enum Resampler resampler) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index d236c58b..3d1a4986 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -264,6 +264,8 @@ enum HrtfRequestMode { void aluInitMixer(void); +MixerFunc SelectMixer(void); + /* aluInitRenderer * * Set up the appropriate panning method and mixing method given the device -- cgit v1.2.3 From 6b7e14f11f6eea9d77dcf6076fbecaffb1b6d1ab Mon Sep 17 00:00:00 2001 From: Dmytry Lavrov Date: Tue, 6 Sep 2016 19:22:42 -0500 Subject: mmdevapi: Allow specifying output device by it's audio endpoint GUID or by the device id string (Oculus VR api requires you to play back on a specific device). --- Alc/backends/mmdevapi.c | 53 +++++++++++++++++++++++++++++++++++++++++-------- Alc/helpers.c | 1 + 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index bcef0a5f..b444a341 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -52,6 +52,7 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) @@ -67,6 +68,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x typedef struct { al_string name; + al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. WCHAR *devid; } DevMap; TYPEDEF_VECTOR(DevMap, vector_DevMap) @@ -75,6 +77,7 @@ static void clear_devlist(vector_DevMap *list) { #define CLEAR_DEVMAP(i) do { \ AL_STRING_DEINIT((i)->name); \ + AL_STRING_DEINIT((i)->endpoint_guid); \ free((i)->devid); \ (i)->devid = NULL; \ } while(0) @@ -119,10 +122,11 @@ static HRESULT WaitForResponse(ThreadRequest *req) } -static void get_device_name(IMMDevice *device, al_string *name) +static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) { IPropertyStore *ps; PROPVARIANT pvname; + PROPVARIANT pvguid; HRESULT hr; al_string_copy_cstr(name, DEVNAME_HEAD); @@ -132,6 +136,7 @@ static void get_device_name(IMMDevice *device, al_string *name) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); al_string_append_cstr(name, "Unknown Device Name"); + if(guid!=NULL)al_string_copy_cstr(guid, "Unknown Device GUID"); return; } @@ -150,8 +155,28 @@ static void get_device_name(IMMDevice *device, al_string *name) WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); al_string_append_cstr(name, "Unknown Device Name"); } - PropVariantClear(&pvname); + + if(guid!=NULL){ + PropVariantInit(&pvguid); + + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pvguid); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + al_string_copy_cstr(guid, "Unknown Device GUID"); + } + else if(pvguid.vt == VT_LPWSTR) + al_string_copy_wcstr(guid, pvguid.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); + al_string_copy_cstr(guid, "Unknown Device GUID"); + } + + PropVariantClear(&pvguid); + } + IPropertyStore_Release(ps); } @@ -193,9 +218,10 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) AL_STRING_INIT(tmpname); AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.endpoint_guid); entry.devid = strdupW(devid); - get_device_name(device, &tmpname); + get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); while(1) { @@ -216,7 +242,7 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) count++; } - TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid); + TRACE("Got device \"%s\", %s, \"%ls\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.endpoint_guid), entry.devid); VECTOR_PUSH_BACK(*list, entry); AL_STRING_DEINIT(tmpname); @@ -663,6 +689,17 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX * return ALC_TRUE; } + static ALCboolean match_name_or_guid(const DevMap *iter, const ALCchar *deviceName){ + al_string tmp_id; + ALCboolean result; + result=AL_FALSE; + if (al_string_cmp_cstr(iter->name, deviceName) == 0 || al_string_cmp_cstr(iter->endpoint_guid, deviceName) == 0) return ALC_TRUE; + AL_STRING_INIT(tmp_id); + al_string_copy_wcstr(&tmp_id, iter->devid); + if(al_string_cmp_cstr(tmp_id, deviceName)==0)result=AL_TRUE; + AL_STRING_DEINIT(tmp_id); + return result; +} static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName) { @@ -690,7 +727,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi } hr = E_FAIL; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) +#define MATCH_NAME(i) (match_name_or_guid((i), (deviceName))==ALC_TRUE) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); if(iter == VECTOR_END(PlaybackDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); @@ -758,7 +795,7 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) { self->client = ptr; if(al_string_empty(device->DeviceName)) - get_device_name(self->mmdev, &device->DeviceName); + get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); } if(FAILED(hr)) @@ -1335,7 +1372,7 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device } hr = E_FAIL; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) +#define MATCH_NAME(i) (match_name_or_guid((i), (deviceName))==ALC_TRUE) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); if(iter == VECTOR_END(CaptureDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); @@ -1421,7 +1458,7 @@ static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) { self->client = ptr; if(al_string_empty(device->DeviceName)) - get_device_name(self->mmdev, &device->DeviceName); + get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); } if(FAILED(hr)) diff --git a/Alc/helpers.c b/Alc/helpers.c index 9d7d564f..9b6c7894 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -65,6 +65,7 @@ DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x1 #include DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); #endif #endif #endif /* AL_NO_UID_DEFS */ -- cgit v1.2.3 From 7973c5abf8f3097b795601c9619113d080792768 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Sep 2016 05:18:42 -0700 Subject: Use unsigned int shifts for device flags --- OpenAL32/Include/alMain.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d7975cea..ac537978 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -699,17 +699,17 @@ struct ALCdevice_struct }; // Frequency was requested by the app or config file -#define DEVICE_FREQUENCY_REQUEST (1<<1) +#define DEVICE_FREQUENCY_REQUEST (1u<<1) // Channel configuration was requested by the config file -#define DEVICE_CHANNELS_REQUEST (1<<2) +#define DEVICE_CHANNELS_REQUEST (1u<<2) // Sample type was requested by the config file -#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3) +#define DEVICE_SAMPLE_TYPE_REQUEST (1u<<3) // Specifies if the DSP is paused at user request -#define DEVICE_PAUSED (1<<30) +#define DEVICE_PAUSED (1u<<30) // Specifies if the device is currently running -#define DEVICE_RUNNING (1<<31) +#define DEVICE_RUNNING (1u<<31) /* Nanosecond resolution for the device clock time. */ -- cgit v1.2.3 From 3af1d5b72226971f08fca869875c4348314dae5c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Sep 2016 05:37:01 -0700 Subject: Properly align 16-bit fields in the Hrtf struct --- Alc/hrtf.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 16db0c33..b94faf9d 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -468,6 +468,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str { size_t total = sizeof(struct Hrtf); total += sizeof(azCount[0])*evCount; + total = (total+1)&~1; /* Align for (u)short fields */ total += sizeof(evOffset[0])*evCount; total += sizeof(coeffs[0])*irSize*irCount; total += sizeof(delays[0])*irCount; @@ -483,14 +484,18 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(!failed) { + char *base = (char*)Hrtf; + uintptr_t offset = sizeof(*Hrtf); + Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(Hrtf+1)); - Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); - Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); - Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); - Hrtf->filename = ((char*)(Hrtf->delays + irCount)); + Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]); + offset = (offset+1)&~1; /* Align for (u)short fields */ + Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]); + Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]); + Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]); + Hrtf->filename = ((char*)(base + offset)); Hrtf->next = NULL; memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); @@ -644,6 +649,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str { size_t total = sizeof(struct Hrtf); total += sizeof(azCount[0])*evCount; + total = (total+1)&~1; /* Align for (u)short fields */ total += sizeof(evOffset[0])*evCount; total += sizeof(coeffs[0])*irSize*irCount; total += sizeof(delays[0])*irCount; @@ -659,14 +665,18 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(!failed) { + char *base = (char*)Hrtf; + uintptr_t offset = sizeof(*Hrtf); + Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(Hrtf+1)); - Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); - Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); - Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); - Hrtf->filename = ((char*)(Hrtf->delays + irCount)); + Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]); + offset = (offset+1)&~1; /* Align for (u)short fields */ + Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]); + Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]); + Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]); + Hrtf->filename = ((char*)(base + offset)); Hrtf->next = NULL; memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); -- cgit v1.2.3 From ef67d17a842a315eac3ef863edc8682a5c033032 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Sep 2016 09:22:34 -0700 Subject: Simplify mmdevapi's device name search Avoids converting each enumerated devid from WSTR to UTF-8, and instead just converts the device name from UTF-8 to WSTR once if needed. --- Alc/backends/mmdevapi.c | 50 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index b444a341..31092db7 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -242,7 +242,7 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) count++; } - TRACE("Got device \"%s\", %s, \"%ls\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.endpoint_guid), entry.devid); + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.endpoint_guid), entry.devid); VECTOR_PUSH_BACK(*list, entry); AL_STRING_DEINIT(tmpname); @@ -689,18 +689,6 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX * return ALC_TRUE; } - static ALCboolean match_name_or_guid(const DevMap *iter, const ALCchar *deviceName){ - al_string tmp_id; - ALCboolean result; - result=AL_FALSE; - if (al_string_cmp_cstr(iter->name, deviceName) == 0 || al_string_cmp_cstr(iter->endpoint_guid, deviceName) == 0) return ALC_TRUE; - AL_STRING_INIT(tmp_id); - al_string_copy_wcstr(&tmp_id, iter->devid); - if(al_string_cmp_cstr(tmp_id, deviceName)==0)result=AL_TRUE; - AL_STRING_DEINIT(tmp_id); - return result; -} - static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName) { HRESULT hr = S_OK; @@ -727,8 +715,23 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi } hr = E_FAIL; -#define MATCH_NAME(i) (match_name_or_guid((i), (deviceName))==ALC_TRUE) +#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \ + al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(PlaybackDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) + { + WCHAR *wname = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + free(wname); + } + } if(iter == VECTOR_END(PlaybackDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); else @@ -738,7 +741,6 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi al_string_copy(&device->DeviceName, iter->name); hr = S_OK; } -#undef MATCH_NAME } } @@ -1372,8 +1374,23 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device } hr = E_FAIL; -#define MATCH_NAME(i) (match_name_or_guid((i), (deviceName))==ALC_TRUE) +#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \ + al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(CaptureDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) + { + WCHAR *wname = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + free(wname); + } + } if(iter == VECTOR_END(CaptureDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); else @@ -1383,7 +1400,6 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device al_string_copy(&device->DeviceName, iter->name); hr = S_OK; } -#undef MATCH_NAME } } -- cgit v1.2.3 From a52cfc804813aef8e4b304e20cf843fa6907af6c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Sep 2016 09:57:40 -0700 Subject: Check for run-time NEON support by reading /proc/cpuinfo Less than ideal since documentations warn it may not list 'neon' even if it's really supported. However, the "proper" APIs to check for NEON extensions don't seem to exist in my toolchain. --- Alc/helpers.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 9b6c7894..4ffda46c 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -32,6 +32,7 @@ #include #include #include +#include #ifdef HAVE_MALLOC_H #include #endif @@ -232,8 +233,37 @@ void FillCPUCaps(ALuint capfilter) #endif #endif #ifdef HAVE_NEON - /* Assume Neon support if compiled with it */ - caps |= CPU_CAP_NEON; + FILE *file = fopen("/proc/cpuinfo", "rt"); + if(file) + ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); + else + { + char buf[256]; + while(fgets(buf, sizeof(buf), file) != NULL) + { + char *str; + + if(strncmp(buf, "Features\t:", 10) != 0) + continue; + + TRACE("Got features string:%s\n", buf+10); + + str = buf; + while((str=strstr(str, "neon")) != NULL) + { + if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) + { + caps |= CPU_CAP_NEON; + break; + } + str++; + } + break; + } + + fclose(file); + file = NULL; + } #endif TRACE("Extensions:%s%s%s%s%s%s\n", -- cgit v1.2.3 From 742f181595e5891f1ed132aa403f939b767a2f28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Sep 2016 16:26:13 -0700 Subject: Use a few more HRIRs for the HRTF B-Format decoder 14 in total, an 8-point cube and a 6-point diamond shape, to help improve sound localization a bit. Incurs no real extra CPU cost once the IRs are built. --- Alc/hrtf.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index b94faf9d..d7cd6bad 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -178,25 +178,37 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ static const struct { ALfloat elevation; ALfloat azimuth; - } CubePoints[8] = { + } Ambi3DPoints[14] = { + { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; - static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = { - { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, - { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, - { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, - { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, - { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, - { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, - { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, - { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, + static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { + { { 0.18898176f, 0.000000000f, 0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, + { { 0.18898176f, 0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, 0.0714286206f } }, + { { 0.18898176f, -0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, 0.0714286206f } }, + { { 0.18898176f, -0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, -0.0714286206f } }, + { { 0.18898176f, 0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, -0.0714286206f } }, + { { 0.18898176f, 0.000000000f, 0.000000000f, 0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, + { { 0.18898176f, -0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.18898176f, 0.000000000f, 0.000000000f, -0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, + { { 0.18898176f, 0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.18898176f, 0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, 0.0714286206f } }, + { { 0.18898176f, -0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, 0.0714286206f } }, + { { 0.18898176f, -0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, -0.0714286206f } }, + { { 0.18898176f, 0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, -0.0714286206f } }, + { { 0.18898176f, 0.000000000f, -0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, }; /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -205,21 +217,21 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ #define NUM_BANDS 1 BandSplitter splitter; ALfloat temps[3][HRIR_LENGTH]; - ALuint lidx[8], ridx[8]; + ALuint lidx[14], ridx[14]; ALuint min_delay = HRTF_HISTORY_LENGTH; ALuint max_length = 0; ALuint i, j, c, b; assert(NumChannels == 4); - for(c = 0;c < 8;c++) + for(c = 0;c < COUNTOF(Ambi3DPoints);c++) { ALuint evidx, azidx; ALuint evoffset; ALuint azcount; /* Calculate elevation index. */ - evidx = (ALuint)floorf((F_PI_2 + CubePoints[c].elevation) * + evidx = (ALuint)floorf((F_PI_2 + Ambi3DPoints[c].elevation) * (Hrtf->evCount-1)/F_PI + 0.5f); evidx = minu(evidx, Hrtf->evCount-1); @@ -227,7 +239,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - azidx = (ALuint)floorf((F_TAU+CubePoints[c].azimuth) * + azidx = (ALuint)floorf((F_TAU+Ambi3DPoints[c].azimuth) * azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ @@ -239,7 +251,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ memset(temps, 0, sizeof(temps)); bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); - for(c = 0;c < 8;c++) + for(c = 0;c < COUNTOF(Ambi3DMatrix);c++) { const ALshort *fir; ALuint delay; @@ -268,7 +280,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][0] += temps[b][k++] * CubeMatrix[c][b][i]; + coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][i]; } } max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -297,7 +309,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][1] += temps[b][k++] * CubeMatrix[c][b][i]; + coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][i]; } } max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); -- cgit v1.2.3 From c3c283a0b5d0130afafaa2a5b6ce6fbc30b6e6a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Sep 2016 02:02:09 -0700 Subject: Properly check if /proc/cpuinfo opened --- Alc/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 4ffda46c..26ed535a 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -234,7 +234,7 @@ void FillCPUCaps(ALuint capfilter) #endif #ifdef HAVE_NEON FILE *file = fopen("/proc/cpuinfo", "rt"); - if(file) + if(!file) ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); else { -- cgit v1.2.3 From 958301d8801c27027eb8a0562f7a18ffae0fe26d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Sep 2016 06:30:25 -0700 Subject: Try increasing the stack size if thread creation fails Also increase the default stack size to 2MB. --- common/threads.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/common/threads.c b/common/threads.c index 24a197a4..0a019d03 100644 --- a/common/threads.c +++ b/common/threads.c @@ -55,7 +55,7 @@ extern inline int altss_set(altss_t tss_id, void *val); #endif -#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ +#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */ #ifdef _WIN32 @@ -531,6 +531,8 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) { thread_cntr *cntr; pthread_attr_t attr; + size_t stackmult = 1; + int err; cntr = malloc(sizeof(*cntr)); if(!cntr) return althrd_nomem; @@ -540,7 +542,8 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) free(cntr); return althrd_error; } - if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0) +retry_stacksize: + if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0) { pthread_attr_destroy(&attr); free(cntr); @@ -549,15 +552,30 @@ int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) cntr->func = func; cntr->arg = arg; - if(pthread_create(thr, &attr, althrd_starter, cntr) != 0) + if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0) { pthread_attr_destroy(&attr); - free(cntr); - return althrd_error; + return althrd_success; } - pthread_attr_destroy(&attr); - return althrd_success; + if(err == EINVAL) + { + /* If an invalid stack size, try increasing it (limit x4, 8MB). */ + if(stackmult < 4) + { + stackmult *= 2; + goto retry_stacksize; + } + /* If still nothing, try defaults and hope they're good enough. */ + if(pthread_create(thr, NULL, althrd_starter, cntr) == 0) + { + pthread_attr_destroy(&attr); + return althrd_success; + } + } + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; } int althrd_detach(althrd_t thr) -- cgit v1.2.3 From b21e481827b660e7439fcebb505cdb0349517a54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Sep 2016 11:56:25 -0700 Subject: Only WARN if GetProcPath fails to find the binary --- Alc/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 26ed535a..d4b44ced 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -726,7 +726,7 @@ al_string GetProcPath(void) if(len <= 0) { free(pathname); - ERR("Failed to link %s: %s\n", fname, strerror(errno)); + WARN("Failed to readlink %s: %s\n", fname, strerror(errno)); return ret; } -- cgit v1.2.3 From 0f24f49a44a12d139692d0846b2722de2213f1a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Sep 2016 12:05:08 -0700 Subject: Allow specifying the device to open for the examples --- examples/alffplay.c | 15 +++++++++++++-- examples/alhrtf.c | 34 ++++++++++++++++++---------------- examples/allatency.c | 11 ++++++----- examples/alreverb.c | 11 ++++++----- examples/alstream.c | 9 +++++---- examples/altonegen.c | 28 ++++++++++++++++------------ examples/common/alhelpers.c | 30 ++++++++++++++++++++++++------ examples/common/alhelpers.h | 2 +- 8 files changed, 89 insertions(+), 51 deletions(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index 2d38216f..e95dede6 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -1332,6 +1332,7 @@ int main(int argc, char *argv[]) SDL_Renderer *renderer; ALCdevice *device; ALCcontext *context; + int fileidx; if(argc < 2) { @@ -1389,7 +1390,17 @@ int main(int argc, char *argv[]) SDL_RenderPresent(renderer); /* Open an audio device */ - device = alcOpenDevice(NULL); + fileidx = 1; + device = NULL; + if(argc > 3 && strcmp(argv[1], "-device") == 0) + { + fileidx = 3; + device = alcOpenDevice(argv[2]); + if(!device) + fprintf(stderr, "OpenAL: could not open \"%s\" - trying default\n", argv[2]); + } + if(!device) + device = alcOpenDevice(NULL); if(!device) { fprintf(stderr, "OpenAL: could not open device - exiting\n"); @@ -1429,7 +1440,7 @@ int main(int argc, char *argv[]) movState = av_mallocz(sizeof(MovieState)); - av_strlcpy(movState->filename, argv[1], sizeof(movState->filename)); + av_strlcpy(movState->filename, argv[fileidx], sizeof(movState->filename)); packet_queue_init(&movState->audio.q); packet_queue_init(&movState->video.q); diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 23d60a74..3964a7c6 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -122,28 +122,18 @@ int main(int argc, char **argv) ALdouble angle; ALenum state; - /* Print out usage if no file was specified */ - if(argc < 2 || (strcmp(argv[1], "-hrtf") == 0 && argc < 4)) + /* Print out usage if no arguments were specified */ + if(argc < 2) { - fprintf(stderr, "Usage: %s [-hrtf ] \n", argv[0]); + fprintf(stderr, "Usage: %s [-device ] [-hrtf ] \n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for HRTF support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for HRTF support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; - if(strcmp(argv[1], "-hrtf") == 0) - { - hrtfname = argv[2]; - soundname = argv[3]; - } - else - { - hrtfname = NULL; - soundname = argv[1]; - } - device = alcGetContextsDevice(alcGetCurrentContext()); if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF")) { @@ -164,6 +154,18 @@ int main(int argc, char **argv) has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES"); printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not"); + /* Check for user-preferred HRTF */ + if(strcmp(argv[0], "-hrtf") == 0) + { + hrtfname = argv[1]; + soundname = argv[2]; + } + else + { + hrtfname = NULL; + soundname = argv[0]; + } + /* Enumerate available HRTFs, and reset the device using one. */ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); if(!num_hrtf) diff --git a/examples/allatency.c b/examples/allatency.c index afef43ca..56d96b9e 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -125,15 +125,16 @@ int main(int argc, char **argv) ALdouble offsets[2]; ALenum state; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s [-device ] \n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for EFX support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for source_latency support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(!alIsExtensionPresent("AL_SOFT_source_latency")) @@ -166,7 +167,7 @@ int main(int argc, char **argv) #undef LOAD_PROC /* Load the sound into a buffer. */ - buffer = LoadSound(argv[1]); + buffer = LoadSound(argv[0]); if(!buffer) { CloseAL(); diff --git a/examples/alreverb.c b/examples/alreverb.c index 7d2bb343..ec71f354 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -217,15 +217,16 @@ int main(int argc, char **argv) ALuint source, buffer, effect, slot; ALenum state; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s [-device \n", argv[0]); return 1; } - /* Initialize OpenAL with the default device, and check for EFX support. */ - if(InitAL() != 0) + /* Initialize OpenAL, and check for EFX support. */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(!alcIsExtensionPresent(alcGetContextsDevice(alcGetCurrentContext()), "ALC_EXT_EFX")) @@ -269,7 +270,7 @@ int main(int argc, char **argv) #undef LOAD_PROC /* Load the sound into a buffer. */ - buffer = LoadSound(argv[1]); + buffer = LoadSound(argv[0]); if(!buffer) { CloseAL(); diff --git a/examples/alstream.c b/examples/alstream.c index 63478d6a..65a04475 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -270,14 +270,15 @@ int main(int argc, char **argv) StreamPlayer *player; int i; - /* Print out usage if no file was specified */ + /* Print out usage if no arguments were specified */ if(argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s [-device ] \n", argv[0]); return 1; } - if(InitAL() != 0) + argv++; argc--; + if(InitAL(&argv, &argc) != 0) return 1; if(alIsExtensionPresent("AL_SOFT_buffer_samples")) @@ -292,7 +293,7 @@ int main(int argc, char **argv) player = NewPlayer(); /* Play each file listed on the command line */ - for(i = 1;i < argc;i++) + for(i = 0;i < argc;i++) { const char *namepart; diff --git a/examples/altonegen.c b/examples/altonegen.c index 74a04ee2..422e6d66 100644 --- a/examples/altonegen.c +++ b/examples/altonegen.c @@ -133,6 +133,7 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate) int main(int argc, char *argv[]) { enum WaveType wavetype = WT_Sine; + const char *appname = argv[0]; ALuint source, buffer; ALint last_pos, num_loops; ALint max_loops = 4; @@ -142,13 +143,24 @@ int main(int argc, char *argv[]) ALenum state; int i; - for(i = 1;i < argc;i++) + argv++; argc--; + if(InitAL(&argv, &argc) != 0) + return 1; + + if(!alIsExtensionPresent("AL_EXT_FLOAT32")) + { + fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n"); + CloseAL(); + return 1; + } + + for(i = 0;i < argc;i++) { if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { fprintf(stderr, "OpenAL Tone Generator\n" "\n" -"Usage: %s \n" +"Usage: %s [-device ] \n" "\n" "Available options:\n" " --help/-h This help text\n" @@ -157,8 +169,9 @@ int main(int argc, char *argv[]) " triangle, impulse\n" " --freq/-f Tone frequency (default 1000 hz)\n" " --srate/-s Sampling rate (default output rate)\n", - argv[0] + appname ); + CloseAL(); return 1; } else if(i+1 < argc && strcmp(argv[i], "-t") == 0) @@ -204,15 +217,6 @@ int main(int argc, char *argv[]) } } - InitAL(); - - if(!alIsExtensionPresent("AL_EXT_FLOAT32")) - { - fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n"); - CloseAL(); - return 1; - } - { ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); alcGetIntegerv(device, ALC_FREQUENCY, 1, &dev_rate); diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 4582321c..43548b5c 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -29,6 +29,7 @@ * channel configs and sample types. */ #include +#include #include "AL/al.h" #include "AL/alc.h" @@ -37,15 +38,26 @@ #include "alhelpers.h" -/* InitAL opens the default device and sets up a context using default - * attributes, making the program ready to call OpenAL functions. */ -int InitAL(void) +/* InitAL opens a device and sets up a context using default attributes, making + * the program ready to call OpenAL functions. */ +int InitAL(char ***argv, int *argc) { + const ALCchar *name; ALCdevice *device; ALCcontext *ctx; - /* Open and initialize a device with default settings */ - device = alcOpenDevice(NULL); + /* Open and initialize a device */ + device = NULL; + if(argc && argv && *argc > 1 && strcmp((*argv)[0], "-device") == 0) + { + device = alcOpenDevice((*argv)[1]); + if(!device) + fprintf(stderr, "Failed to open \"%s\", trying default\n", (*argv)[1]); + (*argv) += 2; + (*argc) -= 2; + } + if(!device) + device = alcOpenDevice(NULL); if(!device) { fprintf(stderr, "Could not open a device!\n"); @@ -62,7 +74,13 @@ int InitAL(void) return 1; } - printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER)); + name = NULL; + if(alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT")) + name = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER); + if(!name || alcGetError(device) != AL_NO_ERROR) + name = alcGetString(device, ALC_DEVICE_SPECIFIER); + printf("Opened \"%s\"\n", name); + return 0; } diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 1b4d2fbf..9f60df2a 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -35,7 +35,7 @@ void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, const ALvoid *data); /* Easy device init/deinit functions. InitAL returns 0 on success. */ -int InitAL(void); +int InitAL(char ***argv, int *argc); void CloseAL(void); #ifdef __cplusplus -- cgit v1.2.3 From 45dfdca6f9efa7ec8fb5c16be1bb0f513fe5d772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Sep 2016 16:22:46 -0700 Subject: Reduce the volume for the HRTF ambisonic decoder Since it's accumulating multiple HRIRs for two output speakers, it seems to be a better option to preserve the amplitude of the high-frequency decoder instead of increasing it, and reduce the amplitude of the low-frequency decoder to compensate. --- Alc/hrtf.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d7cd6bad..92a1acea 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -195,20 +195,20 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { - { { 0.18898176f, 0.000000000f, 0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, - { { 0.18898176f, 0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, 0.0714286206f } }, - { { 0.18898176f, -0.109109004f, 0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, 0.0714286206f } }, - { { 0.18898176f, -0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, 0.0714286206f, -0.0714286206f } }, - { { 0.18898176f, 0.109109004f, 0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, 0.0714286206f, -0.0714286206f } }, - { { 0.18898176f, 0.000000000f, 0.000000000f, 0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, - { { 0.18898176f, -0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.18898176f, 0.000000000f, 0.000000000f, -0.188982460f }, { 0.0714283915f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, - { { 0.18898176f, 0.188982460f, 0.000000000f, 0.000000000f }, { 0.0714283915f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.18898176f, 0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, 0.0714286206f } }, - { { 0.18898176f, -0.109109004f, -0.109109004f, 0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, 0.0714286206f } }, - { { 0.18898176f, -0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, -0.0714286206f, -0.0714286206f, -0.0714286206f } }, - { { 0.18898176f, 0.109109004f, -0.109109004f, -0.109109004f }, { 0.0714283915f, 0.0714286206f, -0.0714286206f, -0.0714286206f } }, - { { 0.18898176f, 0.000000000f, -0.188982460f, 0.000000000f }, { 0.0714283915f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, + { { 0.071428392f, 0.000000000f, 0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, 0.0467610443f, 0.0000000000f } }, + { { 0.071428392f, 0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.000000000f, 0.000000000f, 0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, 0.0467610443f } }, + { { 0.071428392f, -0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, -0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.071428392f, 0.000000000f, 0.000000000f, -0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, -0.0467610443f } }, + { { 0.071428392f, 0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, 0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.071428392f, 0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.071428392f, -0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.071428392f, 0.000000000f, -0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, -0.0467610443f, 0.0000000000f } }, }; /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the -- cgit v1.2.3 From ba449ccce5246031f481bf84b9dce4237553f628 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Sep 2016 09:52:01 -0700 Subject: Handle UTF-8 output on Windows in openal-info --- utils/openal-info.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/utils/openal-info.c b/utils/openal-info.c index 5b45ceef..5fd8784b 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -24,6 +24,7 @@ #include #include +#include #include "AL/alc.h" #include "AL/al.h" @@ -41,6 +42,70 @@ #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +static WCHAR *FromUTF8(const char *str) +{ + WCHAR *out = NULL; + int len; + + if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) + { + out = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); + } + return out; +} + +/* Override printf, fprintf, and fwrite so we can print UTF-8 strings. */ +static void al_fprintf(FILE *file, const char *fmt, ...) +{ + char str[1024]; + WCHAR *wstr; + va_list ap; + + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + str[sizeof(str)-1] = 0; + wstr = FromUTF8(str); + if(!wstr) + fprintf(file, " %s", str); + else + fprintf(file, "%ls", wstr); + free(wstr); +} +#define fprintf al_fprintf +#define printf(...) al_fprintf(stdout, __VA_ARGS__) + +static int al_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *file) +{ + char str[1024]; + WCHAR *wstr; + size_t len; + + len = size * nmemb; + if(len > sizeof(str)-1) + len = sizeof(str)-1; + memcpy(str, ptr, len); + str[len] = 0; + + wstr = FromUTF8(str); + if(!wstr) + fprintf(file, " %s", str); + else + fprintf(file, "%ls", wstr); + free(wstr); + + return len / size; +} +#define fwrite al_fwrite +#endif + + #define MAX_WIDTH 80 static void printList(const char *list, char separator) -- cgit v1.2.3 From f993fd0cefe5dd04c2c37d4c1cde191dfbf2c882 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Sep 2016 07:55:33 -0700 Subject: Don't warn if the desired default HRTF is already first --- Alc/hrtf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 92a1acea..34070792 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -1051,16 +1051,16 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) /* Find the preferred HRTF and move it to the front of the list. */ #define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY); - if(iter != VECTOR_END(list) && iter != VECTOR_BEGIN(list)) +#undef FIND_ENTRY + if(iter == VECTOR_END(list)) + WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); + else if(iter != VECTOR_BEGIN(list)) { HrtfEntry entry = *iter; memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), (iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry)); VECTOR_ELEM(list,0) = entry; } - else - WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); -#undef FIND_ENTRY } return list; -- cgit v1.2.3 From 4fcf9279febdaf9136e2ea61602dc39dcf5391dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Sep 2016 07:20:02 -0700 Subject: Mark a global variable declaration as extern --- OpenAL32/Include/alu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3d1a4986..29cb00fb 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -79,7 +79,7 @@ inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALf typedef union aluMatrixf { alignas(16) ALfloat m[4][4]; } aluMatrixf; -const aluMatrixf IdentityMatrixf; +extern const aluMatrixf IdentityMatrixf; inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) -- cgit v1.2.3 From 651715abc96dd2925486507f8197a18a5f2f11e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Sep 2016 12:25:06 -0700 Subject: Combine the reverb decorrelator delay line with the main delay line Since it was merely acting as an extension of it anyway, with the second delay line tap (for late reverb) copying attenuated samples to the decorrelator line that was being tapped off of. Just extend the delay line and offset the decorrelator taps to be relative to the late reverb tap. --- Alc/effects/reverb.c | 72 +++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ef25c076..7068e077 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -88,11 +88,16 @@ typedef struct ALreverbState { ALfloat Filter; } Mod; // EAX only - // Initial effect delay. + /* Core delay line (early reflections and late reverb tap from this). */ DelayLine Delay; - // The tap points for the initial delay. First tap goes to early - // reflections, the last to late reverb. + /* The tap points for the initial delay. First tap goes to early + * reflections, second to late reverb. + */ ALuint DelayTap[2]; + /* There are actually 4 decorrelator taps, but the first occurs at the late + * reverb tap. + */ + ALuint DecoTap[3]; struct { // Early reflections are done with 4 delay lines. @@ -105,12 +110,6 @@ typedef struct ALreverbState { ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; } Early; - // Decorrelator delay line. - DelayLine Decorrelator; - // There are actually 4 decorrelator taps, but the first occurs at the - // initial sample. - ALuint DecoTap[3]; - struct { // Output gain for late reverb. ALfloat Gain; @@ -213,6 +212,9 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Line = NULL; state->DelayTap[0] = 0; state->DelayTap[1] = 0; + state->DecoTap[0] = 0; + state->DecoTap[1] = 0; + state->DecoTap[2] = 0; for(index = 0;index < 4;index++) { @@ -222,12 +224,6 @@ static void ALreverbState_Construct(ALreverbState *state) 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->Late.Gain = 0.0f; state->Late.DensityGain = 0.0f; state->Late.ApFeedCoeff = 0.0f; @@ -407,11 +403,15 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) totalSamples += CalcLineLength(length, totalSamples, frequency, 1, &State->Mod.Delay); - // The initial delay is the sum of the reflections and late reverb - // delays. This must include space for storing a loop update to feed the - // early reflections, decorrelator, and echo. + /* The initial delay is the sum of the reflections and late reverb delays. + * The decorrelator length is calculated from the lowest reverb density (a + * parameter value of 1). This must include space for storing a loop + * update. + */ length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; + length += (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * + LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Delay); @@ -420,14 +420,6 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, frequency, 0, &State->Early.Delay[index]); - // The decorrelator line is calculated from the lowest reverb density (a - // parameter value of 1). This must include space for storing a loop update - // to feed the late reverb. - length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * - LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, - &State->Decorrelator); - // The late all-pass lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, @@ -462,7 +454,6 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) // Update all delays to reflect the new sample buffer. RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); for(index = 0;index < 4;index++) { RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); @@ -697,7 +688,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->DecoTap[index] = fastf2u(length * frequency); + State->DecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; } } @@ -1023,12 +1014,12 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, frequency, State); - // Update the early lines. - UpdateEarlyLines(props->Reverb.LateReverbDelay, State); - // Update the decorrelator. UpdateDecorrelator(props->Reverb.Density, frequency, State); + // Update the early lines. + UpdateEarlyLines(props->Reverb.LateReverbDelay, State); + // Get the mixing matrix coefficients (x and y). CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); // Then divide x into y to simplify the matrix calculation. @@ -1230,17 +1221,6 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res ALuint offset; ALuint base, i; - // Feed the decorrelator from the energy-attenuated output of the second - // delay tap. - offset = State->Offset; - for(i = 0;i < todo;i++) - { - ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * - State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, offset, sample); - offset++; - } - offset = State->Offset; for(base = 0;base < todo;) { @@ -1250,10 +1230,10 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res for(i = 0;i < tmp_todo;i++) { /* Obtain four decorrelated input samples. */ - f[0] = DelayLineOut(&State->Decorrelator, offset); - f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); - f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); - f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); + f[0] = DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * State->Late.DensityGain; + f[1] = DelayLineOut(&State->Delay, offset-State->DecoTap[0]) * State->Late.DensityGain; + f[2] = DelayLineOut(&State->Delay, offset-State->DecoTap[1]) * State->Late.DensityGain; + f[3] = DelayLineOut(&State->Delay, offset-State->DecoTap[2]) * State->Late.DensityGain; /* Add the decayed results of the cyclical delay lines, then pass * the results through the low-pass filters. -- cgit v1.2.3 From efaa09dc23066ec288f48b2a0479eb9c988404ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Sep 2016 17:11:19 -0700 Subject: Write to the correct outputs for extra reverb channels --- Alc/effects/reverb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7068e077..071f4fc3 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1461,7 +1461,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo ); if(State->ExtraChannels > 0) - DoMix(early[c], SamplesOut, State->ExtraChannels, + DoMix(early[c], State->ExtraOut, State->ExtraChannels, State->Early.PanGain[c]+NumChannels, State->Early.CurrentGain[c]+NumChannels, delta, base, SamplesToDo-base, todo @@ -1473,7 +1473,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples State->Late.CurrentGain[c], delta, base, SamplesToDo, todo ); if(State->ExtraChannels > 0) - DoMix(late[c], SamplesOut, State->ExtraChannels, + DoMix(late[c], State->ExtraOut, State->ExtraChannels, State->Late.PanGain[c]+NumChannels, State->Late.CurrentGain[c]+NumChannels, delta, base, SamplesToDo-base, todo -- cgit v1.2.3 From 46b3e1d08ca10e809eb2e20b6371812958b97e1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Sep 2016 11:31:59 -0700 Subject: Check if -mfpu=neon is available for compiling the NEON mixer --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d92bbb7d..0d3bb5cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,6 +364,7 @@ SET(SSE_SWITCH "") SET(SSE2_SWITCH "") SET(SSE3_SWITCH "") SET(SSE4_1_SWITCH "") +SET(FPU_NEON_SWITCH "") IF(NOT MSVC) CHECK_C_COMPILER_FLAG(-msse HAVE_MSSE_SWITCH) IF(HAVE_MSSE_SWITCH) @@ -381,6 +382,10 @@ IF(NOT MSVC) IF(HAVE_MSSE4_1_SWITCH) SET(SSE4_1_SWITCH "-msse4.1") ENDIF() + CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_MFPU_NEON_SWITCH) + IF(HAVE_MFPU_NEON_SWITCH) + SET(FPU_NEON_SWITCH "-mfpu=neon") + ENDIF() ENDIF() CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2))); @@ -766,8 +771,11 @@ IF(HAVE_ARM_NEON_H) IF(ALSOFT_CPUEXT_NEON) SET(HAVE_NEON 1) SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_neon.c) + IF(FPU_NEON_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer_neon.c PROPERTIES + COMPILE_FLAGS "${FPU_NEON_SWITCH}") + ENDIF() SET(CPU_EXTS "${CPU_EXTS}, Neon") - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_neon.c PROPERTIES COMPILE_FLAGS -mfpu=neon) ENDIF() ENDIF() IF(ALSOFT_REQUIRE_NEON AND NOT HAVE_NEON) -- cgit v1.2.3 From 53d8a496736c61b9cde5d982737bed98b2f72004 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Sep 2016 11:48:15 -0700 Subject: Call ALfilterState_processC directly It's the only implementation currently, so there's no point to having it stored as a function pointer in the filter struct. Even if there were SIMD versions, it'd be a global selection, not per-instance. --- Alc/effects/equalizer.c | 4 ---- Alc/effects/modulator.c | 1 - OpenAL32/Include/alFilter.h | 5 ++--- OpenAL32/alFilter.c | 2 -- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 61932ffb..1a63b418 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -151,7 +151,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[0][i].b0 = state->filter[0][0].b0; state->filter[0][i].b1 = state->filter[0][0].b1; state->filter[0][i].b2 = state->filter[0][0].b2; - state->filter[0][i].process = state->filter[0][0].process; } gain = props->Equalizer.Mid1Gain; @@ -168,7 +167,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[1][i].b0 = state->filter[1][0].b0; state->filter[1][i].b1 = state->filter[1][0].b1; state->filter[1][i].b2 = state->filter[1][0].b2; - state->filter[1][i].process = state->filter[1][0].process; } gain = props->Equalizer.Mid2Gain; @@ -185,7 +183,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[2][i].b0 = state->filter[2][0].b0; state->filter[2][i].b1 = state->filter[2][0].b1; state->filter[2][i].b2 = state->filter[2][0].b2; - state->filter[2][i].process = state->filter[2][0].process; } gain = sqrtf(props->Equalizer.HighGain); @@ -200,7 +197,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[3][i].b0 = state->filter[3][0].b0; state->filter[3][i].b1 = state->filter[3][0].b1; state->filter[3][i].b2 = state->filter[3][0].b2; - state->filter[3][i].process = state->filter[3][0].process; } } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 5ca37f4f..247cdf61 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -142,7 +142,6 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * state->Filter[i].b0 = a; state->Filter[i].b1 = -a; state->Filter[i].b2 = 0.0f; - state->Filter[i].process = ALfilterState_processC; } STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index a74cd211..1f7095bc 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -44,10 +44,9 @@ typedef struct ALfilterState { ALfloat y[2]; /* History of two last output samples */ ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ - - void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); } ALfilterState; -#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__)) +/* Currently only a C-based filter process method is implemented. */ +#define ALfilterState_process ALfilterState_processC /* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the * reference gain and shelf slope parameter. diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index fa3496c9..c675d344 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -431,8 +431,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->b0 = b[0] / a[0]; filter->b1 = b[1] / a[0]; filter->b2 = b[2] / a[0]; - - filter->process = ALfilterState_processC; } -- cgit v1.2.3 From a004ccfa1ad482d001c2c891b14e22ab7300ad04 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Sep 2016 12:42:11 -0700 Subject: Check for libatomic, in case C11 atomics need it --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d3bb5cd..825e36b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,13 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() +# Some systems may need libatomic for (C11) atomic functions to work +CHECK_LIBRARY_EXISTS(atomic atomic_fetch_add "" HAVE_LIBATOMIC) +IF(HAVE_LIBATOMIC) + SET(EXTRA_LIBS atomic ${EXTRA_LIBS}) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} atomic) +ENDIF() + # Check if we have C99 variable length arrays CHECK_C_SOURCE_COMPILES( "int main(int argc, char *argv[]) @@ -213,8 +220,10 @@ HAVE_C11_ALIGNAS) CHECK_C_SOURCE_COMPILES( "#include const int _Atomic foo = ATOMIC_VAR_INIT(~0); + int _Atomic bar = ATOMIC_VAR_INIT(0); int main() { + atomic_fetch_add(&bar, 2); return atomic_load(&foo); }" HAVE_C11_ATOMIC) -- cgit v1.2.3 From 1ff24c717104dd8527394ac1779e95ff5e2e1d30 Mon Sep 17 00:00:00 2001 From: Sergei Nikulov Date: Tue, 13 Sep 2016 15:08:47 +0300 Subject: build: added appveyour-ci script to verify windows build --- appveyor.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..4010f2ea --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,14 @@ +version: 1.17.2.{build} + +environment: + matrix: + - GEN: "Visual Studio 14 2015" + CFG: Release + - GEN: "Visual Studio 14 2015 Win64" + CFG: Release + +build_script: + - cd build + - cmake .. -G"%GEN%" + - cmake --build . --config %CFG% --clean-first + -- cgit v1.2.3 From af5fb3d6e73ac5e7f015011974c7a7443ae6744b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Sep 2016 12:11:52 -0700 Subject: Fix the libatomic check --- CMakeLists.txt | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 825e36b6..4195be43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,12 +171,22 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() -# Some systems may need libatomic for (C11) atomic functions to work -CHECK_LIBRARY_EXISTS(atomic atomic_fetch_add "" HAVE_LIBATOMIC) -IF(HAVE_LIBATOMIC) +# Some systems may need libatomic for C11 atomic functions to work +SET(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +SET(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) +CHECK_C_SOURCE_COMPILES("#include +int _Atomic foo = ATOMIC_VAR_INIT(0); +int main() +{ + return atomic_fetch_add(&foo, 2); +}" +HAVE_LIBATOMIC) +IF(NOT HAVE_LIBATOMIC) + SET(CMAKE_REQUIRED_LIBRARIES "${OLD_REQUIRED_LIBRARIES}") +ELSE() SET(EXTRA_LIBS atomic ${EXTRA_LIBS}) - SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} atomic) ENDIF() +UNSET(OLD_REQUIRED_LIBRARIES) # Check if we have C99 variable length arrays CHECK_C_SOURCE_COMPILES( -- cgit v1.2.3 From bb48a7e520bedb8f5bc54c0322b5922279b10ffd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Sep 2016 16:55:39 -0700 Subject: Fix EAX reverb effect output for HRTF and UHJ --- Alc/effects/reverb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 071f4fc3..c9397b67 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1504,7 +1504,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo ); if(State->ExtraChannels > 0) - DoMix(early[c], SamplesOut, State->ExtraChannels, + DoMix(early[c], State->ExtraOut, State->ExtraChannels, State->Early.PanGain[c]+NumChannels, State->Early.CurrentGain[c]+NumChannels, delta, base, SamplesToDo-base, todo @@ -1516,7 +1516,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, State->Late.CurrentGain[c], delta, base, SamplesToDo, todo ); if(State->ExtraChannels > 0) - DoMix(late[c], SamplesOut, State->ExtraChannels, + DoMix(late[c], State->ExtraOut, State->ExtraChannels, State->Late.PanGain[c]+NumChannels, State->Late.CurrentGain[c]+NumChannels, delta, base, SamplesToDo-base, todo -- cgit v1.2.3 From 4486043ae509f00a971e30f1da642f2351f1974d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Sep 2016 13:37:20 -0700 Subject: Skip audio packets that fail to decode in alffplay --- examples/alffplay.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/alffplay.c b/examples/alffplay.c index e95dede6..b61828f0 100644 --- a/examples/alffplay.c +++ b/examples/alffplay.c @@ -414,7 +414,11 @@ static int audio_decode_frame(MovieState *movState) int got_frame = 0; int len1 = avcodec_decode_audio4(movState->audio.st->codec, frame, &got_frame, pkt); - if(len1 < 0) break; + if(len1 < 0) + { + av_shrink_packet(pkt, 0); + continue; + } if(len1 <= pkt->size) { -- cgit v1.2.3 From d89624b03c2622c7deb2104ddf9318b131de67ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Sep 2016 15:16:09 -0700 Subject: Recognize Headset formfactors as headphones --- Alc/backends/mmdevapi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 31092db7..7cad93a9 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1063,7 +1063,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; } get_device_formfactor(self->mmdev, &formfactor); - device->IsHeadphones = (device->FmtChans == DevFmtStereo && formfactor == Headphones); + device->IsHeadphones = (device->FmtChans == DevFmtStereo && + (formfactor == Headphones || formfactor == Headset) + ); SetDefaultWFXChannelOrder(device); -- cgit v1.2.3 From 24f9a0f2aed5b0770af1633ab4a2e2832462294e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Sep 2016 14:29:27 -0700 Subject: Remove some more unnecessary volatiles --- OpenAL32/Include/alMain.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ac537978..356a749a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -733,12 +733,12 @@ struct ALCcontext_struct { ATOMIC(ALenum) LastError; - volatile enum DistanceModel DistanceModel; - volatile ALboolean SourceDistanceModel; + enum DistanceModel DistanceModel; + ALboolean SourceDistanceModel; - volatile ALfloat DopplerFactor; - volatile ALfloat DopplerVelocity; - volatile ALfloat SpeedOfSound; + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; ATOMIC(ALenum) DeferUpdates; RWLock PropLock; -- cgit v1.2.3 From f5e4a3ed85993f479c6cc1a967d5252378eb5211 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Sep 2016 18:46:41 -0700 Subject: Add a volume-adjust config option to adjust the source output volume Designed for apps that either don't change the listener's AL_GAIN, or don't allow the listener's AL_GAIN to go above 1. This allows the volume to still be increased further than such apps may allow, if users find it too quiet. Be aware that increasing this can easily cause clipping. The gain limit reported by AL_GAIN_LIMIT_SOFT is also affected by this. --- Alc/ALc.c | 17 +++++++++++++++++ Alc/ALu.c | 2 +- OpenAL32/Include/alMain.h | 2 ++ OpenAL32/alState.c | 10 +++++----- alsoftrc.sample | 7 +++++++ 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c4eb0462..a37e1242 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2319,6 +2319,7 @@ static ALvoid InitContext(ALCcontext *Context) //Validate Context InitRef(&Context->UpdateCount, 0); ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); + Context->GainBoost = 1.0f; RWLockInit(&Context->PropLock); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax); @@ -3159,6 +3160,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) { ALCcontext *ALContext; + ALfloat valf; ALCenum err; LockLists(); @@ -3229,6 +3231,21 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCdevice_IncRef(device); InitContext(ALContext); + if(ConfigValueFloat(al_string_get_cstr(device->DeviceName), NULL, "volume-adjust", &valf)) + { + if(!isfinite(valf)) + ERR("volume-adjust must be finite: %f\n", valf); + else + { + ALfloat db = clampf(valf, -24.0f, 24.0f); + if(db != valf) + WARN("volume-adjust clamped: %f, range: +/-%f\n", valf, 24.0f); + ALContext->GainBoost = powf(10.0f, db/20.0f); + TRACE("volume-adjust gain: %f\n", ALContext->GainBoost); + } + } + UpdateListenerProps(ALContext); + { ALCcontext *head = ATOMIC_LOAD(&device->ContextList); do { diff --git a/Alc/ALu.c b/Alc/ALu.c index f93781df..13aff5d9 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -278,7 +278,7 @@ static ALboolean CalcListenerParams(ALCcontext *Context) 0.0f); Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); - Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); + Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed) * Context->GainBoost; Listener->Params.MetersPerUnit = ATOMIC_LOAD(&props->MetersPerUnit, almemory_order_relaxed); Listener->Params.DopplerFactor = ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 356a749a..6320bc98 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -749,6 +749,8 @@ struct ALCcontext_struct { RefCount UpdateCount; ATOMIC(ALenum) HoldUpdates; + ALfloat GainBoost; + struct ALvoice *Voices; ALsizei VoiceCount; ALsizei MaxVoices; diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index c25aa63e..3d8e6c40 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -155,7 +155,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_GAIN_LIMIT_SOFT: - if(GAIN_MIX_MAX != 0.0f) + if(GAIN_MIX_MAX/context->GainBoost != 0.0f) value = AL_TRUE; break; @@ -201,7 +201,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_GAIN_LIMIT_SOFT: - value = (ALdouble)GAIN_MIX_MAX; + value = (ALdouble)GAIN_MIX_MAX/context->GainBoost; break; default: @@ -246,7 +246,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_GAIN_LIMIT_SOFT: - value = GAIN_MIX_MAX; + value = GAIN_MIX_MAX/context->GainBoost; break; default: @@ -291,7 +291,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_GAIN_LIMIT_SOFT: - value = (ALint)GAIN_MIX_MAX; + value = (ALint)(GAIN_MIX_MAX/context->GainBoost); break; default: @@ -336,7 +336,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_GAIN_LIMIT_SOFT: - value = (ALint64SOFT)GAIN_MIX_MAX; + value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); break; default: diff --git a/alsoftrc.sample b/alsoftrc.sample index 444ebc6f..d5913ff0 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -182,6 +182,13 @@ # possible is 4. #sends = +## volume-adjust: +# A global volume adjustment for source output, expressed in decibels. The +# value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will +# be a scale of 4x, etc. Similarly, -6 will be x1/2, and -12 is about x1/4. A +# value of 0 means no change. +#volume-adjust = 0 + ## excludefx: (global) # 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 -- cgit v1.2.3 From a258790539dd072d2e54d462ab73de013a41b9a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Sep 2016 11:18:26 -0700 Subject: Update the ambisonic coefficients for HRTF This uses an AllRAD-derived decoder matrix for the high frequencies, which seems to improve positioning response. It also switches back to dual-band. The low frequencies appear to be unexpectedly quiet by comparison, but it's not that bad and can be tweaked later. --- Alc/hrtf.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 34070792..87a119a0 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -195,26 +195,26 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { - { { 0.071428392f, 0.000000000f, 0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, 0.0467610443f, 0.0000000000f } }, - { { 0.071428392f, 0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, 0.0269973975f } }, - { { 0.071428392f, -0.041239332f, 0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, 0.0269973975f } }, - { { 0.071428392f, -0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, -0.0269973975f } }, - { { 0.071428392f, 0.041239332f, 0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, -0.0269973975f } }, - { { 0.071428392f, 0.000000000f, 0.000000000f, 0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, 0.0467610443f } }, - { { 0.071428392f, -0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, -0.0467610443f, 0.0000000000f, 0.0000000000f } }, - { { 0.071428392f, 0.000000000f, 0.000000000f, -0.071428392f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, -0.0467610443f } }, - { { 0.071428392f, 0.071428392f, 0.000000000f, 0.000000000f }, { 0.0269973975f, 0.0467610443f, 0.0000000000f, 0.0000000000f } }, - { { 0.071428392f, 0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, 0.0269973975f } }, - { { 0.071428392f, -0.041239332f, -0.041239332f, 0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, 0.0269973975f } }, - { { 0.071428392f, -0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, -0.0269973975f } }, - { { 0.071428392f, 0.041239332f, -0.041239332f, -0.041239332f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, -0.0269973975f } }, - { { 0.071428392f, 0.000000000f, -0.071428392f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, -0.0467610443f, 0.0000000000f } }, + { { 0.078851598f, 0.000000000f, 0.070561967f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, 0.0467610443f, 0.0000000000f } }, + { { 0.124051278f, 0.059847972f, 0.059847972f, 0.059847972f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.124051278f, -0.059847972f, 0.059847972f, 0.059847972f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, 0.0269973975f } }, + { { 0.124051278f, -0.059847972f, 0.059847972f, -0.059847972f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.124051278f, 0.059847972f, 0.059847972f, -0.059847972f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, -0.0269973975f } }, + { { 0.078851598f, 0.000000000f, 0.000000000f, 0.070561967f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, 0.0467610443f } }, + { { 0.078851598f, -0.070561967f, 0.000000000f, 0.000000000f }, { 0.0269973975f, -0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.078851598f, 0.000000000f, 0.000000000f, -0.070561967f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, -0.0467610443f } }, + { { 0.078851598f, 0.070561967f, 0.000000000f, 0.000000000f }, { 0.0269973975f, 0.0467610443f, 0.0000000000f, 0.0000000000f } }, + { { 0.124051278f, 0.059847972f, -0.059847972f, 0.059847972f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.124051278f, -0.059847972f, -0.059847972f, 0.059847972f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, 0.0269973975f } }, + { { 0.124051278f, -0.059847972f, -0.059847972f, -0.059847972f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.124051278f, 0.059847972f, -0.059847972f, -0.059847972f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, -0.0269973975f } }, + { { 0.078851598f, 0.000000000f, -0.070561967f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, -0.0467610443f, 0.0000000000f } }, }; /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the * tail generated by the filter. */ -#define NUM_BANDS 1 +#define NUM_BANDS 2 BandSplitter splitter; ALfloat temps[3][HRIR_LENGTH]; ALuint lidx[14], ridx[14]; -- cgit v1.2.3 From 67c74e858bca5946cd4d0b5ccc912364a147e111 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Oct 2016 12:11:50 -0700 Subject: Finalize AL_SOFT_gain_clamp_ex --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 5 ----- include/AL/alext.h | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a37e1242..7e220205 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -715,7 +715,7 @@ static const ALchar alExtList[] = "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " "AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES " "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels AL_SOFTX_gain_clamp_ex AL_SOFT_loop_points " + "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6320bc98..af599227 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -127,11 +127,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif #endif -#ifndef AL_SOFT_gain_clamp_ex -#define AL_SOFT_gain_clamp_ex 1 -#define AL_GAIN_LIMIT_SOFT 0x200E -#endif - typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; diff --git a/include/AL/alext.h b/include/AL/alext.h index 6af581aa..0090c804 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -431,6 +431,11 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi #endif #endif +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 1e4d9cfa7ef33ac600926246078afafae0bcf0ac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Oct 2016 12:20:13 -0700 Subject: Enhance reverb using B-Format processing Technically it uses A-Format processing from the B-Format input and output. But this attempts to provide better spatial definition to the reverberation so that it can be used in a more generic fashion, allowing it to be decoded as any other B-Format signal to whatever output is needed, and also allowing for a bit of height information when the output is capable of such. There may still be some kinks to work out, such as properly decorrelating the early reflection taps and tweaking the late reverb density. But it seems to be a good enough start. --- Alc/effects/reverb.c | 791 +++++++++++++++++++++++++-------------------------- 1 file changed, 386 insertions(+), 405 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c9397b67..f506486e 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -60,22 +60,20 @@ typedef struct ALreverbState { ALboolean IsEax; - // For HRTF and UHJ - ALfloat (*ExtraOut)[BUFFERSIZE]; - ALuint ExtraChannels; - // All delay lines are allocated as a single buffer to reduce memory // fragmentation and management code. ALfloat *SampleBuffer; ALuint TotalSamples; // Master effect filters - ALfilterState LpFilter; - ALfilterState HpFilter; // EAX only + struct { + ALfilterState Lp; + ALfilterState Hp; // EAX only + } Filter[4]; struct { // Modulator delay line. - DelayLine Delay; + DelayLine Delay[4]; // The vibrato time is tracked with an index over a modulus-wrapped // range (in samples). @@ -97,7 +95,7 @@ typedef struct ALreverbState { /* There are actually 4 decorrelator taps, but the first occurs at the late * reverb tap. */ - ALuint DecoTap[3]; + ALuint LateDecoTap[3]; struct { // Early reflections are done with 4 delay lines. @@ -106,8 +104,8 @@ typedef struct ALreverbState { ALuint Offset[4]; // The gain for each output channel based on 3D panning. - ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2]; - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; + ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Early; struct { @@ -139,8 +137,8 @@ typedef struct ALreverbState { ALfloat LpSample[4]; // The gain for each output channel based on 3D panning. - ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS+2]; - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS+2]; + ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Late; struct { @@ -149,8 +147,10 @@ typedef struct ALreverbState { ALfloat DensityGain; // Echo delay and all-pass lines. - DelayLine Delay; - DelayLine ApDelay; + struct { + DelayLine Feedback; + DelayLine Ap; + } Delay[4]; ALfloat Coeff; ALfloat ApFeedCoeff; @@ -161,7 +161,7 @@ typedef struct ALreverbState { // The echo line is 1-pole low-pass filtered. ALfloat LpCoeff; - ALfloat LpSample; + ALfloat LpSample[4]; // Echo mixing coefficient. ALfloat MixCoeff; @@ -171,6 +171,7 @@ typedef struct ALreverbState { ALuint Offset; /* Temporary storage used when processing. */ + alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; } ALreverbState; @@ -192,16 +193,19 @@ static void ALreverbState_Construct(ALreverbState *state) SET_VTABLE2(ALreverbState, ALeffectState, state); state->IsEax = AL_FALSE; - state->ExtraChannels = 0; state->TotalSamples = 0; state->SampleBuffer = NULL; - ALfilterState_clear(&state->LpFilter); - ALfilterState_clear(&state->HpFilter); + for(index = 0;index < 4;index++) + { + ALfilterState_clear(&state->Filter[index].Lp); + ALfilterState_clear(&state->Filter[index].Hp); + + state->Mod.Delay[index].Mask = 0; + state->Mod.Delay[index].Line = NULL; + } - state->Mod.Delay.Mask = 0; - state->Mod.Delay.Line = NULL; state->Mod.Index = 0; state->Mod.Range = 1; state->Mod.Depth = 0.0f; @@ -212,9 +216,9 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Line = NULL; state->DelayTap[0] = 0; state->DelayTap[1] = 0; - state->DecoTap[0] = 0; - state->DecoTap[1] = 0; - state->DecoTap[2] = 0; + state->LateDecoTap[0] = 0; + state->LateDecoTap[1] = 0; + state->LateDecoTap[2] = 0; for(index = 0;index < 4;index++) { @@ -248,23 +252,29 @@ static void ALreverbState_Construct(ALreverbState *state) { for(index = 0;index < MAX_OUTPUT_CHANNELS;index++) { + state->Early.CurrentGain[l][index] = 0.0f; state->Early.PanGain[l][index] = 0.0f; + state->Late.CurrentGain[l][index] = 0.0f; state->Late.PanGain[l][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; + for(l = 0;l < 4;l++) + { + state->Echo.Delay[l].Feedback.Mask = 0; + state->Echo.Delay[l].Feedback.Line = NULL; + state->Echo.Delay[l].Ap.Mask = 0; + state->Echo.Delay[l].Ap.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; + for(l = 0;l < 4;l++) + state->Echo.LpSample[l] = 0.0f; state->Echo.MixCoeff = 0.0f; state->Offset = 0; @@ -322,18 +332,18 @@ static const ALfloat EARLY_LINE_LENGTH[4] = 0.0015f, 0.0045f, 0.0135f, 0.0405f }; -// The lengths of the late all-pass delay lines. -static const ALfloat ALLPASS_LINE_LENGTH[4] = -{ - 0.0151f, 0.0167f, 0.0183f, 0.0200f, -}; - // The lengths of the late cyclical delay lines. static const ALfloat LATE_LINE_LENGTH[4] = { 0.0211f, 0.0311f, 0.0461f, 0.0680f }; +// The lengths of the late all-pass delay lines. +static const ALfloat ALLPASS_LINE_LENGTH[4] = +{ + 0.0151f, 0.0167f, 0.0183f, 0.0200f, +}; + // The late cyclical delay lines have a variable length dependent on the // effect's density parameter (inverted for some reason) and this multiplier. static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; @@ -400,8 +410,9 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) * modulation. */ length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); - totalSamples += CalcLineLength(length, totalSamples, frequency, 1, - &State->Mod.Delay); + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(length, totalSamples, frequency, 1, + &State->Mod.Delay[index]); /* The initial delay is the sum of the reflections and late reverb delays. * The decorrelator length is calculated from the lowest reverb density (a @@ -412,19 +423,17 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) AL_EAXREVERB_MAX_LATE_REVERB_DELAY; length += (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, - MAX_UPDATE_SAMPLES, &State->Delay); + /* Multiply length by 4, since we're storing 4 interleaved channels in the + * main delay line. + */ + totalSamples += CalcLineLength(length*4, totalSamples, frequency, + MAX_UPDATE_SAMPLES*4, &State->Delay); // The early reflection lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, frequency, 0, &State->Early.Delay[index]); - // The late all-pass lines. - for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Late.ApDelay[index]); - // The late delay lines are calculated from the lowest reverb density. for(index = 0;index < 4;index++) { @@ -433,17 +442,25 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) &State->Late.Delay[index]); } + // The late all-pass lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, + frequency, 0, &State->Late.ApDelay[index]); + // The echo all-pass and delay lines. - totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, - frequency, 0, &State->Echo.ApDelay); - totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, - frequency, 0, &State->Echo.Delay); + for(index = 0;index < 4;index++) + { + totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, + frequency, 0, &State->Echo.Delay[index].Ap); + totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, + frequency, 0, &State->Echo.Delay[index].Feedback); + } if(totalSamples != State->TotalSamples) { ALfloat *newBuffer; - TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); + TRACE("New reverb buffer length: %u samples\n", totalSamples); newBuffer = al_calloc(16, sizeof(ALfloat) * totalSamples); if(!newBuffer) return AL_FALSE; @@ -456,13 +473,16 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) RealizeLineOffset(State->SampleBuffer, &State->Delay); for(index = 0;index < 4;index++) { + RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); + + RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay[index].Ap); + RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay[index].Feedback); } - RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); // Clear the sample buffer. for(index = 0;index < State->TotalSamples;index++) @@ -479,18 +499,6 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; - /* HRTF and UHJ will mix to the real output for ambient output. */ - if(Device->Hrtf.Handle || Device->Uhj_Encoder) - { - State->ExtraOut = Device->RealOut.Buffer; - State->ExtraChannels = Device->RealOut.NumChannels; - } - else - { - State->ExtraOut = NULL; - State->ExtraChannels = 0; - } - // Calculate the modulation filter coefficient. Notice that the exponent // is calculated given the current sample rate. This ensures that the // resulting filter response over time is consistent across all sample @@ -688,7 +696,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->DecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; + State->LateDecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; } } @@ -718,7 +726,10 @@ static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; length *= 1.0f + (density * LATE_LINE_MULTIPLIER); - State->Late.DensityGain = CalcDensityGain( + /* To account for each channel being a discrete input, also multiply by + * sqrt(num_channels). + */ + State->Late.DensityGain = 2.0f * CalcDensityGain( CalcDecayCoeff(length, decayTime) ); @@ -783,205 +794,129 @@ static ALvoid UpdateEchoLine(ALfloat echoTime, ALfloat decayTime, ALfloat diffus State->Echo.MixCoeff = echoDepth; } -// Update the early and late 3D panning gains. -static ALvoid UpdateMixedPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) +/* Creates a transform matrix given a reverb vector. This works by creating a + * Z-focus transform, then a rotate transform around X, then Y, to place the + * focal point in the direction of the vector, using the vector length as a + * focus strength. + * + * This isn't technically correct since the vector is supposed to define the + * aperture and not rotate the perceived soundfield, but in practice it's + * probably good enough. + */ +static aluMatrixf GetTransformFromVector(const ALfloat *vec) { - ALfloat DirGains[MAX_OUTPUT_CHANNELS]; - ALfloat coeffs[MAX_AMBI_COEFFS]; + aluMatrixf zfocus, xrot, yrot; + aluMatrixf tmp1, tmp2; ALfloat length; - ALuint i; + ALfloat sa, a; - /* With HRTF or UHJ, the normal output provides a panned reverb channel - * when a non-0-length vector is specified, while the real stereo output - * provides two other "direct" non-panned reverb channels. - */ - memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); - length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Early.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * EarlyGain; - } - else - { - /* Note that EAX Reverb's panning vectors are using right-handed - * coordinates, rather than OpenAL's left-handed coordinates. Negate Z - * to fix this. - */ - ALfloat pan[3] = { - ReflectionsPan[0] / length, - ReflectionsPan[1] / length, - -ReflectionsPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Early.PanGain[3][i] = DirGains[i] * EarlyGain * length; - for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Early.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * EarlyGain * (1.0f-length); - } + length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); - length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Late.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * LateGain; - } - else - { - ALfloat pan[3] = { - LateReverbPan[0] / length, - LateReverbPan[1] / length, - -LateReverbPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Late.PanGain[3][i] = DirGains[i] * LateGain * length; - for(i = 0;i < Device->RealOut.NumChannels;i++) - State->Late.PanGain[i&3][Device->Dry.NumChannels+i] = Gain * LateGain * (1.0f-length); - } -} + /* Define a Z-focus (X in Ambisonics) transform, given the panning vector + * length. + */ + sa = sinf(minf(length, 1.0f) * (F_PI/4.0f)); + aluMatrixfSet(&zfocus, + 1.0f/(1.0f+sa), 0.0f, 0.0f, (sa/(1.0f+sa))/1.732050808f, + 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, + 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, + (sa/(1.0f+sa))*1.732050808f, 0.0f, 0.0f, 1.0f/(1.0f+sa) + ); -static ALvoid UpdateDirectPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) -{ - ALfloat AmbientGains[MAX_OUTPUT_CHANNELS]; - ALfloat DirGains[MAX_OUTPUT_CHANNELS]; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat length; - ALuint i; + /* Define rotation around X (Y in Ambisonics) */ + a = atan2f(vec[1], sqrtf(vec[0]*vec[0] + vec[2]*vec[2])); + aluMatrixfSet(&xrot, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, cosf(a), sinf(a), + 0.0f, 0.0f, -sinf(a), cosf(a) + ); - /* Apply a boost of about 3dB to better match the expected stereo output volume. */ - ComputeAmbientGains(Device->Dry, Gain*1.414213562f, AmbientGains); + /* Define rotation around Y (Z in Ambisonics). NOTE: EFX's reverb vectors + * use a right-handled coordinate system, compared to the rest of OpenAL + * which uses left-handed. This is fixed by negating Z, however it would + * need to also be negated to get a proper Ambisonics angle, thus + * cancelling it out. + */ + a = atan2f(-vec[0], vec[2]); + aluMatrixfSet(&yrot, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, cosf(a), 0.0f, sinf(a), + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, -sinf(a), 0.0f, cosf(a) + ); - memset(State->Early.PanGain, 0, sizeof(State->Early.PanGain)); - length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Early.PanGain[i&3][i] = AmbientGains[i] * EarlyGain; - } - else - { - ALfloat pan[3] = { - ReflectionsPan[0] / length, - ReflectionsPan[1] / length, - -ReflectionsPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Early.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * EarlyGain; - } +#define MATRIX_MULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ + _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ + _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ + } \ +} while(0) + /* Define a matrix that first focuses on Z, then rotates around X then Y to + * focus the output in the direction of the vector. + */ + MATRIX_MULT(tmp1, xrot, zfocus); + MATRIX_MULT(tmp2, yrot, tmp1); +#undef MATRIX_MULT - memset(State->Late.PanGain, 0, sizeof(State->Late.PanGain)); - length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(!(length > FLT_EPSILON)) - { - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Late.PanGain[i&3][i] = AmbientGains[i] * LateGain; - } - else - { - ALfloat pan[3] = { - LateReverbPan[0] / length, - LateReverbPan[1] / length, - -LateReverbPan[2] / length, - }; - length = minf(length, 1.0f); - - CalcDirectionCoeffs(pan, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain, DirGains); - for(i = 0;i < Device->Dry.NumChannels;i++) - State->Late.PanGain[i&3][i] = lerp(AmbientGains[i], DirGains[i], length) * LateGain; - } + return tmp2; } +// Update the early and late 3D panning gains. static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) { - static const ALfloat PanDirs[4][3] = { - { -0.707106781f, 0.0f, -0.707106781f }, /* Front left */ - { 0.707106781f, 0.0f, -0.707106781f }, /* Front right */ - { 0.707106781f, 0.0f, 0.707106781f }, /* Back right */ - { -0.707106781f, 0.0f, 0.707106781f } /* Back left */ - }; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat gain[4]; - ALfloat length; + /* Converts early reflections A-Format to B-Format (transposed). */ + static const aluMatrixf EarlyA2B = {{ + { 0.8660254038f, 0.8660254038f, 0.8660254038f, 0.8660254038f }, + { 0.8660254038f, 0.8660254038f, -0.8660254038f, -0.8660254038f }, + { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f }, + { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f } + }}; + /* Converts late reverb A-Format to B-Format (transposed). */ + static const aluMatrixf LateA2B = {{ + { 0.8660254038f, -0.8660254038f, 0.8660254038f, 0.8660254038f }, + { 0.8660254038f, -0.8660254038f, -0.8660254038f, -0.8660254038f }, + { 0.8660254038f, 0.8660254038f, 0.8660254038f, -0.8660254038f }, + { 0.8660254038f, 0.8660254038f, -0.8660254038f, 0.8660254038f } +/* { 0.8660254038f, 1.2247448714f, 0.0f, 0.8660254038f }, + { 0.8660254038f, 0.0f, -1.2247448714f, -0.8660254038f }, + { 0.8660254038f, 0.0f, 1.2247448714f, -0.8660254038f }, + { 0.8660254038f, -1.2247448714f, 0.0f, 0.8660254038f }*/ + }}; + aluMatrixf transform, rot; ALuint i; - /* sqrt(0.5) would be the gain scaling when the panning vector is 0. This - * also equals sqrt(2/4), a nice gain scaling for the four virtual points - * producing an "ambient" response. + STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; + + /* Note: Both _m2 and _res are transposed. */ +#define MATRIX_MULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ + _res.m[col][row] = _m1.m[row][0]*_m2.m[col][0] + _m1.m[row][1]*_m2.m[col][1] + \ + _m1.m[row][2]*_m2.m[col][2] + _m1.m[row][3]*_m2.m[col][3]; \ + } \ +} while(0) + /* Create a matrix that first converts A-Format to B-Format, then rotates + * the B-Format soundfield according to the panning vector. */ - gain[0] = gain[1] = gain[2] = gain[3] = 0.707106781f; - length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); - if(length > 1.0f) - { - ALfloat pan[3] = { - ReflectionsPan[0] / length, - ReflectionsPan[1] / length, - -ReflectionsPan[2] / length, - }; - for(i = 0;i < 4;i++) - { - ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); - } - } - else if(length > FLT_EPSILON) - { - for(i = 0;i < 4;i++) - { - ALfloat dotp = ReflectionsPan[0]*PanDirs[i][0] + ReflectionsPan[1]*PanDirs[i][1] + - -ReflectionsPan[2]*PanDirs[i][2]; - gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); - } - } - for(i = 0;i < 4;i++) - { - CalcDirectionCoeffs(PanDirs[i], 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain*EarlyGain*gain[i], - State->Early.PanGain[i]); - } - - gain[0] = gain[1] = gain[2] = gain[3] = 0.707106781f; - length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); - if(length > 1.0f) - { - ALfloat pan[3] = { - LateReverbPan[0] / length, - LateReverbPan[1] / length, - -LateReverbPan[2] / length, - }; - for(i = 0;i < 4;i++) - { - ALfloat dotp = pan[0]*PanDirs[i][0] + pan[1]*PanDirs[i][1] + pan[2]*PanDirs[i][2]; - gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); - } - } - else if(length > FLT_EPSILON) - { - for(i = 0;i < 4;i++) - { - ALfloat dotp = LateReverbPan[0]*PanDirs[i][0] + LateReverbPan[1]*PanDirs[i][1] + - -LateReverbPan[2]*PanDirs[i][2]; - gain[i] = sqrtf(clampf(dotp*0.5f + 0.5f, 0.0f, 1.0f)); - } - } - for(i = 0;i < 4;i++) - { - CalcDirectionCoeffs(PanDirs[i], 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, Gain*LateGain*gain[i], - State->Late.PanGain[i]); - } + rot = GetTransformFromVector(ReflectionsPan); + MATRIX_MULT(transform, rot, EarlyA2B); + memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputeFirstOrderGains(Device->FOAOut, transform.m[i], Gain*EarlyGain, State->Early.PanGain[i]); + + rot = GetTransformFromVector(LateReverbPan); + MATRIX_MULT(transform, rot, LateA2B); + memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputeFirstOrderGains(Device->FOAOut, transform.m[i], Gain*LateGain, State->Late.PanGain[i]); +#undef MATRIX_MULT } static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) @@ -990,6 +925,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device ALfloat lfscale, hfscale, hfRatio; ALfloat gain, gainlf, gainhf; ALfloat cw, x, y; + ALuint i; if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) State->IsEax = AL_TRUE; @@ -999,12 +935,26 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device // Calculate the master filters hfscale = props->Reverb.HFReference / frequency; gainhf = maxf(props->Reverb.GainHF, 0.0001f); - ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, + ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); lfscale = props->Reverb.LFReference / frequency; gainlf = maxf(props->Reverb.GainLF, 0.0001f); - ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, + ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); + for(i = 1;i < 4;i++) + { + State->Filter[i].Lp.a1 = State->Filter[0].Lp.a1; + State->Filter[i].Lp.a2 = State->Filter[0].Lp.a2; + State->Filter[i].Lp.b0 = State->Filter[0].Lp.b0; + State->Filter[i].Lp.b1 = State->Filter[0].Lp.b1; + State->Filter[i].Lp.b2 = State->Filter[0].Lp.b2; + + State->Filter[i].Hp.a1 = State->Filter[0].Hp.a1; + State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; + State->Filter[i].Hp.b0 = State->Filter[0].Hp.b0; + State->Filter[i].Hp.b1 = State->Filter[0].Hp.b1; + State->Filter[i].Hp.b2 = State->Filter[0].Hp.b2; + } // Update the modulator line. UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, @@ -1045,22 +995,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; // Update early and late 3D panning. - if(Device->Hrtf.Handle || Device->Uhj_Encoder) - UpdateMixedPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, - props->Reverb.ReflectionsGain, - props->Reverb.LateReverbGain, State); - else if(Device->AmbiDecoder || (Device->FmtChans >= DevFmtAmbi1 && - Device->FmtChans <= DevFmtAmbi3)) - Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, - props->Reverb.ReflectionsGain, - props->Reverb.LateReverbGain, State); - else - UpdateDirectPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, - props->Reverb.ReflectionsGain, - props->Reverb.LateReverbGain, State); + Update3DPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, gain, + props->Reverb.ReflectionsGain, + props->Reverb.LateReverbGain, State); } @@ -1079,45 +1017,64 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) Delay->Line[offset&Delay->Mask] = in; } -// Given some input samples, this function produces modulation for the late -// reverb. -static void EAXModulation(ALreverbState *State, ALuint offset, ALfloat*restrict dst, const ALfloat*restrict src, ALuint todo) +static inline ALfloat DelayLineInOut(DelayLine *Delay, ALuint offset, ALuint outoffset, ALfloat in) { - ALfloat sinus, frac, fdelay; - ALfloat out0, out1; - ALuint delay, i; + Delay->Line[offset&Delay->Mask] = in; + return Delay->Line[(offset-outoffset)&Delay->Mask]; +} +static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, ALuint todo) +{ + ALfloat sinus, range; + ALuint index, i; + + index = State->Mod.Index; + range = State->Mod.Filter; for(i = 0;i < todo;i++) { /* 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_TAU * State->Mod.Index / State->Mod.Range); + sinus = 1.0f - cosf(F_TAU * index / State->Mod.Range); /* Step the modulation index forward, keeping it bound to its range. */ - State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + index = (index+1) % 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 * small parameter changes. */ - State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, - State->Mod.Coeff); + range = lerp(range, State->Mod.Depth, State->Mod.Coeff); + + /* Calculate the read offset with fraction. */ + delays[i] = range*sinus; + } + State->Mod.Index = index; + State->Mod.Filter = range; +} + +// Given some input samples, this function produces modulation for the late +// reverb. +static void EAXModulation(DelayLine *ModDelay, ALuint offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, ALuint todo) +{ + ALfloat frac, fdelay; + ALfloat out0, out1; + ALuint delay, i; - /* Calculate the read offset and fraction between it and the next + for(i = 0;i < todo;i++) + { + /* Separate the integer offset and fraction between it and the next * sample. */ - frac = modff(State->Mod.Filter*sinus, &fdelay); + frac = modff(delays[i], &fdelay); delay = fastf2u(fdelay); - /* Add the incoming sample to the delay line first, so a 0 delay gets - * the incoming sample. + /* Add the incoming sample to the delay line, and get the two samples + * crossed by the offset delay. */ - DelayLineIn(&State->Mod.Delay, offset, src[i]); - /* Get the two samples crossed by the offset delay */ - out0 = DelayLineOut(&State->Mod.Delay, offset - delay); - out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); + out0 = DelayLineInOut(ModDelay, offset, delay, src[i]); + out1 = DelayLineOut(ModDelay, offset - delay - 1); offset++; /* The output is obtained by linearly interpolating the two samples @@ -1127,9 +1084,10 @@ static void EAXModulation(ALreverbState *State, ALuint offset, ALfloat*restrict } } -// Given some input sample, this function produces four-channel outputs for the -// early reflections. -static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +/* Given some input samples from the main delay line, this function produces + * four-channel outputs for the early reflections. + */ +static ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat d[4], v, f[4]; ALuint i; @@ -1138,11 +1096,11 @@ static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat { ALuint offset = State->Offset+i; - // Obtain the decayed results of each early delay line. - d[0] = DelayLineOut(&State->Early.Delay[0], offset-State->Early.Offset[0]) * State->Early.Coeff[0]; - d[1] = DelayLineOut(&State->Early.Delay[1], offset-State->Early.Offset[1]) * State->Early.Coeff[1]; - d[2] = DelayLineOut(&State->Early.Delay[2], offset-State->Early.Offset[2]) * State->Early.Coeff[2]; - d[3] = DelayLineOut(&State->Early.Delay[3], offset-State->Early.Offset[3]) * State->Early.Coeff[3]; + /* Obtain the first reflection samples from the main delay line. */ + f[0] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 0); + f[1] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 1); + f[2] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 2); + f[3] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 3); /* The following uses a lossless scattering junction from waveguide * theory. It actually amounts to a householder mixing matrix, which @@ -1155,29 +1113,27 @@ static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat * --- * i=1 */ - v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; - // The junction is loaded with the input here. - v += DelayLineOut(&State->Delay, offset-State->DelayTap[0]); - - // Calculate the feed values for the delay lines. - f[0] = v - d[0]; - f[1] = v - d[1]; - f[2] = v - d[2]; - f[3] = v - d[3]; - - // Re-feed the delay lines. - DelayLineIn(&State->Early.Delay[0], offset, f[0]); - DelayLineIn(&State->Early.Delay[1], offset, f[1]); - DelayLineIn(&State->Early.Delay[2], offset, f[2]); - DelayLineIn(&State->Early.Delay[3], offset, f[3]); - - /* Output the results of the junction for all four channels with a - * constant attenuation of 0.5. + v = (f[0] + f[1] + f[2] + f[3]) * 0.5f; + + /* Calculate the feed values for the early delay lines. */ + d[0] = v - f[0]; + d[1] = v - f[1]; + d[2] = v - f[2]; + d[3] = v - f[3]; + + /* Feed the early delay lines, and load the delayed results. */ + d[0] = DelayLineInOut(&State->Early.Delay[0], offset, State->Early.Offset[0], d[0]); + d[1] = DelayLineInOut(&State->Early.Delay[1], offset, State->Early.Offset[1], d[1]); + d[2] = DelayLineInOut(&State->Early.Delay[2], offset, State->Early.Offset[2], d[2]); + d[3] = DelayLineInOut(&State->Early.Delay[3], offset, State->Early.Offset[3], d[3]); + + /* Output the initial reflection taps and the results of the delayed + * and decayed junction for all four channels. */ - out[0][i] = f[0] * 0.5f; - out[1][i] = f[1] * 0.5f; - out[2][i] = f[2] * 0.5f; - out[3][i] = f[3] * 0.5f; + out[0][i] = f[0] + d[0]*State->Early.Coeff[0]; + out[1][i] = f[1] + d[1]*State->Early.Coeff[1]; + out[2][i] = f[2] + d[2]*State->Early.Coeff[2]; + out[3][i] = f[3] + d[3]*State->Early.Coeff[3]; } } @@ -1215,7 +1171,7 @@ static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALflo // Given four decorrelated input samples, this function produces four-channel // output for the late reverb. -static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +static ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat d[4], f[4]; ALuint offset; @@ -1230,10 +1186,10 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res for(i = 0;i < tmp_todo;i++) { /* Obtain four decorrelated input samples. */ - f[0] = DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * State->Late.DensityGain; - f[1] = DelayLineOut(&State->Delay, offset-State->DecoTap[0]) * State->Late.DensityGain; - f[2] = DelayLineOut(&State->Delay, offset-State->DecoTap[1]) * State->Late.DensityGain; - f[3] = DelayLineOut(&State->Delay, offset-State->DecoTap[2]) * State->Late.DensityGain; + f[0] = DelayLineOut(&State->Delay, (offset-State->DelayTap[1])*4 + 0) * State->Late.DensityGain; + f[1] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[0])*4 + 1) * State->Late.DensityGain; + f[2] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[1])*4 + 2) * State->Late.DensityGain; + f[3] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[2])*4 + 3) * State->Late.DensityGain; /* Add the decayed results of the cyclical delay lines, then pass * the results through the low-pass filters. @@ -1243,13 +1199,13 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; - /* This is where the feed-back cycles from line 0 to 1 to 3 to 2 + /* This is where the feed-back cycles from line 0 to 3 to 1 to 2 * and back to 0. */ d[0] = LateLowPassInOut(State, 2, f[2]); - d[1] = LateLowPassInOut(State, 0, f[0]); - d[2] = LateLowPassInOut(State, 3, f[3]); - d[3] = LateLowPassInOut(State, 1, f[1]); + d[1] = LateLowPassInOut(State, 3, f[3]); + d[2] = LateLowPassInOut(State, 1, f[1]); + d[3] = LateLowPassInOut(State, 0, f[0]); /* To help increase diffusion, run each line through an all-pass * filter. When there is no diffusion, the shortest all-pass filter @@ -1322,57 +1278,58 @@ static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*res // Given an input sample, this function mixes echo into the four-channel late // reverb. -static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALfloat out[MAX_UPDATE_SAMPLES]; ALfloat feed; ALuint offset; - ALuint i; + ALuint c, i; - offset = State->Offset; - for(i = 0;i < todo;i++) + for(c = 0;c < 4;c++) { - // Get the latest attenuated echo sample for output. - feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) * - State->Echo.Coeff; - - // Write the output. - out[i] = State->Echo.MixCoeff * feed; - - // Mix the energy-attenuated input with the output and pass it through - // the echo low-pass filter. - feed += DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * - State->Echo.DensityGain; - feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); - State->Echo.LpSample = feed; - - // Then the echo all-pass filter. - feed = AllpassInOut(&State->Echo.ApDelay, offset-State->Echo.ApOffset, - offset, feed, State->Echo.ApFeedCoeff, - State->Echo.ApCoeff); - - // Feed the delay with the mixed and filtered sample. - DelayLineIn(&State->Echo.Delay, offset, feed); - offset++; + offset = State->Offset; + for(i = 0;i < todo;i++) + { + // Get the latest attenuated echo sample for output. + feed = DelayLineOut(&State->Echo.Delay[c].Feedback, offset-State->Echo.Offset) * + State->Echo.Coeff; + + // Write the output. + late[c][i] += State->Echo.MixCoeff * feed; + + // Mix the energy-attenuated input with the output and pass it through + // the echo low-pass filter. + feed += DelayLineOut(&State->Delay, (offset-State->DelayTap[1])*4 + c) * + State->Echo.DensityGain; + feed = lerp(feed, State->Echo.LpSample[c], State->Echo.LpCoeff); + State->Echo.LpSample[c] = feed; + + // Then the echo all-pass filter. + feed = AllpassInOut(&State->Echo.Delay[c].Ap, offset-State->Echo.ApOffset, + offset, feed, State->Echo.ApFeedCoeff, + State->Echo.ApCoeff); + + // Feed the delay with the mixed and filtered sample. + DelayLineIn(&State->Echo.Delay[c].Feedback, offset, feed); + offset++; + } } - - // Mix the output into the late reverb channels. - for(i = 0;i < todo;i++) late[0][i] += out[i]; - for(i = 0;i < todo;i++) late[1][i] += out[i]; - for(i = 0;i < todo;i++) late[2][i] += out[i]; - for(i = 0;i < todo;i++) late[3][i] += out[i]; } // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALvoid VerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALuint i; + ALuint i, c; - // Low-pass filter the incoming samples (use the early buffer as temp storage). - ALfilterState_process(&State->LpFilter, &early[0][0], input, todo); - for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, early[0][i]); + for(c = 0;c < 4;c++) + { + /* Low-pass filter the incoming samples (use the early buffer as temp + * storage). + */ + ALfilterState_process(&State->Filter[c].Lp, &early[0][0], input[c], todo); + for(i = 0;i < todo;i++) + DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[0][i]); + } // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); @@ -1386,19 +1343,27 @@ static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat * // Perform the EAX reverb pass on a given input sample, resulting in four- // channel output. -static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALuint i; + ALuint i, c; - /* Perform any modulation on the input (use the early buffer as temp storage). */ - EAXModulation(State, State->Offset, &early[0][0], input, todo); - /* Band-pass the incoming samples */ - ALfilterState_process(&State->LpFilter, &early[1][0], &early[0][0], todo); - ALfilterState_process(&State->HpFilter, &early[2][0], &early[1][0], todo); + /* Perform any modulation on the input (use the early and late buffers as + * temp storage). + */ + CalcModulationDelays(State, &late[0][0], todo); + for(c = 0;c < 4;c++) + { + EAXModulation(&State->Mod.Delay[c], State->Offset, &late[0][0], + &early[0][0], input[c], todo); - // Feed the initial delay line. - for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, early[2][i]); + /* Band-pass the incoming samples */ + ALfilterState_process(&State->Filter[c].Lp, &early[1][0], &early[0][0], todo); + ALfilterState_process(&State->Filter[c].Hp, &early[2][0], &early[1][0], todo); + + /* Feed the initial delay line. */ + for(i = 0;i < todo;i++) + DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[2][i]); + } // Calculate the early reflection from the first delay tap. EarlyReflection(State, todo, early); @@ -1441,11 +1406,18 @@ static void DoMix(const ALfloat *restrict src, ALfloat (*dst)[BUFFERSIZE], ALuin current_gains[c] = gains[c].Current; } -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { + static const aluMatrixf B2A = {{ + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f } + }}; + ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint base, c; + ALuint base, c, c2, i; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) @@ -1453,42 +1425,53 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - VerbPass(State, todo, &SamplesIn[base], early, late); + /* Convert B-Foramt to A-Format for processing (could use the row + * mixers). + */ + memset(afmt, 0, sizeof(*afmt)*4); + for(c = 0;c < 4;c++) + { + for(c2 = 0;c2 < MAX_EFFECT_CHANNELS;c2++) + { + for(i = 0;i < todo;i++) + afmt[c][i] += SamplesIn[c2][base+i] * B2A.m[c][c2]; + } + } + + VerbPass(State, todo, afmt, early, late); + /* Mix the A-Format results to output, implicitly converting back to + * B-Format. + */ for(c = 0;c < 4;c++) { DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo ); - if(State->ExtraChannels > 0) - DoMix(early[c], State->ExtraOut, State->ExtraChannels, - State->Early.PanGain[c]+NumChannels, - State->Early.CurrentGain[c]+NumChannels, delta, base, - SamplesToDo-base, todo - ); } for(c = 0;c < 4;c++) { DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], State->Late.CurrentGain[c], delta, base, SamplesToDo, todo ); - if(State->ExtraChannels > 0) - DoMix(late[c], State->ExtraOut, State->ExtraChannels, - State->Late.PanGain[c]+NumChannels, - State->Late.CurrentGain[c]+NumChannels, delta, base, - SamplesToDo-base, todo - ); } base += todo; } } -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { + static const aluMatrixf B2A = {{ + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f } + }}; + ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint base, c; + ALuint base, c, c2, i; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) @@ -1496,31 +1479,29 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - EAXVerbPass(State, todo, &SamplesIn[base], early, late); + memset(afmt, 0, 4*MAX_UPDATE_SAMPLES*sizeof(float)); + for(c = 0;c < 4;c++) + { + for(c2 = 0;c2 < MAX_EFFECT_CHANNELS;c2++) + { + for(i = 0;i < todo;i++) + afmt[c][i] += SamplesIn[c2][base+i] * B2A.m[c][c2]; + } + } + + EAXVerbPass(State, todo, afmt, early, late); for(c = 0;c < 4;c++) { DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo ); - if(State->ExtraChannels > 0) - DoMix(early[c], State->ExtraOut, State->ExtraChannels, - State->Early.PanGain[c]+NumChannels, - State->Early.CurrentGain[c]+NumChannels, delta, base, - SamplesToDo-base, todo - ); } for(c = 0;c < 4;c++) { DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], State->Late.CurrentGain[c], delta, base, SamplesToDo, todo ); - if(State->ExtraChannels > 0) - DoMix(late[c], State->ExtraOut, State->ExtraChannels, - State->Late.PanGain[c]+NumChannels, - State->Late.CurrentGain[c]+NumChannels, delta, base, - SamplesToDo-base, todo - ); } base += todo; @@ -1530,9 +1511,9 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); + ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn[0], SamplesOut, NumChannels); + ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); } -- cgit v1.2.3 From a0e4696f5578fa42ec0ac7ac47141bf41fb727ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Oct 2016 11:20:01 -0700 Subject: Include wtypes.h for defining Windows' property keys --- Alc/backends/mmdevapi.c | 1 + Alc/helpers.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 7cad93a9..3882b08f 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/Alc/helpers.c b/Alc/helpers.c index d4b44ced..0a6982e9 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -62,6 +62,7 @@ DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xa DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); #ifdef HAVE_MMDEVAPI +#include #include #include DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -- cgit v1.2.3 From 9349ee9002c5cf2cd7906c9444292285529a91e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Oct 2016 16:25:43 -0700 Subject: Make some pointer-to-array parameters const --- Alc/ALu.c | 13 ++++++------- Alc/bformatdec.c | 35 ++++++++++++++--------------------- Alc/bformatdec.h | 6 +++--- Alc/mixer.c | 13 +++++++++++++ Alc/mixer_c.c | 4 ++-- Alc/mixer_defs.h | 15 +++++++++------ Alc/mixer_neon.c | 6 +++--- Alc/mixer_sse.c | 6 +++--- OpenAL32/Include/alMain.h | 42 ++++++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/alu.h | 5 +++-- 10 files changed, 98 insertions(+), 47 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 13aff5d9..5bcf039e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1489,10 +1489,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) slot = slotroot; while(slot) { - const ALeffectslot *cslot = slot; - ALeffectState *state = cslot->Params.EffectState; - V(state,process)(SamplesToDo, cslot->WetBuffer, state->OutBuffer, - state->OutChannels); + ALeffectState *state = slot->Params.EffectState; + V(state,process)(SamplesToDo, SAFE_CONST(ALfloatBUFFERSIZE*,slot->WetBuffer), + state->OutBuffer, state->OutChannels); slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } @@ -1540,19 +1539,19 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { if(device->Dry.Buffer != device->FOAOut.Buffer) bformatdec_upSample(device->AmbiDecoder, - device->Dry.Buffer, device->FOAOut.Buffer, + device->Dry.Buffer, SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), device->FOAOut.NumChannels, SamplesToDo ); bformatdec_process(device->AmbiDecoder, device->RealOut.Buffer, device->RealOut.NumChannels, - device->Dry.Buffer, SamplesToDo + SAFE_CONST(ALfloatBUFFERSIZE*,device->Dry.Buffer), SamplesToDo ); } else if(device->AmbiUp) { ambiup_process(device->AmbiUp, device->RealOut.Buffer, device->RealOut.NumChannels, - device->FOAOut.Buffer, SamplesToDo + SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo ); } else if(device->Uhj_Encoder) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 0722c061..2aab4ed8 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -161,19 +161,6 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS]; -static inline RowMixerFunc SelectRowMixer(void) -{ -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_SSE; -#endif -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_Neon; -#endif - return MixRow_C; -} - static RowMixerFunc MixMatrixRow = MixRow_C; @@ -495,7 +482,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, } -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { ALuint chan, i; @@ -512,10 +499,12 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], - dec->SamplesHF, dec->NumChannels, SamplesToDo + SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0, + SamplesToDo ); MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], - dec->SamplesLF, dec->NumChannels, SamplesToDo + SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0, + SamplesToDo ); if(dec->Delay[chan].Length > 0) @@ -553,7 +542,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, - dec->NumChannels, SamplesToDo); + dec->NumChannels, 0, SamplesToDo); if(dec->Delay[chan].Length > 0) { @@ -584,7 +573,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU } -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) { ALuint i, j; @@ -608,7 +597,9 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B /* Now write each band to the output. */ for(j = 0;j < dec->NumChannels;j++) MixMatrixRow(OutBuffer[j], dec->UpSampler.Gains[i][j], - dec->Samples, FB_Max, SamplesToDo); + SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0, + SamplesToDo + ); } } @@ -659,7 +650,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) } } -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) { ALuint i, j; @@ -672,6 +663,8 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[ for(j = 0;j < OutChannels;j++) MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j], - ambiup->Samples, FB_Max, SamplesToDo); + SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0, + SamplesToDo + ); } } diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 433603dd..e78d89a7 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -17,10 +17,10 @@ int bformatdec_getOrder(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags); /* Decodes the ambisonic input to the given output channels. */ -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); /* Up-samples a first-order input to the decoder's configuration. */ -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); /* Stand-alone first-order upsampler. Kept here because it shares some stuff @@ -30,7 +30,7 @@ struct AmbiUpsampler *ambiup_alloc(); void ambiup_free(struct AmbiUpsampler *ambiup); void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); /* Band splitter. Splits a signal into two phase-matching frequency bands. */ diff --git a/Alc/mixer.c b/Alc/mixer.c index 2736920e..864e2395 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -79,6 +79,19 @@ MixerFunc SelectMixer(void) return Mix_C; } +RowMixerFunc SelectRowMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_SSE; +#endif +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_Neon; +#endif + return MixRow_C; +} + static inline HrtfMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_SSE diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index c74729a8..3e726df5 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -208,7 +208,7 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B * transform. And as the matrices are more or less static once set up, no * stepping is necessary. */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) { ALuint c, i; @@ -219,6 +219,6 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data) continue; for(i = 0;i < BufferSize;i++) - OutBuffer[i] += data[c][i] * gain; + OutBuffer[i] += data[c][InPos+i] * gain; } } diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 1572ac36..05e6f964 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -31,8 +31,9 @@ void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALu ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], - ALuint InChans, ALuint BufferSize); +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint InPos, ALuint BufferSize); /* SSE mixers */ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, @@ -45,8 +46,9 @@ void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, A ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], - ALuint InChans, ALuint BufferSize); +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint InPos, ALuint BufferSize); /* SSE resamplers */ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size) @@ -92,7 +94,8 @@ void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], - ALuint InChans, ALuint BufferSize); +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint InPos, ALuint BufferSize); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 73395aeb..8c96aef1 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -144,7 +144,7 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer } } -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) { float32x4_t gain4; ALuint c; @@ -159,12 +159,12 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict da gain4 = vdupq_n_f32(gain); for(;BufferSize-pos > 3;pos += 4) { - const float32x4_t val4 = vld1q_f32(&data[c][pos]); + const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); dry4 = vmlaq_f32(dry4, val4, gain4); vst1q_f32(&OutBuffer[pos], dry4); } for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][pos]*gain; + OutBuffer[pos] += data[c][InPos+pos]*gain; } } diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 1ac78f9c..24e0e545 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -262,7 +262,7 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) } } -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint BufferSize) +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) { __m128 gain4; ALuint c; @@ -277,12 +277,12 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALfloat (*restrict dat gain4 = _mm_set1_ps(gain); for(;BufferSize-pos > 3;pos += 4) { - const __m128 val4 = _mm_load_ps(&data[c][pos]); + const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); _mm_store_ps(&OutBuffer[pos], dry4); } for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][pos]*gain; + OutBuffer[pos] += data[c][InPos+pos]*gain; } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index af599227..837e1082 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -128,6 +128,48 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif +#ifdef __GNUC__ +/* Because of a long-standing deficiency in C, you're not allowed to implicitly + * cast a pointer-to-type-array to a pointer-to-const-type-array. For example, + * + * int (*ptr)[10]; + * const int (*cptr)[10] = ptr; + * + * is not allowed and most compilers will generate noisy warnings about + * incompatible types, even though it just makes the array elements const. + * Clang will allow it if you make the array type a typedef, like this: + * + * typedef int int10[10]; + * int10 *ptr; + * const int10 *cptr = ptr; + * + * however GCC does not and still issues the incompatible type warning. The + * "proper" way to fix it is to add an explicit cast for the constified type, + * but that removes the vast majority of otherwise useful type-checking you'd + * get, and runs the risk of improper casts if types are later changed. Leaving + * it non-const can also be an issue if you use it as a function parameter, and + * happen to have a const type as input (and also reduce the capabilities of + * the compiler to better optimize the function). + * + * So to work around the problem, we use a macro. The macro first assigns the + * incoming variable to the specified non-const type to ensure it's the correct + * type, then casts the variable as the desired constified type. Very ugly, but + * I'd rather not have hundreds of lines of warnings because I want to tell the + * compiler that some array(s) can't be changed by the code, or have lots of + * error-prone casts. + */ +#define SAFE_CONST(T, var) __extension__({ \ + T _tmp = (var); \ + (const T)_tmp; \ +}) +#else +/* Non-GNU-compatible compilers have to use a straight cast with no extra + * checks, due to the lack of multi-statement expressions. + */ +#define SAFE_CONST(T, var) ((const T)(var)) +#endif + + typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 29cb00fb..3ced9628 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -162,8 +162,8 @@ typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, - ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint BufferSize); + const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, + ALuint InPos, ALuint BufferSize); typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, const MixHrtfParams *hrtfparams, @@ -265,6 +265,7 @@ enum HrtfRequestMode { void aluInitMixer(void); MixerFunc SelectMixer(void); +RowMixerFunc SelectRowMixer(void); /* aluInitRenderer * -- cgit v1.2.3 From 422f065809d4a93ce3294f50661ad877d8f97486 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Oct 2016 16:42:28 -0700 Subject: Use the row mixer functions for the B-to-A-Format conversion --- Alc/effects/reverb.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f506486e..ecc8b8e6 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -39,11 +39,13 @@ static MixerFunc MixSamples = Mix_C; +static RowMixerFunc MixRowSamples = MixRow_C; static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT; static void init_mixfunc(void) { MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); } @@ -1417,7 +1419,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint base, c, c2, i; + ALuint base, c; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) @@ -1430,13 +1432,9 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples */ memset(afmt, 0, sizeof(*afmt)*4); for(c = 0;c < 4;c++) - { - for(c2 = 0;c2 < MAX_EFFECT_CHANNELS;c2++) - { - for(i = 0;i < todo;i++) - afmt[c][i] += SamplesIn[c2][base+i] * B2A.m[c][c2]; - } - } + MixRowSamples(afmt[c], B2A.m[c], + SamplesIn, MAX_EFFECT_CHANNELS, base, todo + ); VerbPass(State, todo, afmt, early, late); @@ -1471,7 +1469,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALuint base, c, c2, i; + ALuint base, c; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) @@ -1481,13 +1479,9 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, memset(afmt, 0, 4*MAX_UPDATE_SAMPLES*sizeof(float)); for(c = 0;c < 4;c++) - { - for(c2 = 0;c2 < MAX_EFFECT_CHANNELS;c2++) - { - for(i = 0;i < todo;i++) - afmt[c][i] += SamplesIn[c2][base+i] * B2A.m[c][c2]; - } - } + MixRowSamples(afmt[c], B2A.m[c], + SamplesIn, MAX_EFFECT_CHANNELS, base, todo + ); EAXVerbPass(State, todo, afmt, early, late); -- cgit v1.2.3 From bb6fba2183a2f12d47a81c761936bc7b86dab848 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Oct 2016 17:19:47 -0700 Subject: Properly check for struct timespec --- CMakeLists.txt | 8 ++++++++ include/threads.h | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4b4b626..cf6d7ca6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ INCLUDE(CheckSymbolExists) INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckTypeSize) +include(CheckStructHasMember) include(CheckFileOffsetBits) include(GNUInstallDirs) @@ -178,6 +179,13 @@ IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() +# Check if we have a proper timespec declaration +CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_sec time.h HAVE_STRUCT_TIMESPEC) +IF(HAVE_STRUCT_TIMESPEC) + # Define it here so we don't have to include config.h for it + ADD_DEFINITIONS("-DHAVE_STRUCT_TIMESPEC") +ENDIF() + # Some systems may need libatomic for C11 atomic functions to work SET(OLD_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) SET(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES} atomic) diff --git a/include/threads.h b/include/threads.h index a11405f7..c2848ee7 100644 --- a/include/threads.h +++ b/include/threads.h @@ -33,17 +33,11 @@ typedef void (*altss_dtor_t)(void*); #include -#if !defined(_TIMESPEC_DEFINED) && !(defined(_MSC_VER) && (_MSC_VER >= 1900)) -#define _TIMESPEC_DEFINED +#ifndef HAVE_STRUCT_TIMESPEC struct timespec { time_t tv_sec; long tv_nsec; }; - -struct itimerspec { - struct timespec it_interval; - struct timespec it_value; -}; #endif typedef DWORD althrd_t; -- cgit v1.2.3 From 06639b8250f102cb729e3fe49f6ade9b949944fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Oct 2016 13:21:49 -0700 Subject: Better pack the late reverb low- and all-pass variables --- Alc/effects/reverb.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ecc8b8e6..525d7f30 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -125,9 +125,11 @@ typedef struct ALreverbState { ALfloat MixCoeff; // Late reverb has 4 parallel all-pass filters. - ALfloat ApCoeff[4]; - DelayLine ApDelay[4]; - ALuint ApOffset[4]; + struct { + ALfloat Coeff; + DelayLine Delay; + ALuint Offset; + } Ap[4]; // In addition to 4 cyclical delay lines. ALfloat Coeff[4]; @@ -135,8 +137,10 @@ typedef struct ALreverbState { ALuint Offset[4]; // The cyclical delay lines are 1-pole low-pass filtered. - ALfloat LpCoeff[4]; - ALfloat LpSample[4]; + struct { + ALfloat Sample; + ALfloat Coeff; + } Lp[4]; // The gain for each output channel based on 3D panning. ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; @@ -236,18 +240,18 @@ static void ALreverbState_Construct(ALreverbState *state) 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.Ap[index].Coeff = 0.0f; + state->Late.Ap[index].Delay.Mask = 0; + state->Late.Ap[index].Delay.Line = NULL; + state->Late.Ap[index].Offset = 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.Lp[index].Sample = 0.0f; + state->Late.Lp[index].Coeff = 0.0f; } for(l = 0;l < 4;l++) @@ -447,7 +451,7 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) // The late all-pass lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Late.ApDelay[index]); + frequency, 0, &State->Late.Ap[index].Delay); // The echo all-pass and delay lines. for(index = 0;index < 4;index++) @@ -479,7 +483,7 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); - RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.Ap[index].Delay); RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay[index].Ap); @@ -513,7 +517,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev for(index = 0;index < 4;index++) { State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * frequency); - State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * frequency); + State->Late.Ap[index].Offset = fastf2u(ALLPASS_LINE_LENGTH[index] * frequency); } // The echo all-pass filter line length is static, so its offset only @@ -741,7 +745,7 @@ static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, for(index = 0;index < 4;index++) { // Calculate the gain (coefficient) for each all-pass line. - State->Late.ApCoeff[index] = CalcDecayCoeff( + State->Late.Ap[index].Coeff = CalcDecayCoeff( ALLPASS_LINE_LENGTH[index], decayTime ); @@ -756,7 +760,7 @@ static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); // Calculate the damping coefficient for each low-pass filter. - State->Late.LpCoeff[index] = CalcDampingCoeff( + State->Late.Lp[index].Coeff = CalcDampingCoeff( hfRatio, length, decayTime, State->Late.Coeff[index], cw ); @@ -1157,17 +1161,17 @@ static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint in // All-pass input/output routine for late reverb. static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in) { - return AllpassInOut(&State->Late.ApDelay[index], - offset - State->Late.ApOffset[index], + return AllpassInOut(&State->Late.Ap[index].Delay, + offset - State->Late.Ap[index].Offset, offset, in, State->Late.ApFeedCoeff, - State->Late.ApCoeff[index]); + State->Late.Ap[index].Coeff); } // Low-pass filter input/output routine for late reverb. 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; + in = lerp(in, State->Late.Lp[index].Sample, State->Late.Lp[index].Coeff); + State->Late.Lp[index].Sample = in; return in; } -- cgit v1.2.3 From 1e1a8837f8a595639aa8933889b892766379d111 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Oct 2016 15:09:14 -0700 Subject: Update a comment about using row mixers --- Alc/effects/reverb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 525d7f30..17d2fa84 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1431,9 +1431,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - /* Convert B-Foramt to A-Format for processing (could use the row - * mixers). - */ + /* Convert B-Foramt to A-Format for processing. */ memset(afmt, 0, sizeof(*afmt)*4); for(c = 0;c < 4;c++) MixRowSamples(afmt[c], B2A.m[c], -- cgit v1.2.3 From 9b8f36b75879d2fee652c9ff81e1cb5db665a5c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Oct 2016 20:33:45 -0700 Subject: Pass current and target gains directly for mixing --- Alc/effects/reverb.c | 57 ++++++--------------------- Alc/mixer.c | 102 ++++++++----------------------------------------- Alc/mixer_c.c | 17 +++++---- Alc/mixer_defs.h | 9 +++-- Alc/mixer_neon.c | 17 +++++---- Alc/mixer_sse.c | 17 +++++---- OpenAL32/Include/alu.h | 5 ++- 7 files changed, 67 insertions(+), 157 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 17d2fa84..46883104 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1384,33 +1384,6 @@ static ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict State->Offset += todo; } -static void DoMix(const ALfloat *restrict src, ALfloat (*dst)[BUFFERSIZE], ALuint num_chans, - const ALfloat *restrict target_gains, ALfloat *restrict current_gains, - ALfloat delta, ALuint offset, ALuint total_rem, ALuint todo) -{ - MixGains gains[MAX_OUTPUT_CHANNELS]; - ALuint c; - - for(c = 0;c < num_chans;c++) - { - ALfloat diff; - gains[c].Target = target_gains[c]; - gains[c].Current = current_gains[c]; - diff = gains[c].Target - gains[c].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - gains[c].Step = diff * delta; - else - { - gains[c].Current = gains[c].Target; - gains[c].Step = 0.0f; - } - } - - MixSamples(src, num_chans, dst, gains, total_rem, offset, todo); - - for(c = 0;c < num_chans;c++) - current_gains[c] = gains[c].Current; -} static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { @@ -1428,7 +1401,6 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); /* Convert B-Foramt to A-Format for processing. */ @@ -1444,17 +1416,15 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples * B-Format. */ for(c = 0;c < 4;c++) - { - DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], - State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo + MixSamples(early[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo ); - } for(c = 0;c < 4;c++) - { - DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], - State->Late.CurrentGain[c], delta, base, SamplesToDo, todo + MixSamples(late[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo ); - } base += todo; } @@ -1476,7 +1446,6 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - const ALfloat delta = 1.0f / (ALfloat)(SamplesToDo-base); ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); memset(afmt, 0, 4*MAX_UPDATE_SAMPLES*sizeof(float)); @@ -1488,17 +1457,15 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, EAXVerbPass(State, todo, afmt, early, late); for(c = 0;c < 4;c++) - { - DoMix(early[c], SamplesOut, NumChannels, State->Early.PanGain[c], - State->Early.CurrentGain[c], delta, base, SamplesToDo-base, todo + MixSamples(early[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo ); - } for(c = 0;c < 4;c++) - { - DoMix(late[c], SamplesOut, NumChannels, State->Late.PanGain[c], - State->Late.CurrentGain[c], delta, base, SamplesToDo, todo + MixSamples(late[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo ); - } base += todo; } diff --git a/Alc/mixer.c b/Alc/mixer.c index 864e2395..a0132e0f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -393,6 +393,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALuint NumChannels; ALuint SampleSize; ALint64 DataSize64; + ALuint Counter; ALuint IrSize; ALuint chan, send, j; @@ -411,22 +412,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : ResampleSamples); + Counter = voice->Moving ? SamplesToDo : 0; OutPos = 0; do { ALuint SrcBufferSize, DstBufferSize; - ALuint Counter; - ALfloat Delta; - - if(!voice->Moving) - { - Counter = 0; - Delta = 0.0f; - } - else - { - Counter = SamplesToDo - OutPos; - Delta = 1.0f / (ALfloat)Counter; - } /* Figure out how many buffer samples will be needed */ DataSize64 = SamplesToDo-OutPos; @@ -575,42 +564,12 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ); if(!voice->IsHrtf) { - ALfloat *restrict currents = parms->Gains.Current; - const ALfloat *targets = parms->Gains.Target; - MixGains gains[MAX_OUTPUT_CHANNELS]; - if(!Counter) - { - for(j = 0;j < voice->DirectOut.Channels;j++) - { - gains[j].Target = targets[j]; - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - else - { - for(j = 0;j < voice->DirectOut.Channels;j++) - { - ALfloat diff; - gains[j].Target = targets[j]; - gains[j].Current = currents[j]; - diff = gains[j].Target - gains[j].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = diff * Delta; - else - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - } - + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); MixSamples(samples, voice->DirectOut.Channels, voice->DirectOut.Buffer, - gains, Counter, OutPos, DstBufferSize); - - for(j = 0;j < voice->DirectOut.Channels;j++) - currents[j] = gains[j].Current; + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize + ); } else { @@ -630,19 +589,20 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } else { + ALfloat delta = 1.0f / (ALfloat)Counter; ALfloat coeffdiff; ALint delaydiff; for(j = 0;j < IrSize;j++) { coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; - hrtfparams.Steps.Coeffs[j][0] = coeffdiff * Delta; + hrtfparams.Steps.Coeffs[j][0] = coeffdiff * delta; coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1]; - hrtfparams.Steps.Coeffs[j][1] = coeffdiff * Delta; + hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta; } delaydiff = (ALint)(parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]); - hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * Delta); + hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta); delaydiff = (ALint)(parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]); - hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * Delta); + hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta); } hrtfparams.Target = &parms->Hrtf.Target; hrtfparams.Current = &parms->Hrtf.Current; @@ -660,9 +620,6 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam for(send = 0;send < Device->NumAuxSends;send++) { SendParams *parms = &voice->Chan[chan].Send[send]; - ALfloat *restrict currents = parms->Gains.Current; - const ALfloat *targets = parms->Gains.Target; - MixGains gains[MAX_OUTPUT_CHANNELS]; const ALfloat *samples; if(!voice->SendOut[send].Buffer) @@ -674,39 +631,11 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ); if(!Counter) - { - for(j = 0;j < voice->SendOut[send].Channels;j++) - { - gains[j].Target = targets[j]; - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - else - { - for(j = 0;j < voice->SendOut[send].Channels;j++) - { - ALfloat diff; - gains[j].Target = targets[j]; - gains[j].Current = currents[j]; - diff = gains[j].Target - gains[j].Current; - if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = diff * Delta; - else - { - gains[j].Current = gains[j].Target; - gains[j].Step = 0.0f; - } - } - } - - MixSamples(samples, - voice->SendOut[send].Channels, voice->SendOut[send].Buffer, - gains, Counter, OutPos, DstBufferSize + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); + MixSamples(samples, voice->SendOut[send].Channels, voice->SendOut[send].Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); - - for(j = 0;j < voice->SendOut[send].Channels;j++) - currents[j] = gains[j].Current; } } /* Update positions */ @@ -716,6 +645,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos += DstBufferSize; voice->Offset += DstBufferSize; + Counter = maxu(DstBufferSize, Counter) - DstBufferSize; /* Handle looping sources */ while(1) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 3e726df5..a75ad002 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -172,17 +172,20 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize) { - ALfloat gain, step; + ALfloat gain, delta, step; ALuint c; + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + for(c = 0;c < OutChans;c++) { ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 0.0f && Counter > 0) + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) { ALuint minsize = minu(BufferSize, Counter); for(;pos < minsize;pos++) @@ -191,8 +194,8 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B gain += step; } if(pos == Counter) - gain = Gains[c].Target; - Gains[c].Current = gain; + gain = TargetGains[c]; + CurrentGains[c] = gain; } if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 05e6f964..df449197 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -30,7 +30,8 @@ void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALu ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize); void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize); @@ -45,7 +46,8 @@ void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, A ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALuint BufferSize); void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize); void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize); @@ -93,7 +95,8 @@ void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALuint BufferSize); void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize); void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize); diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 8c96aef1..6b506357 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -76,18 +76,21 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize) { - ALfloat gain, step; + ALfloat gain, delta, step; float32x4_t gain4; ALuint c; + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + for(c = 0;c < OutChans;c++) { ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 0.0f && Counter > 0) + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) { ALuint minsize = minu(BufferSize, Counter); /* Mix with applying gain steps in aligned multiples of 4. */ @@ -120,8 +123,8 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer gain += step; } if(pos == Counter) - gain = Gains[c].Target; - Gains[c].Current = gain; + gain = TargetGains[c]; + CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ minsize = minu(BufferSize, (pos+3)&~3); diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 24e0e545..6d18a638 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -192,18 +192,21 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) + ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize) { - ALfloat gain, step; + ALfloat gain, delta, step; __m128 gain4; ALuint c; + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + for(c = 0;c < OutChans;c++) { ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 0.0f && Counter > 0) + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) { ALuint minsize = minu(BufferSize, Counter); /* Mix with applying gain steps in aligned multiples of 4. */ @@ -238,8 +241,8 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) gain += step; } if(pos == Counter) - gain = Gains[c].Target; - Gains[c].Current = gain; + gain = TargetGains[c]; + CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ minsize = minu(BufferSize, (pos+3)&~3); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3ced9628..47d4fab0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -159,8 +159,9 @@ typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, ); typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, - ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, - ALuint Counter, ALuint OutPos, ALuint BufferSize); + ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, + const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, + ALuint BufferSize); typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize); -- cgit v1.2.3 From 965e91c702db7b79fe70124634902712fd19b4ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Oct 2016 20:35:14 -0700 Subject: Remove an unused struct --- OpenAL32/Include/alu.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 47d4fab0..09c8c238 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -110,12 +110,6 @@ enum ActiveFilters { }; -typedef struct MixGains { - ALfloat Current; - ALfloat Step; - ALfloat Target; -} MixGains; - typedef struct MixHrtfParams { const HrtfParams *Target; HrtfParams *Current; -- cgit v1.2.3 From 76cd6797b7e58272e4e5268f1461f209045b9de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Oct 2016 01:39:18 -0700 Subject: Add some more 'restrict' keywords --- Alc/mixer.c | 2 +- Alc/mixer_c.c | 17 +++++++++-------- Alc/mixer_defs.h | 46 ++++++++++++++++++++++++++-------------------- Alc/mixer_sse.c | 5 +++-- Alc/mixer_sse2.c | 5 +++-- Alc/mixer_sse3.c | 10 ++++++---- Alc/mixer_sse41.c | 15 +++++++++------ OpenAL32/Include/alu.h | 2 +- 8 files changed, 58 insertions(+), 44 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index a0132e0f..b1f79d05 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -41,7 +41,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size); +extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size); alignas(16) union ResamplerCoeffs ResampleCoeffs; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index a75ad002..6ef818c7 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -8,17 +8,17 @@ #include "alAuxEffectSlot.h" -static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac)) +static inline ALfloat point32(const ALfloat *restrict vals, ALuint UNUSED(frac)) { return vals[0]; } -static inline ALfloat lerp32(const ALfloat *vals, ALuint frac) +static inline ALfloat lerp32(const ALfloat *restrict vals, ALuint frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac) +static inline ALfloat fir4_32(const ALfloat *restrict vals, ALuint frac) { return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); } -static inline ALfloat fir8_32(const ALfloat *vals, ALuint frac) +static inline ALfloat fir8_32(const ALfloat *restrict vals, ALuint frac) { return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); } -const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *src, ALuint UNUSED(frac), +const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *restrict src, ALuint UNUSED(frac), ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples) { #if defined(HAVE_SSE) || defined(HAVE_NEON) @@ -32,7 +32,7 @@ const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat #define DECL_TEMPLATE(Sampler) \ const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \ - const ALfloat *src, ALuint frac, ALuint increment, \ + const ALfloat *restrict src, ALuint frac, ALuint increment, \ ALfloat *restrict dst, ALuint numsamples) \ { \ ALuint i; \ @@ -54,8 +54,9 @@ DECL_TEMPLATE(fir8_32) #undef DECL_TEMPLATE -const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, - ALuint increment, ALfloat *restrict dst, ALuint dstlen) +const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint dstlen) { const ALfloat *fil, *scd, *phd, *spd; const ALfloat sf = state->sf; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index df449197..24916002 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -12,12 +12,12 @@ struct MixHrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); /* C mixers */ @@ -53,7 +53,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALuint InPos, ALuint BufferSize); /* SSE resamplers */ -inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size) +inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size) { ALuint i; @@ -67,23 +67,29 @@ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_a } } -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac, +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); -const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); +const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); -const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); -const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); +const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); -const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); -const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); +const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples); /* Neon mixers */ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 6d18a638..f5e21e23 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -12,8 +12,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac, - ALuint increment, ALfloat *restrict dst, ALuint dstlen) +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint dstlen) { const __m128 sf4 = _mm_set1_ps(state->sf); const ALuint m = state->m; diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index 004dba9e..22a18ef3 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -27,8 +27,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 1b946461..66005e53 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -31,8 +31,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); @@ -95,8 +96,9 @@ const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index ed49447d..7a4db6cf 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -28,8 +28,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); @@ -84,8 +85,9 @@ const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); @@ -151,8 +153,9 @@ const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALf return dst; } -const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALuint increment, ALfloat *restrict dst, + ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 09c8c238..ae8645fa 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -149,7 +149,7 @@ typedef struct SendParams { typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, - const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen + const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen ); typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, -- cgit v1.2.3 From f826f8684280c722a19ccb1814a0ec0ae4b83ded Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Oct 2016 19:45:48 -0700 Subject: Decorrelate the early reflection inputs --- Alc/effects/reverb.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 46883104..7dfa37d1 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -97,6 +97,7 @@ typedef struct ALreverbState { /* There are actually 4 decorrelator taps, but the first occurs at the late * reverb tap. */ + ALuint EarlyDecoTap[3]; ALuint LateDecoTap[3]; struct { @@ -222,6 +223,9 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Line = NULL; state->DelayTap[0] = 0; state->DelayTap[1] = 0; + state->EarlyDecoTap[0] = 0; + state->EarlyDecoTap[1] = 0; + state->EarlyDecoTap[2] = 0; state->LateDecoTap[0] = 0; state->LateDecoTap[1] = 0; state->LateDecoTap[2] = 0; @@ -324,9 +328,10 @@ static const ALfloat MODULATION_FILTER_CONST = 100000.0f; // the echo effect. It uses the following line length (in seconds). static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; -// Input into the late reverb is decorrelated between four channels. Their -// timings are dependent on a fraction and multiplier. See the -// UpdateDecorrelator() routine for the calculations involved. +/* Input into the early reflections and late reverb are decorrelated between + * four channels. Their timings are dependent on a fraction and multiplier. See + * the UpdateDecorrelator() routine for the calculations involved. + */ static const ALfloat DECO_FRACTION = 0.15f; static const ALfloat DECO_MULTIPLIER = 2.0f; @@ -691,15 +696,19 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat ALuint index; ALfloat length; - /* The late reverb inputs are decorrelated to smooth the reverb tail and - * reduce harsh echos. The first tap occurs immediately, while the - * remaining taps are delayed by multiples of a fraction of the smallest - * cyclical delay time. + /* The early reflections and late reverb inputs are decorrelated to provide + * time-varying reflections, smooth out the reverb tail, and reduce harsh + * echos. The first tap occurs immediately, while the remaining taps are + * delayed by multiples of a fraction of the smallest cyclical delay time. * * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay */ for(index = 0;index < 3;index++) { + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * + EARLY_LINE_LENGTH[0]; + State->EarlyDecoTap[index] = fastf2u(length * frequency) + State->DelayTap[0]; + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); State->LateDecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; @@ -1104,9 +1113,9 @@ static ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restr /* Obtain the first reflection samples from the main delay line. */ f[0] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 0); - f[1] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 1); - f[2] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 2); - f[3] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 3); + f[1] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[0])*4 + 1); + f[2] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[1])*4 + 2); + f[3] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[2])*4 + 3); /* The following uses a lossless scattering junction from waveguide * theory. It actually amounts to a householder mixing matrix, which -- cgit v1.2.3 From 698eddbb0caf6ba77d644e7de5da01ad6687ee68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Oct 2016 20:05:16 -0700 Subject: Better sort the main delay line taps --- Alc/effects/reverb.c | 99 +++++++++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 60 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7dfa37d1..d8dd14f3 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -90,15 +90,11 @@ typedef struct ALreverbState { /* Core delay line (early reflections and late reverb tap from this). */ DelayLine Delay; - /* The tap points for the initial delay. First tap goes to early + /* The tap points for the initial delay. First set go to early * reflections, second to late reverb. */ - ALuint DelayTap[2]; - /* There are actually 4 decorrelator taps, but the first occurs at the late - * reverb tap. - */ - ALuint EarlyDecoTap[3]; - ALuint LateDecoTap[3]; + ALuint EarlyDelayTap[4]; + ALuint LateDelayTap[4]; struct { // Early reflections are done with 4 delay lines. @@ -221,14 +217,10 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Mask = 0; state->Delay.Line = NULL; - state->DelayTap[0] = 0; - state->DelayTap[1] = 0; - state->EarlyDecoTap[0] = 0; - state->EarlyDecoTap[1] = 0; - state->EarlyDecoTap[2] = 0; - state->LateDecoTap[0] = 0; - state->LateDecoTap[1] = 0; - state->LateDecoTap[2] = 0; + for(index = 0;index < 4;index++) + state->EarlyDelayTap[index] = 0; + for(index = 0;index < 4;index++) + state->LateDelayTap[index] = 0; for(index = 0;index < 4;index++) { @@ -330,7 +322,7 @@ static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; /* Input into the early reflections and late reverb are decorrelated between * four channels. Their timings are dependent on a fraction and multiplier. See - * the UpdateDecorrelator() routine for the calculations involved. + * the UpdateDelayLine() routine for the calculations involved. */ static const ALfloat DECO_FRACTION = 0.15f; static const ALfloat DECO_MULTIPLIER = 2.0f; @@ -669,12 +661,27 @@ static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequenc 2.0f * frequency; } -// Update the offsets for the initial effect delay line. -static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State) +// Update the offsets for the main effect delay line. +static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat density, ALuint frequency, ALreverbState *State) { - // Calculate the initial delay taps. - State->DelayTap[0] = fastf2u(earlyDelay * frequency); - State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); + ALfloat length; + ALuint i; + + State->EarlyDelayTap[0] = fastf2u(earlyDelay * frequency); + for(i = 1;i < 4;i++) + { + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * + EARLY_LINE_LENGTH[0]; + State->EarlyDelayTap[i] = fastf2u(length * frequency) + State->EarlyDelayTap[0]; + } + + State->LateDelayTap[0] = fastf2u((earlyDelay + lateDelay) * frequency); + for(i = 1;i < 4;i++) + { + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * + LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); + State->LateDelayTap[i] = fastf2u(length * frequency) + State->LateDelayTap[0]; + } } // Update the early reflections mix and line coefficients. @@ -690,31 +697,6 @@ static ALvoid UpdateEarlyLines(ALfloat lateDelay, ALreverbState *State) lateDelay); } -// Update the offsets for the decorrelator line. -static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State) -{ - ALuint index; - ALfloat length; - - /* The early reflections and late reverb inputs are decorrelated to provide - * time-varying reflections, smooth out the reverb tail, and reduce harsh - * echos. The first tap occurs immediately, while the remaining taps are - * delayed by multiples of a fraction of the smallest cyclical delay time. - * - * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay - */ - for(index = 0;index < 3;index++) - { - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * - EARLY_LINE_LENGTH[0]; - State->EarlyDecoTap[index] = fastf2u(length * frequency) + State->DelayTap[0]; - - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * - LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->LateDecoTap[index] = fastf2u(length * frequency) + State->DelayTap[1]; - } -} - // Update the late reverb mix, line lengths, and line coefficients. static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { @@ -975,12 +957,9 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, frequency, State); - // Update the initial effect delay. + // Update the main effect delay. UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, - frequency, State); - - // Update the decorrelator. - UpdateDecorrelator(props->Reverb.Density, frequency, State); + props->Reverb.Density, frequency, State); // Update the early lines. UpdateEarlyLines(props->Reverb.LateReverbDelay, State); @@ -1112,10 +1091,10 @@ static ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restr ALuint offset = State->Offset+i; /* Obtain the first reflection samples from the main delay line. */ - f[0] = DelayLineOut(&State->Delay, (offset-State->DelayTap[0])*4 + 0); - f[1] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[0])*4 + 1); - f[2] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[1])*4 + 2); - f[3] = DelayLineOut(&State->Delay, (offset-State->EarlyDecoTap[2])*4 + 3); + f[0] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[0])*4 + 0); + f[1] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[1])*4 + 1); + f[2] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[2])*4 + 2); + f[3] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[3])*4 + 3); /* The following uses a lossless scattering junction from waveguide * theory. It actually amounts to a householder mixing matrix, which @@ -1201,10 +1180,10 @@ static ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict o for(i = 0;i < tmp_todo;i++) { /* Obtain four decorrelated input samples. */ - f[0] = DelayLineOut(&State->Delay, (offset-State->DelayTap[1])*4 + 0) * State->Late.DensityGain; - f[1] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[0])*4 + 1) * State->Late.DensityGain; - f[2] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[1])*4 + 2) * State->Late.DensityGain; - f[3] = DelayLineOut(&State->Delay, (offset-State->LateDecoTap[2])*4 + 3) * State->Late.DensityGain; + f[0] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[0])*4 + 0) * State->Late.DensityGain; + f[1] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[1])*4 + 1) * State->Late.DensityGain; + f[2] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[2])*4 + 2) * State->Late.DensityGain; + f[3] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[3])*4 + 3) * State->Late.DensityGain; /* Add the decayed results of the cyclical delay lines, then pass * the results through the low-pass filters. @@ -1313,7 +1292,7 @@ static ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late // Mix the energy-attenuated input with the output and pass it through // the echo low-pass filter. - feed += DelayLineOut(&State->Delay, (offset-State->DelayTap[1])*4 + c) * + feed += DelayLineOut(&State->Delay, (offset-State->LateDelayTap[0])*4 + c) * State->Echo.DensityGain; feed = lerp(feed, State->Echo.LpSample[c], State->Echo.LpCoeff); State->Echo.LpSample[c] = feed; -- cgit v1.2.3 From 4bb6b9589f730be4068012b33f0c4323c3794816 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Oct 2016 00:37:47 -0700 Subject: Don't interpolate between nearest HRIRs It still fades between HRIRs when it changes, but now it selects the nearest one instead of blending the nearest four. Due to the minimum-phase nature of the HRIRs, interpolating between delays lead to some oddities which are exasperated by the fading (and the fading is needed to avoid clicks and pops, and smooth out changes). --- Alc/ALu.c | 8 ++--- Alc/hrtf.c | 113 +++++++++++++++++++++---------------------------------------- Alc/hrtf.h | 2 +- 3 files changed, 43 insertions(+), 80 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 5bcf039e..cc01f336 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -657,7 +657,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } /* Get the static HRIR coefficients and delays for this channel. */ - GetLerpedHrtfCoeffs(Device->Hrtf.Handle, + GetHrtfCoeffs(Device->Hrtf.Handle, chans[c].elevation, chans[c].angle, 0.0f, DryGain, voice->Chan[c].Direct.Hrtf.Target.Coeffs, voice->Chan[c].Direct.Hrtf.Target.Delay @@ -1172,9 +1172,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro spread = asinf(radius / Distance) * 2.0f; /* Get the HRIR coefficients and delays. */ - GetLerpedHrtfCoeffs(Device->Hrtf.Handle, ev, az, spread, DryGain, - voice->Chan[0].Direct.Hrtf.Target.Coeffs, - voice->Chan[0].Direct.Hrtf.Target.Delay); + GetHrtfCoeffs(Device->Hrtf.Handle, ev, az, spread, DryGain, + voice->Chan[0].Direct.Hrtf.Target.Coeffs, + voice->Chan[0].Direct.Hrtf.Target.Delay); CalcDirectionCoeffs(dir, spread, coeffs); diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 87a119a0..02889736 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -55,111 +55,74 @@ static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/; static struct Hrtf *LoadedHrtfs = NULL; -/* Calculate the elevation indices given the polar elevation in radians. - * This will return two indices between 0 and (evcount - 1) and an - * interpolation factor between 0.0 and 1.0. + +/* Calculate the elevation index given the polar elevation in radians. This + * will return an index between 0 and (evcount - 1). Assumes the FPU is in + * round-to-zero mode. */ -static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *evmu) +static ALuint CalcEvIndex(ALuint evcount, ALfloat ev) { ev = (F_PI_2 + ev) * (evcount-1) / F_PI; - evidx[0] = fastf2u(ev); - evidx[1] = minu(evidx[0] + 1, evcount-1); - *evmu = ev - evidx[0]; + return minu(fastf2u(ev + 0.5f), evcount-1); } -/* Calculate the azimuth indices given the polar azimuth in radians. This - * will return two indices between 0 and (azcount - 1) and an interpolation - * factor between 0.0 and 1.0. +/* Calculate the azimuth index given the polar azimuth in radians. This will + * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to- + * zero mode. */ -static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu) +static ALuint CalcAzIndex(ALuint azcount, ALfloat az) { az = (F_TAU + az) * azcount / F_TAU; - azidx[0] = fastf2u(az) % azcount; - azidx[1] = (azidx[0] + 1) % azcount; - *azmu = az - floorf(az); + return fastf2u(az + 0.5f) % azcount; } -/* Calculates static HRIR coefficients and delays for the given polar - * elevation and azimuth in radians. Linear interpolation is used to - * increase the apparent resolution of the HRIR data set. The coefficients - * are also normalized and attenuated by the specified gain. +/* Calculates static HRIR coefficients and delays for the given polar elevation + * and azimuth in radians. The coefficients are normalized and attenuated by + * the specified gain. */ -void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) { - ALuint evidx[2], lidx[4], ridx[4]; - ALfloat mu[3], blend[4]; + ALuint evidx, azidx, lidx, ridx; + ALuint azcount, evoffset; ALfloat dirfact; ALuint i; dirfact = 1.0f - (spread / F_TAU); - /* Claculate elevation indices and interpolation factor. */ - CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]); + /* Claculate elevation index. */ + evidx = CalcEvIndex(Hrtf->evCount, elevation); + azcount = Hrtf->azCount[evidx]; + evoffset = Hrtf->evOffset[evidx]; - for(i = 0;i < 2;i++) - { - ALuint azcount = Hrtf->azCount[evidx[i]]; - ALuint evoffset = Hrtf->evOffset[evidx[i]]; - ALuint azidx[2]; - - /* Calculate azimuth indices and interpolation factor for this elevation. */ - CalcAzIndices(azcount, azimuth, azidx, &mu[i]); - - /* Calculate a set of linear HRIR indices for left and right channels. */ - lidx[i*2 + 0] = evoffset + azidx[0]; - lidx[i*2 + 1] = evoffset + azidx[1]; - ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount); - ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount); - } + /* Calculate azimuth index. */ + azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth); - /* Calculate 4 blending weights for 2D bilinear interpolation. */ - blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); - blend[1] = ( mu[0]) * (1.0f-mu[2]); - blend[2] = (1.0f-mu[1]) * ( mu[2]); - blend[3] = ( mu[1]) * ( mu[2]); + /* Calculate the HRIR indices for left and right channels. */ + lidx = evoffset + azidx; + ridx = evoffset + ((azcount-azidx) % azcount); - /* Calculate the HRIR delays using linear interpolation. */ - delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + - Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + - Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; + /* Calculate the HRIR delays. */ + delays[0] = fastf2u(Hrtf->delays[lidx]*dirfact + 0.5f) << HRTFDELAY_BITS; + delays[1] = fastf2u(Hrtf->delays[ridx]*dirfact + 0.5f) << HRTFDELAY_BITS; /* Calculate the sample offsets for the HRIR indices. */ - lidx[0] *= Hrtf->irSize; - lidx[1] *= Hrtf->irSize; - lidx[2] *= Hrtf->irSize; - lidx[3] *= Hrtf->irSize; - ridx[0] *= Hrtf->irSize; - ridx[1] *= Hrtf->irSize; - ridx[2] *= Hrtf->irSize; - ridx[3] *= Hrtf->irSize; - - /* Calculate the normalized and attenuated HRIR coefficients using linear - * interpolation when there is enough gain to warrant it. Zero the + lidx *= Hrtf->irSize; + ridx *= Hrtf->irSize; + + /* Calculate the normalized and attenuated HRIR coefficients. Zero the * coefficients if gain is too low. */ if(gain > 0.0001f) { - ALfloat c; + gain /= 32767.0f; i = 0; - c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + - Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); - c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + - Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); - + coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact)*gain; + coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact)*gain; for(i = 1;i < Hrtf->irSize;i++) { - c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + - Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); - c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + - Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); + coeffs[i][0] = Hrtf->coeffs[lidx+i]*gain * dirfact; + coeffs[i][1] = Hrtf->coeffs[ridx+i]*gain * dirfact; } } else diff --git a/Alc/hrtf.h b/Alc/hrtf.h index d3ecfc3c..ebba0d50 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -40,7 +40,7 @@ void FreeHrtfs(void); vector_HrtfEntry EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_HrtfEntry *list); -void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); /* Produces HRTF filter coefficients for decoding B-Format. The result will * have ACN ordering with N3D normalization. NumChannels must currently be 4, -- cgit v1.2.3 From 16ed117d71aee8e0ee02b6e2873dacae15056d04 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Oct 2016 01:33:33 -0700 Subject: Restore a comment that was accidentally deleted --- Alc/effects/reverb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index d8dd14f3..f2d5b718 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -667,6 +667,15 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat den ALfloat length; ALuint i; + /* The early reflections and late reverb inputs are decorrelated to provide + * time-varying reflections, smooth out the reverb tail, and reduce harsh + * echoes. The first tap occurs immediately, while the remaining taps are + * delayed by multiples of a fraction of the smallest cyclical delay time. + * + * offset[index] = (FRACTION (MULTIPLIER^(index-1))) smallest_delay + * + * for index = 1...max_lines + */ State->EarlyDelayTap[0] = fastf2u(earlyDelay * frequency); for(i = 1;i < 4;i++) { -- cgit v1.2.3 From 2668da696c0fb18668977e5e6f9aeed56f1abf29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Oct 2016 22:12:48 -0700 Subject: Round the early and late delay tap sample offsets --- Alc/effects/reverb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f2d5b718..54587f7e 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -676,20 +676,20 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat den * * for index = 1...max_lines */ - State->EarlyDelayTap[0] = fastf2u(earlyDelay * frequency); + State->EarlyDelayTap[0] = fastf2u(earlyDelay*frequency + 0.5f); for(i = 1;i < 4;i++) { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * EARLY_LINE_LENGTH[0]; - State->EarlyDelayTap[i] = fastf2u(length * frequency) + State->EarlyDelayTap[0]; + State->EarlyDelayTap[i] = fastf2u(length*frequency + 0.5f) + State->EarlyDelayTap[0]; } - State->LateDelayTap[0] = fastf2u((earlyDelay + lateDelay) * frequency); + State->LateDelayTap[0] = fastf2u((earlyDelay + lateDelay)*frequency + 0.5f); for(i = 1;i < 4;i++) { length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->LateDelayTap[i] = fastf2u(length * frequency) + State->LateDelayTap[0]; + State->LateDelayTap[i] = fastf2u(length*frequency + 0.5f) + State->LateDelayTap[0]; } } -- cgit v1.2.3 From 9120e7987ee8b416c50486dfc292b5aefc72b0d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Oct 2016 06:27:01 -0700 Subject: Cleanup and clarify a bit of the ambisonic docs --- docs/ambisonics.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt index 77ec8ef7..4e4d8faa 100644 --- a/docs/ambisonics.txt +++ b/docs/ambisonics.txt @@ -74,8 +74,8 @@ accuracy over what simple pan-pot could provide. This is effectively what the high-quality mode option does, when given an appropriate decoder configuation for the playback channel layout. 3D rendering -is done to an ambisonic buffer, which is later decoded for output utilizing the -benefits available to ambisonic processing. +and effect mixing is done to an ambisonic buffer, which is later decoded for +output utilizing the benefits available to ambisonic processing. The basic, non-high-quality, renderer uses similar principles, however it skips the frequency-dependent processing (so low frequency sounds are treated the @@ -88,14 +88,14 @@ quality for less memory and processor usage. In addition to providing good support for surround sound playback, Ambisonics also has benefits with stereo output. 2-channel UHJ is a stereo-compatible format that encodes some surround sound information using a wide-band 90-degree -phase shift filter. It works by taking a B-Format signal, then deriving a -frontal stereo mix with some of the rear sounds filtered in with it. Although -the result is not as good as 3-channel (2D) B-Format, it has the distinct -advantage of only using 2 channels and being compatible with stereo output. -This means it will sound just fine when played as-is through a normal stereo -device, or it may optionally be fed to a properly configured surround sound -receiver which can extract the encoded information and restore some of the -original surround sound signal. +phase shift filter. It works by taking a B-Format signal, and deriving a +frontal stereo mix with the rear sounds attenuated and filtered in with it. +Although the result is not as good as 3-channel (2D) B-Format, it has the +distinct advantage of only using 2 channels and being compatible with stereo +output. This means it will sound just fine when played as-is through a normal +stereo device, or it may optionally be fed to a properly configured surround +sound receiver which can extract the encoded information and restore some of +the original surround sound signal. What Are Its Limitations? -- cgit v1.2.3 From d01d30ad5e4fb430b0d36fb3eaa3b7f13aa8f65d Mon Sep 17 00:00:00 2001 From: septag Date: Sun, 30 Oct 2016 14:18:45 +0330 Subject: Added cmake support for dsound and windows 8/10 SDKs --- cmake/FindDSound.cmake | 60 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/cmake/FindDSound.cmake b/cmake/FindDSound.cmake index 0ddf98aa..3fd26ed6 100644 --- a/cmake/FindDSound.cmake +++ b/cmake/FindDSound.cmake @@ -8,19 +8,63 @@ # DSOUND_LIBRARY - the dsound library # +# DSOUND_INCLUDE_DIR +file(GLOB DXSDK_INCLUDE_DIRS LIST_DIRECTORIES TRUE "C:/Program Files (x86)/Windows Kits/10/Include/*") +if (DXSDK_INCLUDE_DIRS) + list(SORT DXSDK_INCLUDE_DIRS) + list(REVERSE DXSDK_INCLUDE_DIRS) +endif() + find_path(DSOUND_INCLUDE_DIR - NAMES dsound.h - PATHS "${DXSDK_DIR}" - PATH_SUFFIXES include - DOC "The DirectSound include directory" + NAMES + "dsound.h" + PATHS + "${DXSDK_DIR}" + ${DXSDK_INCLUDE_DIRS} + "C:/Program Files (x86)/Windows Kits/8.0" + "C:/Program Files (x86)/Windows Kits/8.1" + PATH_SUFFIXES + Include + um + Include/um + DOC + "The DirectSound include directory" ) +# DSOUND_LIBRARY +if(CMAKE_CL_64) + set (DirectX_ARCHITECTURE x64) +else() + set (DirectX_ARCHITECTURE x86) +endif() + +file(GLOB DXSDK_LIB_DIRS LIST_DIRECTORIES TRUE "C:/Program Files (x86)/Windows Kits/10/Lib/*") +if (DXSDK_LIB_DIRS) + list(SORT DXSDK_LIB_DIRS) + list(REVERSE DXSDK_LIB_DIRS) +endif() + find_library(DSOUND_LIBRARY NAMES dsound - PATHS "${DXSDK_DIR}" - PATH_SUFFIXES lib lib/x86 lib/x64 - DOC "The DirectSound library" -) + DOC "The DirectSound library") +if (NOT DSOUND_LIBRARY) + find_library(DSOUND_LIBRARY + NAMES dsound + PATHS + "${DXSDK_DIR}" + ${DXSDK_LIB_DIRS} + "C:/Program Files (x86)/Windows Kits/8.0" + "C:/Program Files (x86)/Windows Kits/8.1" + PATH_SUFFIXES + Lib + Lib/${DirectX_ARCHITECTURE} + um/${DirectX_ARCHITECTURE} + Lib/win8/um/${DirectX_ARCHITECTURE} + Lib/winv6.3/um/${DirectX_ARCHITECTURE} + DOC + "The DirectSound library" + ) +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DSound -- cgit v1.2.3 From e46a92c220444db505d19e62c0d3e4ef886fb8ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Oct 2016 08:45:09 -0700 Subject: Workaround some systems having an ECHO macro --- OpenAL32/Include/alEffect.h | 20 ++++++++++---------- OpenAL32/alEffect.c | 4 ++-- OpenAL32/alExtension.c | 22 +++++++++++----------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index b97b0147..80f029a9 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -10,16 +10,16 @@ extern "C" { struct ALeffect; enum { - EAXREVERB = 0, - REVERB, - CHORUS, - COMPRESSOR, - DISTORTION, - ECHO, - EQUALIZER, - FLANGER, - MODULATOR, - DEDICATED, + AL__EAXREVERB = 0, + AL__REVERB, + AL__CHORUS, + AL__COMPRESSOR, + AL__DISTORTION, + AL__ECHO, + AL__EQUALIZER, + AL__FLANGER, + AL__MODULATOR, + AL__DEDICATED, MAX_EFFECTS }; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 65a4dcb6..6761e661 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -667,9 +667,9 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect) return; } - if(!DisabledEffects[EAXREVERB]) + if(!DisabledEffects[AL__EAXREVERB]) InitEffectParams(effect, AL_EFFECT_EAXREVERB); - else if(!DisabledEffects[REVERB]) + else if(!DisabledEffects[AL__REVERB]) InitEffectParams(effect, AL_EFFECT_REVERB); else InitEffectParams(effect, AL_EFFECT_NULL); diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 1a559d9c..c85e9007 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -36,17 +36,17 @@ const struct EffectList EffectList[] = { - { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, - { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, - { "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 }, + { "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, + { "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, + { "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, + { "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, + { "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, + { "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, + { "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, + { "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, + { "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, + { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, { NULL, 0, NULL, (ALenum)0 } }; -- cgit v1.2.3 From a44f4c2fcb3cb22737a46b8a2419ff7bd1ce3555 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Oct 2016 11:09:34 -0700 Subject: Initial ChangeLog update for 1.18 changes --- ChangeLog | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ChangeLog b/ChangeLog index 189872cf..18bcf251 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,68 @@ +openal-soft-1.18.0: + + Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. + + Implemented the AL_SOFT_gain_clamp_ex extension. + + Implemented 3D processing for some effects. Currently implemented for + Reverb, Compressor, Equalizer, and Ring Modulator. + + Implemented 2-channel UHJ output encoding. Used by default for stereo playback. + + Implemented dual-band processing for high-quality ambisonic decoding. + + Implemented distance-compensation for high-quality ambisonic decoding. + + Implemented a config option to select a preferred HRTF. + + Implemented a run-time check for NEON extensions using /proc/cpuinfo. + + Fixed building on compilers with NEON support but don't default to having + NEON enabled. + + Fixed support for JACK on Windows. + + Fixed starting a source while alcSuspendContext is in effect. + + Fixed detection of headsets as headphones, with MMDevAPI. + + Added support for AmbDec config files, for custom ambisonic decoder + configurations. Version 3 files only. + + Added backend-specific options to alsoft-config. + + Added first-, second-, and third-order ambisonic output formats. Currently + only works with backends that don't rely on channel labels, like JACK, + ALSA, and OSS. + + Added a build option to embed the default HRTFs into the lib. + + Added AmbDec presets to enable high-quality ambisonic decoding. + + Added an AmbDec preset for 3D7.1 speaker setups. + + Added documentation regarding Ambisonics, 3D7.1, AmbDec config files, and + the provided ambdec presets. + + Added the ability for MMDevAPI to open devices given a Device ID or GUID + string. + + Added an option to the example apps to open a specific device. + + Slightly improved automatic naming for enumerated HRTFs. + + Improved B-Format decoding with HRTF output. + + Improved internal property handling for better batching behavior. + + Improved performance of certain filter uses. + + Altered cone behavior for automatic auxiliary send gain and gainhf + management. Now better represents the energy the room receives. + + Removed support for the AL_SOFT_buffer_samples and AL_SOFT_buffer_sub_data + extensions. Due to conflicts with AL_EXT_SOURCE_RADIUS. + openal-soft-1.17.2: Implemented device enumeration for OSSv4. -- cgit v1.2.3 From 43e7323adba756ca96abef2e69a09461c8e1e633 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Nov 2016 02:20:19 -0700 Subject: Rebalance the frequencies for B-Format HRTF coefficients The original pseudo-inverse method that generated the LF matrix expects the high frequencies to be scaled up by ~2.645751 over the low frequencies (or sqrt(7), ~8.45dB). However, the AllRAD method used to generate the HF matrix produced a matrix that was only scaled up by 1.46551981258 (based on the average of the W coefficients). Previously, the LF matrix was scaled down by sqrt(7), as the difference specified in the pseudo-inverse results. This failed to account for the increase already present in the HF matrix, so now the LF matrix is scaled down by the remaining difference between the expected scaling and the scaling already present in the HF matrix (sqrt(7) / 1.46551981258 = 1.80533302205, or roughly 5.13dB, where the reciprocal is 0.553914423 for -5.13 dB). --- Alc/hrtf.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 02889736..cd9656bc 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -158,21 +158,24 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { - { { 0.078851598f, 0.000000000f, 0.070561967f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, 0.0467610443f, 0.0000000000f } }, - { { 0.124051278f, 0.059847972f, 0.059847972f, 0.059847972f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, 0.0269973975f } }, - { { 0.124051278f, -0.059847972f, 0.059847972f, 0.059847972f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, 0.0269973975f } }, - { { 0.124051278f, -0.059847972f, 0.059847972f, -0.059847972f }, { 0.0269973975f, -0.0269973975f, 0.0269973975f, -0.0269973975f } }, - { { 0.124051278f, 0.059847972f, 0.059847972f, -0.059847972f }, { 0.0269973975f, 0.0269973975f, 0.0269973975f, -0.0269973975f } }, - { { 0.078851598f, 0.000000000f, 0.000000000f, 0.070561967f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, 0.0467610443f } }, - { { 0.078851598f, -0.070561967f, 0.000000000f, 0.000000000f }, { 0.0269973975f, -0.0467610443f, 0.0000000000f, 0.0000000000f } }, - { { 0.078851598f, 0.000000000f, 0.000000000f, -0.070561967f }, { 0.0269973975f, 0.0000000000f, 0.0000000000f, -0.0467610443f } }, - { { 0.078851598f, 0.070561967f, 0.000000000f, 0.000000000f }, { 0.0269973975f, 0.0467610443f, 0.0000000000f, 0.0000000000f } }, - { { 0.124051278f, 0.059847972f, -0.059847972f, 0.059847972f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, 0.0269973975f } }, - { { 0.124051278f, -0.059847972f, -0.059847972f, 0.059847972f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, 0.0269973975f } }, - { { 0.124051278f, -0.059847972f, -0.059847972f, -0.059847972f }, { 0.0269973975f, -0.0269973975f, -0.0269973975f, -0.0269973975f } }, - { { 0.124051278f, 0.059847972f, -0.059847972f, -0.059847972f }, { 0.0269973975f, 0.0269973975f, -0.0269973975f, -0.0269973975f } }, - { { 0.078851598f, 0.000000000f, -0.070561967f, 0.000000000f }, { 0.0269973975f, 0.0000000000f, -0.0467610443f, 0.0000000000f } }, + { { 0.078851598f, 0.000000000f, 0.070561967f, 0.000000000f }, { 0.0714285714f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, + { { 0.124051278f, 0.059847972f, 0.059847972f, 0.059847972f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, 0.0714285714f } }, + { { 0.124051278f, -0.059847972f, 0.059847972f, 0.059847972f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, 0.0714285714f } }, + { { 0.124051278f, -0.059847972f, 0.059847972f, -0.059847972f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, -0.0714285714f } }, + { { 0.124051278f, 0.059847972f, 0.059847972f, -0.059847972f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, -0.0714285714f } }, + { { 0.078851598f, 0.000000000f, 0.000000000f, 0.070561967f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, + { { 0.078851598f, -0.070561967f, 0.000000000f, 0.000000000f }, { 0.0714285714f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.078851598f, 0.000000000f, 0.000000000f, -0.070561967f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, + { { 0.078851598f, 0.070561967f, 0.000000000f, 0.000000000f }, { 0.0714285714f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.124051278f, 0.059847972f, -0.059847972f, 0.059847972f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, 0.0714285714f } }, + { { 0.124051278f, -0.059847972f, -0.059847972f, 0.059847972f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, 0.0714285714f } }, + { { 0.124051278f, -0.059847972f, -0.059847972f, -0.059847972f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, -0.0714285714f } }, + { { 0.124051278f, 0.059847972f, -0.059847972f, -0.059847972f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, -0.0714285714f } }, + { { 0.078851598f, 0.000000000f, -0.070561967f, 0.000000000f }, { 0.0714285714f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, }; +#define AMBIHF_GAIN 1.0f +#define AMBILF_GAIN 0.553914423f /* -5.13dB */ + /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the * tail generated by the filter. @@ -233,6 +236,11 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(i = 0;i < Hrtf->irSize;i++) temps[2][i] = fir[i] / 32767.0f; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + /* Scale the low and high frequency responses. */ + for(i = 0;i < HRIR_LENGTH;i++) + temps[0][i] *= AMBIHF_GAIN; + for(i = 0;i < HRIR_LENGTH;i++) + temps[1][i] *= AMBILF_GAIN; } /* Add to the left output coefficients with the specified delay. */ @@ -262,6 +270,11 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(i = 0;i < Hrtf->irSize;i++) temps[2][i] = fir[i] / 32767.0f; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + /* Scale the low and high frequency responses. */ + for(i = 0;i < HRIR_LENGTH;i++) + temps[0][i] *= AMBIHF_GAIN; + for(i = 0;i < HRIR_LENGTH;i++) + temps[1][i] *= AMBILF_GAIN; } /* Add to the right output coefficients with the specified delay. */ -- cgit v1.2.3 From d142ba1ab4d5d63f166f9236da21460ec90ce9bd Mon Sep 17 00:00:00 2001 From: septag Date: Thu, 3 Nov 2016 00:37:09 +0330 Subject: Added cmake FindWindowsSDK for FindDSound module and fixed FindDSound.cmake --- CMakeLists.txt | 1 - cmake/FindDSound.cmake | 66 +---- cmake/FindWindowsSDK.cmake | 626 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 639 insertions(+), 54 deletions(-) create mode 100644 cmake/FindWindowsSDK.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index cf6d7ca6..1e371bc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ include(CheckStructHasMember) include(CheckFileOffsetBits) include(GNUInstallDirs) - SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) diff --git a/cmake/FindDSound.cmake b/cmake/FindDSound.cmake index 3fd26ed6..70e94269 100644 --- a/cmake/FindDSound.cmake +++ b/cmake/FindDSound.cmake @@ -8,68 +8,28 @@ # DSOUND_LIBRARY - the dsound library # -# DSOUND_INCLUDE_DIR -file(GLOB DXSDK_INCLUDE_DIRS LIST_DIRECTORIES TRUE "C:/Program Files (x86)/Windows Kits/10/Include/*") -if (DXSDK_INCLUDE_DIRS) - list(SORT DXSDK_INCLUDE_DIRS) - list(REVERSE DXSDK_INCLUDE_DIRS) -endif() +if (WIN32) + include(FindWindowsSDK) + get_windowssdk_library_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_LIB_DIRS) + get_windowssdk_include_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_INCLUDE_DIRS) +endif() +# DSOUND_INCLUDE_DIR find_path(DSOUND_INCLUDE_DIR - NAMES - "dsound.h" - PATHS - "${DXSDK_DIR}" - ${DXSDK_INCLUDE_DIRS} - "C:/Program Files (x86)/Windows Kits/8.0" - "C:/Program Files (x86)/Windows Kits/8.1" - PATH_SUFFIXES - Include - um - Include/um - DOC - "The DirectSound include directory" -) + NAMES "dsound.h" + PATHS ${WINSDK_INCLUDE_DIRS} "${DXSDK_DIR}" + PATH_SUFFIXES include + DOC "The DirectSound include directory") # DSOUND_LIBRARY -if(CMAKE_CL_64) - set (DirectX_ARCHITECTURE x64) -else() - set (DirectX_ARCHITECTURE x86) -endif() - -file(GLOB DXSDK_LIB_DIRS LIST_DIRECTORIES TRUE "C:/Program Files (x86)/Windows Kits/10/Lib/*") -if (DXSDK_LIB_DIRS) - list(SORT DXSDK_LIB_DIRS) - list(REVERSE DXSDK_LIB_DIRS) -endif() - find_library(DSOUND_LIBRARY NAMES dsound + PATHS ${WINSDK_LIB_DIRS} "${DXSDK_DIR}" + PATH_SUFFIXES lib lib/x86 lib/x64 DOC "The DirectSound library") -if (NOT DSOUND_LIBRARY) - find_library(DSOUND_LIBRARY - NAMES dsound - PATHS - "${DXSDK_DIR}" - ${DXSDK_LIB_DIRS} - "C:/Program Files (x86)/Windows Kits/8.0" - "C:/Program Files (x86)/Windows Kits/8.1" - PATH_SUFFIXES - Lib - Lib/${DirectX_ARCHITECTURE} - um/${DirectX_ARCHITECTURE} - Lib/win8/um/${DirectX_ARCHITECTURE} - Lib/winv6.3/um/${DirectX_ARCHITECTURE} - DOC - "The DirectSound library" - ) -endif() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(DSound - REQUIRED_VARS DSOUND_LIBRARY DSOUND_INCLUDE_DIR -) +find_package_handle_standard_args(DSound REQUIRED_VARS DSOUND_LIBRARY DSOUND_INCLUDE_DIR) if(DSOUND_FOUND) set(DSOUND_LIBRARIES ${DSOUND_LIBRARY}) diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake new file mode 100644 index 00000000..e136b897 --- /dev/null +++ b/cmake/FindWindowsSDK.cmake @@ -0,0 +1,626 @@ +# - Find the Windows SDK aka Platform SDK +# +# Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK +# +# Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case +# you just want the tool binaries to run, rather than the libraries and headers +# for compiling. +# +# Variables: +# WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio +# WINDOWSSDK_LATEST_DIR +# WINDOWSSDK_LATEST_NAME +# WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version +# WINDOWSSDK_PREFERRED_DIR +# WINDOWSSDK_PREFERRED_NAME +# +# WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first. +# WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency +# +# Functions: +# windowssdk_name_lookup( ) - Find the name corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# windowssdk_build_lookup( ) - Find the build version number corresponding with the SDK directory you pass in, or +# NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. +# +# get_windowssdk_from_component( ) - Given a library or include dir, +# find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized. +# +# get_windowssdk_library_dirs( ) - Find the architecture-appropriate +# library directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# get_windowssdk_library_dirs_multiple( ...) - Find the architecture-appropriate +# library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# +# get_windowssdk_include_dirs( ) - Find the +# include directories corresponding to the SDK directory you pass in (or NOTFOUND if none) +# +# get_windowssdk_include_dirs_multiple( ...) - Find the +# include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. +# Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. +# +# Requires these CMake modules: +# FindPackageHandleStandardArgs (known included with CMake >=2.6.2) +# +# Original Author: +# 2012 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(_preferred_sdk_dirs) # pre-output +set(_win_sdk_dirs) # pre-output +set(_win_sdk_versanddirs) # pre-output +set(_win_sdk_buildsanddirs) # pre-output +set(_winsdk_vistaonly) # search parameters +set(_winsdk_kits) # search parameters + + +set(_WINDOWSSDK_ANNOUNCE OFF) +if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY)) + set(_WINDOWSSDK_ANNOUNCE ON) +endif() +macro(_winsdk_announce) + if(_WINSDK_ANNOUNCE) + message(STATUS ${ARGN}) + endif() +endmacro() + +set(_winsdk_win10vers + 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" + 10.0.10586.0 # TH2 aka Win10 1511 + 10.0.10240.0 # Win10 RTM + 10.0.10150.0 # just ucrt + 10.0.10056.0 +) + +if(WindowsSDK_FIND_COMPONENTS MATCHES "tools") + set(_WINDOWSSDK_IGNOREMSVC ON) + _winsdk_announce("Checking for tools from Windows/Platform SDKs...") +else() + set(_WINDOWSSDK_IGNOREMSVC OFF) + _winsdk_announce("Checking for Windows/Platform SDKs...") +endif() + +# Appends to the three main pre-output lists used only if the path exists +# and is not already in the list. +function(_winsdk_conditional_append _vername _build _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_dirs "${_path}") + set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_versanddirs + "${_vername}" + "${_path}") + set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE) + list(APPEND + _win_sdk_buildsanddirs + "${_build}" + "${_path}") + set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE) +endfunction() + +# Appends to the "preferred SDK" lists only if the path exists +function(_winsdk_conditional_append_preferred _info _path) + if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) + # Path invalid - do not add + return() + endif() + + get_filename_component(_path "${_path}" ABSOLUTE) + + list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx) + if(_win_sdk_idx GREATER -1) + # Path already in list - do not add + return() + endif() + _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}") + # Not yet in the list, so we'll add it + list(APPEND _win_sdk_preferred_sdk_dirs "${_path}") + set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE) + + # Just in case we somehow missed it: + _winsdk_conditional_append("${_info}" "" "${_path}") +endfunction() + +# Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs". +# If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows +# and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits", +# use this macro first, since these registry keys usually have more information. +# +# Pass a "default" build number as an extra argument in case we can't find it. +function(_winsdk_check_microsoft_sdks_registry _winsdkver) + set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}") + get_filename_component(_sdkdir + "[${SDKKEY};InstallationFolder]" + ABSOLUTE) + + set(_sdkname "Windows SDK ${_winsdkver}") + + # Default build number passed as extra argument + set(_build ${ARGN}) + # See if the registry holds a Microsoft-mutilated, err, designated, product name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkproductname + "[${SDKKEY};ProductName]" + NAME) + if(NOT "${_sdkproductname}" MATCHES "registry") + # Got a product name + set(_sdkname "${_sdkname} (${_sdkproductname})") + endif() + + # try for a version to augment our name + # (just using get_filename_component to execute the registry lookup) + get_filename_component(_sdkver + "[${SDKKEY};ProductVersion]" + NAME) + if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES) + # Got a version + if(NOT "${_sdkver}" MATCHES "\\.\\.") + # and it's not an invalid one with two dots in it: + # use to override the default build + set(_build ${_sdkver}) + if(NOT "${_sdkname}" MATCHES "${_sdkver}") + # Got a version that's not already in the name, let's use it to improve our name. + set(_sdkname "${_sdkname} (${_sdkver})") + endif() + endif() + endif() + _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes, the build number, and a key (technically a "value name") +# corresponding to a Windows SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Note that the key or "value name" tends to be something weird like KitsRoot81 - +# no easy way to predict, just have to observe them in the wild. +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]" + ABSOLUTE) + _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}") +endfunction() + +# Given a name for identification purposes and the build number +# corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it +# in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots +# Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these: +# sometimes you get keys in both parts of the registry (in the wow64 portion especially), +# and the non-"Windows Kits" location is often more descriptive. +function(_winsdk_check_win10_kits _winkit_build) + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" + ABSOLUTE) + if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}")) + return() # not found + endif() + if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um") + _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}") + endif() +endfunction() + +# Given a name for indentification purposes, the build number, and the associated package GUID, +# look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\ +# for that guid and the SDK it points to. +function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid) + foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) + get_filename_component(_sdkdir + "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" + ABSOLUTE) + _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}") + endforeach() +endfunction() + +### +# Detect toolchain information: to know whether it's OK to use Vista+ only SDKs +### +set(_winsdk_vistaonly_ok OFF) +if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC) + # VC 10 and older has broad target support + if(MSVC_VERSION LESS 1700) + # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") + # This is the XP-compatible v110+ toolset + elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90") + # This is the VS2010/VS2008 toolset + else() + # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset. + # These versions have no XP (and possibly Vista pre-SP1) support + set(_winsdk_vistaonly_ok ON) + if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED) + set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE) + message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!") + endif() + endif() +endif() +if(_WINDOWSSDK_IGNOREMSVC) + set(_winsdk_vistaonly_ok ON) +endif() + +### +# MSVC version checks - keeps messy conditionals in one place +# (messy because of _WINDOWSSDK_IGNOREMSVC) +### +set(_winsdk_msvc_greater_1200 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200))) + set(_winsdk_msvc_greater_1200 ON) +endif() +# Newer than VS .NET/VS Toolkit 2003 +set(_winsdk_msvc_greater_1310 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310))) + set(_winsdk_msvc_greater_1310 ON) +endif() + +# VS2005/2008 +set(_winsdk_msvc_less_1600 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600))) + set(_winsdk_msvc_less_1600 ON) +endif() + +# VS2013+ +set(_winsdk_msvc_not_less_1800 OFF) +if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800))) + set(_winsdk_msvc_not_less_1800 ON) +endif() + +### +# START body of find module +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + ### + # Look for "preferred" SDKs + ### + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() + + ### + # Begin the massive list of SDK searching! + ### + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # These require at least Visual Studio 2013 (VC12) + + _winsdk_check_microsoft_sdks_registry(v10.0A) + + # Windows Software Development Kit (SDK) for Windows 10 + # Several different versions living in the same directory - if nothing else we can assume RTM (10240) + _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0) + foreach(_win10build ${_winsdk_win10vers}) + _winsdk_check_win10_kits(${_win10build}) + endforeach() + endif() # vista-only and 2013+ + + # Included in Visual Studio 2013 + # Includes the v120_xp toolset + _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636) + + if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) + # Windows Software Development Kit (SDK) for Windows 8.1 + # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 + _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0) + _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81) + endif() # vista-only and 2013+ + + if(_winsdk_vistaonly_ok) + # Included in Visual Studio 2012 + _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727) + + # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 + # This is the first version to also include the DirectX SDK + # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx + _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384) + _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot) + endif() # vista-only + + # Included with VS 2012 Update 1 or later + # Introduces v110_xp toolset + _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106) + if(_winsdk_vistaonly_ok) + # Microsoft Windows SDK for Windows 7 and .NET Framework 4 + # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b + _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514) + endif() # vista-only + + # Included with VS 2010 + _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385) + + # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 + # Works with VC9 + # http://www.microsoft.com/en-us/download/details.aspx?id=18950 + _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385) + + # Two versions call themselves "v6.1": + # Older: + # Windows Vista Update & .NET 3.0 SDK + # http://www.microsoft.com/en-us/download/details.aspx?id=14477 + + # Newer: + # Windows Server 2008 & .NET 3.5 SDK + # may have broken VS9SP1? they recommend v7.0 instead, or a KB... + # http://www.microsoft.com/en-us/download/details.aspx?id=24826 + _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10) + + # Included in VS 2008 + _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1) + + # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components + # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx + _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384) +endif() + +# Let's not forget the Platform SDKs, which sometimes are useful! +if(_winsdk_msvc_greater_1200) + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1") + _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3") +endif() +### +# Finally, look for "preferred" SDKs +### +if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 + + + # Environment variable for SDK dir + if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) + _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") + endif() + + if(_winsdk_msvc_less_1600) + # Per-user current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") + + # System-wide current Windows SDK for VS2005/2008 + get_filename_component(_sdkdir + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" + ABSOLUTE) + _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") + endif() +endif() + + +function(windowssdk_name_lookup _dir _outvar) + list(FIND _win_sdk_versanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_versanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +function(windowssdk_build_lookup _dir _outvar) + list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx) + math(EXPR _idx "${_diridx} - 1") + if(${_idx} GREATER -1) + list(GET _win_sdk_buildsanddirs ${_idx} _ret) + else() + set(_ret "NOTFOUND") + endif() + set(${_outvar} "${_ret}" PARENT_SCOPE) +endfunction() + +# If we found something... +if(_win_sdk_dirs) + list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR) + windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" + WINDOWSSDK_LATEST_NAME) + set(WINDOWSSDK_DIRS ${_win_sdk_dirs}) + + # Fallback, in case no preference found. + set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") + set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") + set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) + set(WINDOWSSDK_FOUND_PREFERENCE OFF) +endif() + +# If we found indications of a user preference... +if(_win_sdk_preferred_sdk_dirs) + list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) + windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}" + WINDOWSSDK_PREFERRED_NAME) + set(WINDOWSSDK_PREFERRED_FIRST_DIRS + ${_win_sdk_preferred_sdk_dirs} + ${_win_sdk_dirs}) + list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS) + set(WINDOWSSDK_FOUND_PREFERENCE ON) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WindowsSDK + "No compatible version of the Windows SDK or Platform SDK found." + WINDOWSSDK_DIRS) + +if(WINDOWSSDK_FOUND) + # Internal: Architecture-appropriate library directory names. + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM") + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + # Only supported in Win10 SDK and up. + set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch arm) # what the architecture used to be called + set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture + endif() + else() + if(CMAKE_SIZEOF_VOID_P MATCHES "8") + set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch amd64) # what the architecture used to be called + set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture + else() + set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs + set(_winsdk_arch i386) # what the architecture used to be called + set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture + endif() + endif() + + function(get_windowssdk_from_component _component _var) + get_filename_component(_component "${_component}" ABSOLUTE) + file(TO_CMAKE_PATH "${_component}" _component) + foreach(_sdkdir ${WINDOWSSDK_DIRS}) + get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE) + string(LENGTH "${_sdkdir}" _sdklen) + file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}") + # If we don't have any "parent directory" items... + if(NOT "${_rel}" MATCHES "[.][.]") + set(${_var} "${_sdkdir}" PARENT_SCOPE) + return() + endif() + endforeach() + # Fail. + set(${_var} "NOTFOUND" PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs _winsdk_dir _var) + set(_dirs) + set(_suffixes + "lib${_winsdk_archbare}" # SDKs like 7.1A + "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir + "lib/w2k/${_winsdk_arch}" # Win2k min requirement + "lib/wxp/${_winsdk_arch}" # WinXP min requirement + "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement + "lib/wlh/${_winsdk_arch}" + "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement + "lib/win7/${_winsdk_arch}" + "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement + ) + foreach(_ver + wlh # Win Vista ("Long Horn") min requirement + win7 # Win 7 min requirement + win8 # Win 8 min requirement + winv6.3 # Win 8.1 min requirement + ) + + list(APPEND _suffixes + "lib/${_ver}/${_winsdk_arch}" + "lib/${_ver}/um/${_winsdk_arch8}" + "lib/${_ver}/km/${_winsdk_arch8}" + ) + endforeach() + + # Look for WDF libraries in Win10+ SDK + foreach(_mode umdf kmdf) + file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*") + if(_wdfdirs) + list(APPEND _suffixes ${_wdfdirs}) + endif() + endforeach() + + # Look in each Win10+ SDK version for the components + foreach(_win10ver ${_winsdk_win10vers}) + foreach(_component um km ucrt mmos) + list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a library actually exists here. + file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib") + if(_libs) + list(APPEND _dirs "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs _winsdk_dir _var) + set(_dirs) + + set(_subdirs shared um winrt km wdf mmos ucrt) + set(_suffixes Include) + + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_dir}") + endforeach() + + foreach(_ver ${_winsdk_win10vers}) + foreach(_dir ${_subdirs}) + list(APPEND _suffixes "Include/${_ver}/${_dir}") + endforeach() + endforeach() + + foreach(_suffix ${_suffixes}) + # Check to see if a header file actually exists here. + file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h") + if(_headers) + list(APPEND _dirs "${_winsdk_dir}/${_suffix}") + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_library_dirs_multiple _var) + set(_dirs) + foreach(_sdkdir ${ARGN}) + get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs) + if(_current_sdk_libdirs) + list(APPEND _dirs ${_current_sdk_libdirs}) + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() + function(get_windowssdk_include_dirs_multiple _var) + set(_dirs) + foreach(_sdkdir ${ARGN}) + get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs) + if(_current_sdk_libdirs) + list(APPEND _dirs ${_current_sdk_incdirs}) + endif() + endforeach() + if("${_dirs}" STREQUAL "") + set(_dirs NOTFOUND) + else() + list(REMOVE_DUPLICATES _dirs) + endif() + set(${_var} ${_dirs} PARENT_SCOPE) + endfunction() +endif() -- cgit v1.2.3 From ac26b209a6c3e19a85e3ca960c29f49939aa73bc Mon Sep 17 00:00:00 2001 From: septag Date: Thu, 3 Nov 2016 01:52:40 +0330 Subject: fixed minor check in FindDSound.cmake --- cmake/FindDSound.cmake | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmake/FindDSound.cmake b/cmake/FindDSound.cmake index 70e94269..4078deb5 100644 --- a/cmake/FindDSound.cmake +++ b/cmake/FindDSound.cmake @@ -10,21 +10,23 @@ if (WIN32) include(FindWindowsSDK) - get_windowssdk_library_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_LIB_DIRS) - get_windowssdk_include_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_INCLUDE_DIRS) + if (WINDOWSSDK_FOUND) + get_windowssdk_library_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_LIB_DIRS) + get_windowssdk_include_dirs(${WINDOWSSDK_PREFERRED_DIR} WINSDK_INCLUDE_DIRS) + endif() endif() # DSOUND_INCLUDE_DIR find_path(DSOUND_INCLUDE_DIR NAMES "dsound.h" - PATHS ${WINSDK_INCLUDE_DIRS} "${DXSDK_DIR}" + PATHS "${DXSDK_DIR}" ${WINSDK_INCLUDE_DIRS} PATH_SUFFIXES include DOC "The DirectSound include directory") # DSOUND_LIBRARY find_library(DSOUND_LIBRARY NAMES dsound - PATHS ${WINSDK_LIB_DIRS} "${DXSDK_DIR}" + PATHS "${DXSDK_DIR}" ${WINSDK_LIB_DIRS} PATH_SUFFIXES lib lib/x86 lib/x64 DOC "The DirectSound library") -- cgit v1.2.3 From 2d5efe424faf9de692283279be11fe1399c1d5a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Nov 2016 14:07:14 -0700 Subject: Be clearer about whether full or basic HRTF rendering is used --- Alc/panning.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 1162bbbc..4e4caf46 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -975,7 +975,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ERR("Unexpected hrtf-mode: %s\n", mode); } - TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf.Name)); + TRACE("%s HRTF rendering enabled, using \"%s\"\n", + ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), + al_string_get_cstr(device->Hrtf.Name) + ); InitHrtfPanning(device); return; } -- cgit v1.2.3 From 118cc0907d93d97439be15af07b2385e6865a6fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 Nov 2016 20:49:50 -0700 Subject: Remove an unnecessary intermediate variable --- Alc/mixer.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index b1f79d05..727d0640 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -455,7 +455,6 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam const ALbuffer *ALBuffer = BufferListItem->buffer; const ALubyte *Data = ALBuffer->data; ALuint DataSize; - ALuint pos; /* Offset buffer data to current channel */ Data += chan*SampleSize; @@ -467,10 +466,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam /* Load what's left to play from the source buffer, and * clear the rest of the temp buffer */ - pos = DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos); + DataSize = minu(SrcBufferSize - SrcDataSize, + ALBuffer->SampleLen - DataPosInt); - LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize], + LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); SrcDataSize += DataSize; @@ -484,11 +483,10 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam /* Load what's left of this loop iteration, then load * repeats of the loop section */ - pos = DataPosInt; - DataSize = LoopEnd - pos; + DataSize = LoopEnd - DataPosInt; DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize], + LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); SrcDataSize += DataSize; -- cgit v1.2.3 From 9682a62743091463b8cfac540dbbf854d33128e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 00:47:22 -0700 Subject: Use proper atomics for the lockless ringbuffer --- Alc/alcRing.c | 91 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/Alc/alcRing.c b/Alc/alcRing.c index 5994f196..8a77dda1 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -34,8 +34,8 @@ * size or count is in 'elements', not bytes. Additionally, it only supports * single-consumer/single-provider operation. */ struct ll_ringbuffer { - volatile size_t write_ptr; - volatile size_t read_ptr; + ATOMIC(size_t) write_ptr; + ATOMIC(size_t) read_ptr; size_t size; size_t size_mask; size_t elem_size; @@ -58,11 +58,11 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); if(!rb) return NULL; + ATOMIC_INIT(&rb->write_ptr, 0); + ATOMIC_INIT(&rb->read_ptr, 0); rb->size = power_of_two; rb->size_mask = rb->size - 1; rb->elem_size = elem_sz; - rb->write_ptr = 0; - rb->read_ptr = 0; rb->mlocked = 0; return rb; } @@ -84,7 +84,7 @@ void ll_ringbuffer_free(ll_ringbuffer_t *rb) int ll_ringbuffer_mlock(ll_ringbuffer_t *rb) { #ifdef USE_MLOCK - if(!rb->locked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size)) + if(!rb->mlocked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size)) return -1; #endif /* USE_MLOCK */ rb->mlocked = 1; @@ -94,8 +94,8 @@ int ll_ringbuffer_mlock(ll_ringbuffer_t *rb) /* Reset the read and write pointers to zero. This is not thread safe. */ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { - rb->read_ptr = 0; - rb->write_ptr = 0; + ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_relaxed); + ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); memset(rb->buf, 0, rb->size*rb->elem_size); } @@ -103,16 +103,16 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) * elements in front of the read pointer and behind the write pointer. */ size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) { - size_t w = rb->write_ptr; - size_t r = rb->read_ptr; + size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed); return (rb->size+w-r) & rb->size_mask; } /* Return the number of elements available for writing. This is the number of * elements in front of the write pointer and behind the read pointer. */ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { - size_t w = rb->write_ptr; - size_t r = rb->read_ptr; + size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed); return (rb->size+r-w-1) & rb->size_mask; } @@ -120,6 +120,7 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) * Returns the actual number of elements copied. */ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) { + size_t read_ptr; size_t free_cnt; size_t cnt2; size_t to_read; @@ -129,10 +130,12 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) if(free_cnt == 0) return 0; to_read = (cnt > free_cnt) ? free_cnt : cnt; - cnt2 = rb->read_ptr + to_read; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; if(cnt2 > rb->size) { - n1 = rb->size - rb->read_ptr; + n1 = rb->size - read_ptr; n2 = cnt2 & rb->size_mask; } else @@ -141,13 +144,14 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) n2 = 0; } - memcpy(dest, &(rb->buf[rb->read_ptr*rb->elem_size]), n1*rb->elem_size); - rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask; + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + read_ptr = (read_ptr + n1) & rb->size_mask; if(n2) { - memcpy(dest + n1*rb->elem_size, &(rb->buf[rb->read_ptr*rb->elem_size]), n2*rb->elem_size); - rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask; + memcpy(dest + n1*rb->elem_size, &rb->buf[read_ptr*rb->elem_size], n2*rb->elem_size); + read_ptr += n2; } + ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); return to_read; } @@ -160,17 +164,18 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) size_t cnt2; size_t to_read; size_t n1, n2; - size_t tmp_read_ptr; + size_t read_ptr; - tmp_read_ptr = rb->read_ptr; free_cnt = ll_ringbuffer_read_space(rb); if(free_cnt == 0) return 0; to_read = (cnt > free_cnt) ? free_cnt : cnt; - cnt2 = tmp_read_ptr + to_read; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; if(cnt2 > rb->size) { - n1 = rb->size - tmp_read_ptr; + n1 = rb->size - read_ptr; n2 = cnt2 & rb->size_mask; } else @@ -179,10 +184,10 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) n2 = 0; } - memcpy(dest, &(rb->buf[tmp_read_ptr*rb->elem_size]), n1*rb->elem_size); - tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask; + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + read_ptr = (read_ptr + n1) & rb->size_mask; if(n2) - memcpy(dest + n1*rb->elem_size, &(rb->buf[tmp_read_ptr*rb->elem_size]), n2*rb->elem_size); + memcpy(dest + n1*rb->elem_size, &rb->buf[read_ptr*rb->elem_size], n2*rb->elem_size); return to_read; } @@ -190,6 +195,7 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) * Returns the actual number of elements copied. */ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) { + size_t write_ptr; size_t free_cnt; size_t cnt2; size_t to_write; @@ -199,10 +205,12 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) if(free_cnt == 0) return 0; to_write = (cnt > free_cnt) ? free_cnt : cnt; - cnt2 = rb->write_ptr + to_write; + write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = write_ptr + to_write; if(cnt2 > rb->size) { - n1 = rb->size - rb->write_ptr; + n1 = rb->size - write_ptr; n2 = cnt2 & rb->size_mask; } else @@ -211,28 +219,27 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) n2 = 0; } - memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src, n1*rb->elem_size); - rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask; + memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); + write_ptr = (write_ptr + n1) & rb->size_mask; if(n2) { - memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src + n1*rb->elem_size, n2*rb->elem_size); - rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask; + memcpy(&rb->buf[write_ptr*rb->elem_size], src + n1*rb->elem_size, n2*rb->elem_size); + write_ptr += n2; } + ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); return to_write; } /* Advance the read pointer `cnt' places. */ void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) { - size_t tmp = (rb->read_ptr + cnt) & rb->size_mask; - rb->read_ptr = tmp; + ATOMIC_ADD(size_t, &rb->read_ptr, cnt, almemory_order_acq_rel); } /* Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) { - size_t tmp = (rb->write_ptr + cnt) & rb->size_mask; - rb->write_ptr = tmp; + ATOMIC_ADD(size_t, &rb->write_ptr, cnt, almemory_order_acq_rel); } /* The non-copying data reader. `vec' is an array of two places. Set the values @@ -244,8 +251,8 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data size_t cnt2; size_t w, r; - w = rb->write_ptr; - r = rb->read_ptr; + w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; + r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; free_cnt = (rb->size+w-r) & rb->size_mask; cnt2 = r + free_cnt; @@ -253,7 +260,7 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]); + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; vec[0].len = rb->size - r; vec[1].buf = (char*)rb->buf; vec[1].len = cnt2 & rb->size_mask; @@ -261,7 +268,7 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data else { /* Single part vector: just the rest of the buffer */ - vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]); + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; vec[0].len = free_cnt; vec[1].buf = NULL; vec[1].len = 0; @@ -277,8 +284,8 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat size_t cnt2; size_t w, r; - w = rb->write_ptr; - r = rb->read_ptr; + w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; + r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; free_cnt = (rb->size+r-w-1) & rb->size_mask; cnt2 = w + free_cnt; @@ -286,14 +293,14 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ - vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]); + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; vec[0].len = rb->size - w; vec[1].buf = (char*)rb->buf; vec[1].len = cnt2 & rb->size_mask; } else { - vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]); + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; vec[0].len = free_cnt; vec[1].buf = NULL; vec[1].len = 0; -- cgit v1.2.3 From 815947492c9df58ab4872fd643b09ada5d2033ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 01:22:29 -0700 Subject: Remove the explicit type from ATOMIC_ADD and ATOMIC_SUB --- Alc/alcRing.c | 4 ++-- include/atomic.h | 52 +++++++++++++++++++++------------------------------- 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/Alc/alcRing.c b/Alc/alcRing.c index 8a77dda1..d3059f86 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -233,13 +233,13 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) /* Advance the read pointer `cnt' places. */ void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) { - ATOMIC_ADD(size_t, &rb->read_ptr, cnt, almemory_order_acq_rel); + ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); } /* Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) { - ATOMIC_ADD(size_t, &rb->write_ptr, cnt, almemory_order_acq_rel); + ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); } /* The non-copying data reader. `vec' is an array of two places. Set the values diff --git a/include/atomic.h b/include/atomic.h index 2a996625..1f6ceae2 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -33,8 +33,8 @@ extern "C" { #define ATOMIC_LOAD(...) PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst) #define ATOMIC_STORE(...) PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_ADD(T, ...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_SUB(T, ...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_ADD(...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_SUB(...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst) #define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst) #define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) \ @@ -69,14 +69,8 @@ enum almemory_order { (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - __sync_fetch_and_add(&(_val)->value, (_incr)); \ -}) -#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - __sync_fetch_and_sub(&(_val)->value, (_decr)); \ -}) +#define ATOMIC_ADD(_val, _incr, ...) __sync_fetch_and_add(&(_val)->value, (_incr)) +#define ATOMIC_SUB(_val, _decr, ...) __sync_fetch_and_sub(&(_val)->value, (_decr)) #define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ @@ -143,18 +137,14 @@ enum almemory_order { (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \ - static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - T _r; \ - WRAP_ADD(_r, &(_val)->value, (T)(_incr)); \ +#define ATOMIC_ADD(_val, _incr, ...) __extension__({ \ + __typeof((_val)->value) _r; \ + WRAP_ADD(_r, &(_val)->value, _incr); \ _r; \ }) -#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \ - static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - T _r; \ - WRAP_SUB(_r, &(_val)->value, (T)(_decr)); \ +#define ATOMIC_SUB(_val, _decr, ...) __extension__({ \ + __typeof((_val)->value) _r; \ + WRAP_SUB(_r, &(_val)->value, _decr); \ _r; \ }) @@ -222,7 +212,7 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG return old == *oldval; } -#define WRAP_ADDSUB(T, _func, _ptr, _amnt) ((T(*)(T volatile*,T))_func)((_ptr), (_amnt)) +#define WRAP_ADDSUB(T, _func, _ptr, _amnt) (_func((T volatile*)(_ptr), (_amnt)) #define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval)) #define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval)) @@ -248,12 +238,12 @@ enum almemory_order { int _al_invalid_atomic_size(); /* not defined */ -#define ATOMIC_ADD(T, _val, _incr, ...) \ - ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicAdd32, &(_val)->value, (_incr)) : \ - (T)_al_invalid_atomic_size()) -#define ATOMIC_SUB(T, _val, _decr, ...) \ - ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) : \ - (T)_al_invalid_atomic_size()) +#define ATOMIC_ADD(_val, _incr, ...) \ + ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ + _al_invalid_atomic_size()) +#define ATOMIC_SUB(_val, _decr, ...) \ + ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ + _al_invalid_atomic_size()) #define ATOMIC_EXCHANGE(T, _val, _newval, ...) \ ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \ @@ -278,8 +268,8 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_LOAD(_val, ...) (0) #define ATOMIC_STORE(_val, _newval, ...) ((void)0) -#define ATOMIC_ADD(T, _val, _incr, ...) (0) -#define ATOMIC_SUB(T, _val, _decr, ...) (0) +#define ATOMIC_ADD(_val, _incr, ...) (0) +#define ATOMIC_SUB(_val, _decr, ...) (0) #define ATOMIC_EXCHANGE(T, _val, _newval, ...) (0) #define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0) @@ -300,9 +290,9 @@ inline void InitRef(RefCount *ptr, uint value) inline uint ReadRef(RefCount *ptr) { return ATOMIC_LOAD(ptr); } inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD(uint, ptr, 1)+1; } +{ return ATOMIC_ADD(ptr, 1)+1; } inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB(uint, ptr, 1)-1; } +{ return ATOMIC_SUB(ptr, 1)-1; } /* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non- -- cgit v1.2.3 From 82e8dd0525c0379f33da84e98ff72fe878cb75e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 15:32:31 -0700 Subject: Fix win32 atomic fallbacks --- include/atomic.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/atomic.h b/include/atomic.h index 1f6ceae2..f3ee96b6 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -185,10 +185,18 @@ inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) { return InterlockedExchangeAdd(dest, incr); } +inline LONGLONG AtomicAdd64(volatile LONGLONG *dest, LONGLONG incr) +{ + return InterlockedExchangeAdd64(dest, incr); +} inline LONG AtomicSub32(volatile LONG *dest, LONG decr) { return InterlockedExchangeAdd(dest, -decr); } +inline LONGLONG AtomicSub64(volatile LONGLONG *dest, LONGLONG decr) +{ + return InterlockedExchangeAdd64(dest, -decr); +} inline LONG AtomicSwap32(volatile LONG *dest, LONG newval) { @@ -212,7 +220,7 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG return old == *oldval; } -#define WRAP_ADDSUB(T, _func, _ptr, _amnt) (_func((T volatile*)(_ptr), (_amnt)) +#define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt)) #define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval)) #define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval)) @@ -240,9 +248,11 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_ADD(_val, _incr, ...) \ ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ + (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \ _al_invalid_atomic_size()) #define ATOMIC_SUB(_val, _decr, ...) \ ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ + (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ _al_invalid_atomic_size()) #define ATOMIC_EXCHANGE(T, _val, _newval, ...) \ -- cgit v1.2.3 From acc9f66baf7173da0f027df70e671d1edf513232 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 21:04:24 -0700 Subject: Clean up some ringbuffer atomic calls --- Alc/alcRing.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Alc/alcRing.c b/Alc/alcRing.c index d3059f86..2cb001bf 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -94,7 +94,7 @@ int ll_ringbuffer_mlock(ll_ringbuffer_t *rb) /* Reset the read and write pointers to zero. This is not thread safe. */ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { - ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_relaxed); + ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); memset(rb->buf, 0, rb->size*rb->elem_size); } @@ -103,17 +103,17 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) * elements in front of the read pointer and behind the write pointer. */ size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed); - return (rb->size+w-r) & rb->size_mask; + size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; + size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + return (w-r) & rb->size_mask; } /* Return the number of elements available for writing. This is the number of * elements in front of the write pointer and behind the read pointer. */ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed); - return (rb->size+r-w-1) & rb->size_mask; + size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; + size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + return (r-w-1) & rb->size_mask; } /* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. @@ -145,10 +145,11 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) } memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - read_ptr = (read_ptr + n1) & rb->size_mask; + read_ptr += n1; if(n2) { - memcpy(dest + n1*rb->elem_size, &rb->buf[read_ptr*rb->elem_size], n2*rb->elem_size); + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); read_ptr += n2; } ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); @@ -185,9 +186,12 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) } memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - read_ptr = (read_ptr + n1) & rb->size_mask; if(n2) - memcpy(dest + n1*rb->elem_size, &rb->buf[read_ptr*rb->elem_size], n2*rb->elem_size); + { + read_ptr += n1; + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); + } return to_read; } @@ -220,10 +224,11 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) } memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); - write_ptr = (write_ptr + n1) & rb->size_mask; + write_ptr += n1; if(n2) { - memcpy(&rb->buf[write_ptr*rb->elem_size], src + n1*rb->elem_size, n2*rb->elem_size); + memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, + n2*rb->elem_size); write_ptr += n2; } ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); @@ -252,8 +257,8 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data size_t w, r; w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - free_cnt = (rb->size+w-r) & rb->size_mask; + r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + free_cnt = (w-r) & rb->size_mask; cnt2 = r + free_cnt; if(cnt2 > rb->size) @@ -285,8 +290,8 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat size_t w, r; w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - free_cnt = (rb->size+r-w-1) & rb->size_mask; + r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + free_cnt = (r-w-1) & rb->size_mask; cnt2 = w + free_cnt; if(cnt2 > rb->size) -- cgit v1.2.3 From 939d16d57c2e766828848ab6b10b5e943f2ba024 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 23:29:33 -0700 Subject: Include the full JACK ringbuffer size for the device period count --- Alc/backends/jack.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 283df297..fa04c594 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -211,12 +211,14 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) ALCjackPlayback_lock(self); device->UpdateSize = numframes; device->NumUpdates = 2; - TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); bufsize = device->UpdateSize; if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); bufsize += device->UpdateSize; + device->NumUpdates = bufsize / device->UpdateSize; + + TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType)); @@ -248,8 +250,9 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) todo = minu(numframes, data[0].len); for(c = 0;c < numchans;c++) { + const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c; for(i = 0;i < todo;i++) - out[c][i] = ((ALfloat*)data[0].buf)[i*numchans + c]; + out[c][i] = in[i*numchans]; out[c] += todo; } total += todo; @@ -259,8 +262,9 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) { for(c = 0;c < numchans;c++) { + const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c; for(i = 0;i < todo;i++) - out[c][i] = ((ALfloat*)data[1].buf)[i*numchans + c]; + out[c][i] = in[i*numchans]; out[c] += todo; } total += todo; @@ -407,6 +411,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); bufsize += device->UpdateSize; + device->NumUpdates = bufsize / device->UpdateSize; /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; -- cgit v1.2.3 From 6a91d6a10ad90ec4923f94f36a428073d8cc4811 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Nov 2016 23:46:23 -0700 Subject: Add support for 8-byte types on inline assembly ATOMIC_ADD/SUB --- include/atomic.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/include/atomic.h b/include/atomic.h index f3ee96b6..1dcf9ec5 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -86,14 +86,14 @@ enum almemory_order { /* Atomics using x86/x86-64 GCC inline assembly */ #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define WRAP_ADD(ret, dest, incr) __asm__ __volatile__( \ - "lock; xaddl %0,(%1)" \ +#define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \ + "lock; xadd"S" %0,(%1)" \ : "=r" (ret) \ : "r" (dest), "0" (incr) \ : "memory" \ ) -#define WRAP_SUB(ret, dest, decr) __asm__ __volatile__( \ - "lock; xaddl %0,(%1)" \ +#define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \ + "lock; xadd"S" %0,(%1)" \ : "=r" (ret) \ : "r" (dest), "0" (-(decr)) \ : "memory" \ @@ -137,14 +137,18 @@ enum almemory_order { (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(_val, _incr, ...) __extension__({ \ +#define ATOMIC_ADD(_val, _incr, ...) __extension__({ \ + static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ __typeof((_val)->value) _r; \ - WRAP_ADD(_r, &(_val)->value, _incr); \ + if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \ + else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \ _r; \ }) -#define ATOMIC_SUB(_val, _decr, ...) __extension__({ \ +#define ATOMIC_SUB(_val, _decr, ...) __extension__({ \ + static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ __typeof((_val)->value) _r; \ - WRAP_SUB(_r, &(_val)->value, _decr); \ + if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \ + else if(sizeof((_val)->value) == 8) WRAP_SUB("q", _r, &(_val)->value, _decr); \ _r; \ }) -- cgit v1.2.3 From 0532acdf94c9a63d4d8d9b8f634063e2e63879b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Nov 2016 12:37:07 -0800 Subject: Don't use 0 for a resource ID --- Alc/hrtf.c | 4 ++-- Alc/hrtf_res.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index cd9656bc..7786befc 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -878,8 +878,8 @@ done: #ifndef ALSOFT_EMBED_HRTF_DATA -#define IDR_DEFAULT_44100_MHR 0 -#define IDR_DEFAULT_48000_MHR 1 +#define IDR_DEFAULT_44100_MHR 1 +#define IDR_DEFAULT_48000_MHR 2 static const ALubyte *GetResource(int UNUSED(name), size_t *size) { diff --git a/Alc/hrtf_res.h b/Alc/hrtf_res.h index 027e49de..2dc39cf1 100644 --- a/Alc/hrtf_res.h +++ b/Alc/hrtf_res.h @@ -1,5 +1,5 @@ #define MHRTYPE 256 -#define IDR_DEFAULT_44100_MHR 0 -#define IDR_DEFAULT_48000_MHR 1 +#define IDR_DEFAULT_44100_MHR 1 +#define IDR_DEFAULT_48000_MHR 2 -- cgit v1.2.3 From 9ef7719734505d04d093ee85fb39b4777816d6ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Nov 2016 21:51:45 -0800 Subject: Try to make embedded HRTF data sets work on OSX --- Alc/hrtf.c | 25 +++++++++++++++++++++++++ CMakeLists.txt | 16 ++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 7786befc..ba7ad068 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -908,6 +908,31 @@ static const ALubyte *GetResource(int name, size_t *size) return LockResource(res); } +#elif defined(__APPLE__) + +#include +#include + +static const ALubyte *GetResource(int name, size_t *size) +{ +#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070) + /* NOTE: OSX 10.7 and up need to call getsectiondata(&_mh_execute_header, ...). However, that + * call requires 10.7. + */ + if(name == IDR_DEFAULT_44100_MHR) + return getsectiondata(&_mh_execute_header, "binary", "default_44100_mhr", size); + if(name == IDR_DEFAULT_48000_MHR) + return getsectiondata(&_mh_execute_header, "binary", "default_48000_mhr", size); +#else + if(name == IDR_DEFAULT_44100_MHR) + return getsectdata("binary", "default_44100_mhr", size); + if(name == IDR_DEFAULT_48000_MHR) + return getsectdata("binary", "default_48000_mhr", size); +#endif + *size = 0; + return NULL; +} + #else extern const ALubyte _binary_default_44100_mhr_start[] HIDDEN_DECL; diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e371bc3..e6e5f0f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1108,6 +1108,22 @@ option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library foot if(ALSOFT_EMBED_HRTF_DATA) if(WIN32) set(ALC_OBJS ${ALC_OBJS} Alc/hrtf_res.rc) + elseif(APPLE) + macro(add_custom_binary FILENAME BIN_NAME) + set(outfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}) + set(stubfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}.stub${CMAKE_C_OUTPUT_EXTENSION}) + add_custom_command(OUTPUT ${outfile} + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/hrtf/${FILENAME}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/hrtf" + COMMAND "${CMAKE_C_COMPILER}" -o "${stubfile}" -c /dev/null + COMMAND "${CMAKE_LINKER}" -r -o "${outfile}" -sectcreate binary ${BIN_NAME} ${FILENAME} "${stubfile}" + COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" + VERBATIM + ) + set(ALC_OBJS ${ALC_OBJS} ${outfile}) + endmacro() + add_custom_binary(default-44100.mhr "default_44100_mhr") + add_custom_binary(default-48000.mhr "default_48000_mhr") else() set(FILENAMES default-44100.mhr default-48000.mhr) foreach(FILENAME ${FILENAMES}) -- cgit v1.2.3 From e69af7ab9256507145fdababd092396e85deb651 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Nov 2016 13:14:02 -0800 Subject: Fixes for embedded HRTFs on OSX Use an empty source file to build a stub object file, instead of /dev/null. Use _mh_dylib_header to retrieve the data on 10.7+, instead of _mh_execute_header. And shorten the names to fit in the 16-character limit. Thanks to Anna Cheremnykh for the fixes! --- Alc/hrtf.c | 11 ++++++----- CMakeLists.txt | 8 +++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index ba7ad068..b3b795ac 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -912,22 +912,23 @@ static const ALubyte *GetResource(int name, size_t *size) #include #include +#include static const ALubyte *GetResource(int name, size_t *size) { #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070) - /* NOTE: OSX 10.7 and up need to call getsectiondata(&_mh_execute_header, ...). However, that + /* NOTE: OSX 10.7 and up need to call getsectiondata(&_mh_dylib_header, ...). However, that * call requires 10.7. */ if(name == IDR_DEFAULT_44100_MHR) - return getsectiondata(&_mh_execute_header, "binary", "default_44100_mhr", size); + return getsectiondata(&_mh_dylib_header, "binary", "default_44100", size); if(name == IDR_DEFAULT_48000_MHR) - return getsectiondata(&_mh_execute_header, "binary", "default_48000_mhr", size); + return getsectiondata(&_mh_dylib_header, "binary", "default_48000", size); #else if(name == IDR_DEFAULT_44100_MHR) - return getsectdata("binary", "default_44100_mhr", size); + return getsectdata("binary", "default_44100", size); if(name == IDR_DEFAULT_48000_MHR) - return getsectdata("binary", "default_48000_mhr", size); + return getsectdata("binary", "default_48000", size); #endif *size = 0; return NULL; diff --git a/CMakeLists.txt b/CMakeLists.txt index e6e5f0f6..7cd3ca36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1111,19 +1111,21 @@ if(ALSOFT_EMBED_HRTF_DATA) elseif(APPLE) macro(add_custom_binary FILENAME BIN_NAME) set(outfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}) + set(stubsrcfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}.stub.c) set(stubfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}.stub${CMAKE_C_OUTPUT_EXTENSION}) add_custom_command(OUTPUT ${outfile} DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/hrtf/${FILENAME}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/hrtf" - COMMAND "${CMAKE_C_COMPILER}" -o "${stubfile}" -c /dev/null + COMMAND touch "${stubsrcfile}" + COMMAND "${CMAKE_C_COMPILER}" -o "${stubfile}" -c "${stubsrcfile}" COMMAND "${CMAKE_LINKER}" -r -o "${outfile}" -sectcreate binary ${BIN_NAME} ${FILENAME} "${stubfile}" COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" VERBATIM ) set(ALC_OBJS ${ALC_OBJS} ${outfile}) endmacro() - add_custom_binary(default-44100.mhr "default_44100_mhr") - add_custom_binary(default-48000.mhr "default_48000_mhr") + add_custom_binary(default-44100.mhr "default_44100") + add_custom_binary(default-48000.mhr "default_48000") else() set(FILENAMES default-44100.mhr default-48000.mhr) foreach(FILENAME ${FILENAMES}) -- cgit v1.2.3 From b743bc1c1b45683314f18f3f3c8f171c2cb1a4d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 11 Nov 2016 13:19:45 -0800 Subject: Remove the temporary stub files after the output object is made --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cd3ca36..3dd51d48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1119,6 +1119,7 @@ if(ALSOFT_EMBED_HRTF_DATA) COMMAND touch "${stubsrcfile}" COMMAND "${CMAKE_C_COMPILER}" -o "${stubfile}" -c "${stubsrcfile}" COMMAND "${CMAKE_LINKER}" -r -o "${outfile}" -sectcreate binary ${BIN_NAME} ${FILENAME} "${stubfile}" + COMMAND rm "${stubsrcfile}" "${stubfile}" COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" VERBATIM ) -- cgit v1.2.3 From caead294f292cb6a8d75eaa4eeb26829a06f569c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Nov 2016 22:04:16 -0800 Subject: Update a function comment about its input --- Alc/uhjfilter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 14572bc3..cec3463e 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -42,7 +42,8 @@ typedef struct Uhj2Encoder { } Uhj2Encoder; /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input - * signal. */ + * signal. The input must use FuMa channel ordering and scaling. + */ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); #endif /* UHJFILTER_H */ -- cgit v1.2.3 From a502a41be340826585f9c91b3a8d9a52b5601b54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Nov 2016 00:46:46 -0800 Subject: Stop using almemory_order_consume --- Alc/ALc.c | 4 ++-- OpenAL32/alAuxEffectSlot.c | 2 +- OpenAL32/alListener.c | 2 +- OpenAL32/alSource.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7e220205..8c855157 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2377,10 +2377,10 @@ static void FreeContext(ALCcontext *context) al_free(lprops); } count = 0; - lprops = ATOMIC_LOAD(&listener->FreeList, almemory_order_consume); + lprops = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire); while(lprops) { - struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_consume); + struct ALlistenerProps *next = ATOMIC_LOAD(&lprops->next, almemory_order_acquire); al_free(lprops); lprops = next; ++count; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index b860b2b0..4f1601ed 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -647,7 +647,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, &slot->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_consume) == 0); + almemory_order_acquire) == 0); } /* Copy in current property values. */ diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 08ece19d..4e99f24e 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -470,7 +470,7 @@ void UpdateListenerProps(ALCcontext *context) next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, &listener->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_consume) == 0); + almemory_order_acquire) == 0); } /* Copy in current property values. */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f20498f4..7f187dfe 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2829,7 +2829,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, &source->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_consume) == 0); + almemory_order_acquire) == 0); } /* Copy in current property values. */ -- cgit v1.2.3 From 8bf4fe2eea11afd753e25dd495c26e6522436b5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Nov 2016 21:38:49 -0800 Subject: Update some atomic memory ordering --- Alc/ALu.c | 15 +++++++++------ Alc/mixer.c | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index cc01f336..b90a3983 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -293,11 +293,12 @@ static ALboolean CalcListenerParams(ALCcontext *Context) * in the old container (practically impossible with this little code, * but...). */ - first = ATOMIC_LOAD(&Listener->FreeList); + first = ATOMIC_LOAD(&Listener->FreeList, almemory_order_acquire); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, - &Listener->FreeList, &first, props) == 0); + &Listener->FreeList, &first, props, almemory_order_acq_rel, + almemory_order_acquire) == 0); return AL_TRUE; } @@ -341,11 +342,12 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) * in the old container (practically impossible with this little code, * but...). */ - first = ATOMIC_LOAD(&slot->FreeList); + first = ATOMIC_LOAD(&slot->FreeList, almemory_order_acquire); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, - &slot->FreeList, &first, props) == 0); + &slot->FreeList, &first, props, almemory_order_acq_rel, + almemory_order_acquire) == 0); return AL_TRUE; } @@ -1314,11 +1316,12 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc * actually swap in the old container (practically impossible with this * little code, but...). */ - first = ATOMIC_LOAD(&source->FreeList); + first = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props) == 0); + &source->FreeList, &first, props, almemory_order_acq_rel, + almemory_order_acquire) == 0); } BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); diff --git a/Alc/mixer.c b/Alc/mixer.c index 727d0640..dba429a0 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -399,7 +399,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam /* Get source info */ State = AL_PLAYING; /* Only called while playing. */ - BufferListItem = ATOMIC_LOAD(&Source->current_buffer); + BufferListItem = ATOMIC_LOAD(&Source->current_buffer, almemory_order_acquire); DataPosInt = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); DataPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); @@ -696,5 +696,5 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Source->state = State; ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed); ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, DataPosFrac); + ATOMIC_STORE(&Source->position_fraction, DataPosFrac, almemory_order_release); } -- cgit v1.2.3 From 616adea4cc0629c7ce20a2c7e713342cadc26435 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Nov 2016 23:58:28 -0800 Subject: Improve seqlock behavior --- OpenAL32/alSource.c | 56 ++++++++++++++++++++++++++++++----------------------- include/atomic.h | 23 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 7f187dfe..78aaf61d 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2658,11 +2658,12 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint /* Once the active mix (if any) is done, it's safe to cut the old tail * from the new head. */ - if(((count=ReadRef(&device->MixCount))&1) != 0) + if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) { - while(count == ReadRef(&device->MixCount)) + while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)) althrd_yield(); } + ATOMIC_THREAD_FENCE(almemory_order_acq_rel); OldTail->next = NULL; } WriteUnlock(&source->queue_lock); @@ -2828,7 +2829,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &props, next, almemory_order_seq_cst, + &source->FreeList, &props, next, almemory_order_acq_rel, almemory_order_acquire) == 0); } @@ -2903,7 +2904,8 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props) == 0); + &source->FreeList, &first, props, almemory_order_acq_rel, + almemory_order_acquire) == 0); } } @@ -2954,7 +2956,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->state = AL_PLAYING; ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0); + ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); discontinuity = AL_TRUE; } else @@ -2979,19 +2981,20 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) * unused active source slot to put it in. */ for(i = 0;i < Context->VoiceCount;i++) { - ALsource *old = Source; - if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL)) + if(Context->Voices[i].Source == Source) { - if(voice == NULL) - { + if(voice != NULL) + Context->Voices[i].Source = NULL; + else voice = &Context->Voices[i]; - voice->Source = Source; - } break; } - old = NULL; - if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source)) + + if(!voice && !Context->Voices[i].Source) + { voice = &Context->Voices[i]; + voice->Source = Source; + } } if(voice == NULL) { @@ -3075,15 +3078,16 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint { ReadUnlock(&Source->queue_lock); do { - while(((refcount=ReadRef(&device->MixCount))&1)) + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - } while(refcount != ReadRef(&device->MixCount)); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); return 0; } do { - while(((refcount=ReadRef(&device->MixCount))&1)) + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); @@ -3093,7 +3097,8 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); - } while(refcount != ReadRef(&device->MixCount)); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); while(BufferList && BufferList != Current) { if(BufferList->buffer) @@ -3123,15 +3128,16 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 { ReadUnlock(&Source->queue_lock); do { - while(((refcount=ReadRef(&device->MixCount))&1)) + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - } while(refcount != ReadRef(&device->MixCount)); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); return 0.0; } do { - while(((refcount=ReadRef(&device->MixCount))&1)) + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); @@ -3140,7 +3146,8 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<position_fraction, almemory_order_relaxed); - } while(refcount != ReadRef(&device->MixCount)); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); while(BufferList && BufferList != Current) { const ALbuffer *buffer = BufferList->buffer; @@ -3190,7 +3197,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device totalBufferLen = 0; do { - while(((refcount=ReadRef(&device->MixCount))&1)) + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); @@ -3199,7 +3206,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); - } while(refcount != ReadRef(&device->MixCount)); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); while(BufferList != NULL) { @@ -3295,7 +3303,7 @@ ALboolean ApplyOffset(ALsource *Source) ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, frac); + ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release); return AL_TRUE; } diff --git a/include/atomic.h b/include/atomic.h index 1dcf9ec5..7d743286 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -42,6 +42,8 @@ extern "C" { #define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \ PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) +#define ATOMIC_THREAD_FENCE atomic_thread_fence + /* Atomics using GCC intrinsics */ #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) @@ -83,6 +85,13 @@ enum almemory_order { *(_oldval) == _o; \ }) +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + __asm__ __volatile__("" ::: "memory"); \ +} while(0) + /* Atomics using x86/x86-64 GCC inline assembly */ #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) @@ -169,6 +178,13 @@ enum almemory_order { *(_oldval) == _old; \ }) +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + __asm__ __volatile__("" ::: "memory"); \ +} while(0) + /* Atomics using Windows methods */ #elif defined(_WIN32) @@ -268,6 +284,13 @@ int _al_invalid_atomic_size(); /* not defined */ (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ (bool)_al_invalid_atomic_size()) +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + _ReadWriteBarrier(); \ +} while(0) + #else #error "No atomic functions available on this platform!" -- cgit v1.2.3 From 01babb69d25fd23bde0fdf5ed525bb82934ce6fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Nov 2016 02:28:18 -0800 Subject: Clean up finding a source's voice --- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 55 ++++++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index b288937a..d5eb3c50 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -78,7 +78,7 @@ struct ALsourceProps { typedef struct ALvoice { struct ALsourceProps Props; - struct ALsource *volatile Source; + struct ALsource *Source; /** Current target parameters used for mixing. */ ALint Step; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 78aaf61d..b65c2c18 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -125,6 +125,18 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); +static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context) +{ + ALvoice *voice = context->Voices; + ALvoice *voice_end = voice + context->VoiceCount; + while(voice != voice_end) + { + if(voice->Source == source) + return voice; + } + return NULL; +} + static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) { return (source->state == AL_PLAYING || source->state == AL_PAUSED) && @@ -1584,22 +1596,15 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) } for(i = 0;i < n;i++) { - ALvoice *voice, *voice_end; + ALvoice *voice; if((Source=RemoveSource(context, sources[i])) == NULL) continue; FreeThunkEntry(Source->id); LockContext(context); - voice = context->Voices; - voice_end = voice + context->VoiceCount; - while(voice != voice_end) - { - ALsource *old = Source; - if(COMPARE_EXCHANGE(&voice->Source, &old, NULL)) - break; - voice++; - } + voice = GetSourceVoice(Source, context); + if(voice) voice->Source = NULL; UnlockContext(context); DeinitSource(Source); @@ -2977,29 +2982,27 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(!BufferList || !device->Connected) goto do_stop; - /* Make sure this source isn't already active, while looking for an - * unused active source slot to put it in. */ - for(i = 0;i < Context->VoiceCount;i++) + /* Make sure this source isn't already active, and if not, look for an + * unused voice to put it in. + */ + voice = GetSourceVoice(Source, Context); + if(voice == NULL) { - if(Context->Voices[i].Source == Source) + for(i = 0;i < Context->VoiceCount;i++) { - if(voice != NULL) - Context->Voices[i].Source = NULL; - else + if(Context->Voices[i].Source == NULL) + { voice = &Context->Voices[i]; - break; + voice->Source = Source; + break; + } } - - if(!voice && !Context->Voices[i].Source) + if(voice == NULL) { - voice = &Context->Voices[i]; + voice = &Context->Voices[Context->VoiceCount++]; voice->Source = Source; } - } - if(voice == NULL) - { - voice = &Context->Voices[Context->VoiceCount++]; - voice->Source = Source; + discontinuity = AL_TRUE; } if(discontinuity) -- cgit v1.2.3 From c6189717580453b03cc70f0647a215f3f5f886fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Nov 2016 03:00:16 -0800 Subject: Remove the non-atomic COMPARE_EXCHANGE macro --- Alc/ALc.c | 79 +++++++++++++++++++++++++++++++++----------------------- include/atomic.h | 5 ---- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8c855157..9d3467f7 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2402,7 +2402,6 @@ static void FreeContext(ALCcontext *context) */ static void ReleaseContext(ALCcontext *context, ALCdevice *device) { - ALCcontext *nextctx; ALCcontext *origctx; if(altss_get(LocalContext) == context) @@ -2418,14 +2417,18 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) ALCdevice_Lock(device); origctx = context; - nextctx = context->next; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, nextctx)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, context->next)) { - ALCcontext *list; - do { - list = origctx; - origctx = context; - } while(!COMPARE_EXCHANGE(&list->next, &origctx, nextctx)); + ALCcontext *volatile*list = &origctx->next; + while(*list) + { + if(*list == context) + { + *list = (*list)->next; + break; + } + list = &(*list)->next; + } } ALCdevice_Unlock(device); @@ -3618,31 +3621,36 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) */ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) { - ALCdevice *list, *origdev, *nextdev; + ALCdevice *iter, *origdev; ALCcontext *ctx; LockLists(); - list = ATOMIC_LOAD(&DeviceList); + iter = ATOMIC_LOAD(&DeviceList); do { - if(list == device) + if(iter == device) break; - } while((list=list->next) != NULL); - if(!list || list->Type == Capture) + } while((iter=iter->next) != NULL); + if(!iter || iter->Type == Capture) { - alcSetError(list, ALC_INVALID_DEVICE); + alcSetError(iter, ALC_INVALID_DEVICE); UnlockLists(); return ALC_FALSE; } almtx_lock(&device->BackendLock); origdev = device; - nextdev = device->next; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, nextdev)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, device->next)) { - do { - list = origdev; - origdev = device; - } while(!COMPARE_EXCHANGE(&list->next, &origdev, nextdev)); + ALCdevice *volatile*list = &origdev->next; + while(*list) + { + if(*list == device) + { + *list = (*list)->next; + break; + } + list = &(*list)->next; + } } UnlockLists(); @@ -3769,29 +3777,34 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { - ALCdevice *list, *next, *nextdev; + ALCdevice *iter, *origdev; LockLists(); - list = ATOMIC_LOAD(&DeviceList); + iter = ATOMIC_LOAD(&DeviceList); do { - if(list == device) + if(iter == device) break; - } while((list=list->next) != NULL); - if(!list || list->Type != Capture) + } while((iter=iter->next) != NULL); + if(!iter || iter->Type != Capture) { - alcSetError(list, ALC_INVALID_DEVICE); + alcSetError(iter, ALC_INVALID_DEVICE); UnlockLists(); return ALC_FALSE; } - next = device; - nextdev = device->next; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &next, nextdev)) + origdev = device; + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, device->next)) { - do { - list = next; - next = device; - } while(!COMPARE_EXCHANGE(&list->next, &next, nextdev)); + ALCdevice *volatile*list = &origdev->next; + while(*list) + { + if(*list == device) + { + *list = (*list)->next; + break; + } + list = &(*list)->next; + } } UnlockLists(); diff --git a/include/atomic.h b/include/atomic.h index 7d743286..3a662f8e 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -332,11 +332,6 @@ inline uint DecrementRef(RefCount *ptr) { return ATOMIC_SUB(ptr, 1)-1; } -/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non- - * atomic variables. */ -#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false)) - - #ifdef __cplusplus } #endif -- cgit v1.2.3 From 8492c2845d805c540c115ca8c8efc552dbf2db0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Nov 2016 03:40:15 -0800 Subject: Avoid some unnecessary seq_cst memory ordering --- common/rwlock.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/common/rwlock.c b/common/rwlock.c index cfa3aee4..f1a86fa6 100644 --- a/common/rwlock.c +++ b/common/rwlock.c @@ -11,10 +11,10 @@ /* A simple spinlock. Yield the thread while the given integer is set by * another. Could probably be improved... */ #define LOCK(l) do { \ - while(ATOMIC_EXCHANGE(int, &(l), true) == true) \ + while(ATOMIC_EXCHANGE(int, &(l), true, almemory_order_acq_rel) == true) \ althrd_yield(); \ } while(0) -#define UNLOCK(l) ATOMIC_STORE(&(l), false) +#define UNLOCK(l) ATOMIC_STORE(&(l), false, almemory_order_release) void RWLockInit(RWLock *lock) @@ -30,7 +30,8 @@ void ReadLock(RWLock *lock) { LOCK(lock->read_entry_lock); LOCK(lock->read_lock); - if(IncrementRef(&lock->read_count) == 1) + /* NOTE: ATOMIC_ADD returns the *old* value! */ + if(ATOMIC_ADD(&lock->read_count, 1, almemory_order_acq_rel) == 0) LOCK(lock->write_lock); UNLOCK(lock->read_lock); UNLOCK(lock->read_entry_lock); @@ -38,13 +39,14 @@ void ReadLock(RWLock *lock) void ReadUnlock(RWLock *lock) { - if(DecrementRef(&lock->read_count) == 0) + /* NOTE: ATOMIC_SUB returns the *old* value! */ + if(ATOMIC_SUB(&lock->read_count, 1, almemory_order_acq_rel) == 1) UNLOCK(lock->write_lock); } void WriteLock(RWLock *lock) { - if(IncrementRef(&lock->write_count) == 1) + if(ATOMIC_ADD(&lock->write_count, 1, almemory_order_acq_rel) == 0) LOCK(lock->read_lock); LOCK(lock->write_lock); } @@ -52,6 +54,6 @@ void WriteLock(RWLock *lock) void WriteUnlock(RWLock *lock) { UNLOCK(lock->write_lock); - if(DecrementRef(&lock->write_count) == 0) + if(ATOMIC_SUB(&lock->write_count, 1, almemory_order_acq_rel) == 1) UNLOCK(lock->read_lock); } -- cgit v1.2.3 From 49fd154829604cbe050e51694aa4932a6e00609d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Nov 2016 14:50:55 -0800 Subject: Update cmake scripts to handle policy 0054 --- CMakeLists.txt | 3 +++ cmake/CheckSharedFunctionExists.cmake | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd51d48..6ec81aed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ IF(COMMAND CMAKE_POLICY) IF(POLICY CMP0042) CMAKE_POLICY(SET CMP0042 NEW) ENDIF(POLICY CMP0042) + IF(POLICY CMP0054) + CMAKE_POLICY(SET CMP0054 NEW) + ENDIF(POLICY CMP0054) ENDIF(COMMAND CMAKE_POLICY) SET(CMAKE_MODULE_PATH "${OpenAL_SOURCE_DIR}/cmake") diff --git a/cmake/CheckSharedFunctionExists.cmake b/cmake/CheckSharedFunctionExists.cmake index 7975f233..c691fa9c 100644 --- a/cmake/CheckSharedFunctionExists.cmake +++ b/cmake/CheckSharedFunctionExists.cmake @@ -34,7 +34,7 @@ # License text for the above reference.) MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE) - IF("${VARIABLE}" MATCHES "^${VARIABLE}$") + IF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") SET(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n") SET(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS}) IF(CMAKE_REQUIRED_LIBRARIES) @@ -88,5 +88,5 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE) "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") ENDIF(${VARIABLE}) - ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$") + ENDIF(NOT DEFINED "${VARIABLE}" OR "x${${VARIABLE}}" STREQUAL "x${VARIABLE}") ENDMACRO(CHECK_SHARED_FUNCTION_EXISTS) -- cgit v1.2.3 From fcb669f803d37be80492879801fba9c9011f7edf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Nov 2016 15:47:46 -0800 Subject: Set the windows subsystem for DLLs on MSVC and GCC on Windows --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ec81aed..7a02a48f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1235,6 +1235,14 @@ ENDIF() IF(HAVE_JACK) SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) ENDIF() +IF(WIN32) + IF(MSVC) + SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS") + ELSEIF(CMAKE_COMPILER_IS_GNUCC) + SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " -mwindows") + ENDIF() +ENDIF() + SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") @@ -1252,7 +1260,7 @@ IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") ENDIF() ELSE() - SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES LINK_FLAGS "-Wl,--output-def,${LIBNAME}.def") + SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,${LIBNAME}.def") ADD_CUSTOM_COMMAND(TARGET ${LIBNAME} POST_BUILD COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" ${LIBNAME}.def COMMAND "${DLLTOOL_EXECUTABLE}" -d ${LIBNAME}.def -l ${LIBNAME}.lib -D ${LIBNAME}.dll -- cgit v1.2.3 From 6886f77cbc02b93db3682acb27eb767c6541fba0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Nov 2016 01:31:13 -0800 Subject: Only send source updates for sources that have updated --- Alc/ALc.c | 3 ++- OpenAL32/Include/alSource.h | 2 ++ OpenAL32/alSource.c | 11 ++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 9d3467f7..2e7c1e7f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2141,10 +2141,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) source->Send[s].LFReference = HIGHPASSFREQREF; s++; } + source->NeedsUpdate = AL_TRUE; } UnlockUIntMapRead(&context->SourceMap); - UpdateAllSourceProps(context); + UpdateListenerProps(context); ReadUnlock(&context->PropLock); context = context->next; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index d5eb3c50..8b793102 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -197,6 +197,8 @@ typedef struct ALsource { ALuint NumChannels; ALuint SampleSize; + ALenum NeedsUpdate; + ATOMIC(struct ALsourceProps*) Update; ATOMIC(struct ALsourceProps*) FreeList; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b65c2c18..9ef58115 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -399,6 +399,8 @@ static ALint Int64ValsByProp(ALenum prop) #define DO_UPDATEPROPS() do { \ if(SourceShouldUpdate(Source, Context)) \ UpdateSourceProps(Source, device->NumAuxSends); \ + else \ + Source->NeedsUpdate = AL_TRUE; \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -2772,6 +2774,8 @@ static void InitSourceParams(ALsource *Source) ATOMIC_INIT(&Source->looping, AL_FALSE); + Source->NeedsUpdate = AL_TRUE; + ATOMIC_INIT(&Source->Update, NULL); ATOMIC_INIT(&Source->FreeList, NULL); } @@ -2924,8 +2928,12 @@ void UpdateAllSourceProps(ALCcontext *context) ALvoice *voice = &context->Voices[pos]; ALsource *source = voice->Source; if(source != NULL && (source->state == AL_PLAYING || - source->state == AL_PAUSED)) + source->state == AL_PAUSED) && + source->NeedsUpdate) + { + source->NeedsUpdate = AL_FALSE; UpdateSourceProps(source, num_sends); + } } } @@ -3029,6 +3037,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } + Source->NeedsUpdate = AL_FALSE; UpdateSourceProps(Source, device->NumAuxSends); } else if(state == AL_PAUSED) -- cgit v1.2.3 From 10473285bae659a3ae863df177564ef208d84b1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 Nov 2016 01:32:14 -0800 Subject: Fix an infinite loop --- OpenAL32/alSource.c | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 9ef58115..81cd44cd 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -133,6 +133,7 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * { if(voice->Source == source) return voice; + ++voice; } return NULL; } -- cgit v1.2.3 From ea82a6d19ef39679afd8a83f069dcd12afe20e40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 Nov 2016 21:29:53 -0800 Subject: Use a function to generate the up-sampler transcode matrix --- Alc/bformatdec.c | 110 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 2aab4ed8..5556c2ef 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -135,7 +135,7 @@ static const ALfloat Ambi2DDecoder[4][FB_Max][MAX_AMBI_COEFFS] = { { { 0.353553f, 0.204094f, 0.0f, -0.204094f }, { 0.25f, 0.204094f, 0.0f, -0.204094f } }, { { 0.353553f, -0.204094f, 0.0f, -0.204094f }, { 0.25f, -0.204094f, 0.0f, -0.204094f } }, }; -static ALfloat Ambi2DEncoder[4][MAX_AMBI_COEFFS]; +static ALfloat Ambi2DEncoderT[4][MAX_AMBI_COEFFS]; /* These points are in AL coordinates! */ static const ALfloat Ambi3DPoints[8][3] = { @@ -158,7 +158,7 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; -static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS]; +static ALfloat Ambi3DEncoderT[8][MAX_AMBI_COEFFS]; static RowMixerFunc MixMatrixRow = MixRow_C; @@ -173,20 +173,53 @@ static void init_bformatdec(void) MixMatrixRow = SelectRowMixer(); for(i = 0;i < COUNTOF(Ambi3DPoints);i++) - CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoder[i]); + CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoderT[i]); for(i = 0;i < COUNTOF(Ambi2DPoints);i++) { - CalcDirectionCoeffs(Ambi2DPoints[i], 0.0f, Ambi2DEncoder[i]); + CalcDirectionCoeffs(Ambi2DPoints[i], 0.0f, Ambi2DEncoderT[i]); /* Remove the skipped height-related coefficients for 2D rendering. */ - Ambi2DEncoder[i][2] = Ambi2DEncoder[i][3]; - Ambi2DEncoder[i][3] = Ambi2DEncoder[i][4]; - Ambi2DEncoder[i][4] = Ambi2DEncoder[i][8]; - Ambi2DEncoder[i][5] = Ambi2DEncoder[i][9]; - Ambi2DEncoder[i][6] = Ambi2DEncoder[i][15]; + Ambi2DEncoderT[i][2] = Ambi2DEncoderT[i][3]; + Ambi2DEncoderT[i][3] = Ambi2DEncoderT[i][4]; + Ambi2DEncoderT[i][4] = Ambi2DEncoderT[i][8]; + Ambi2DEncoderT[i][5] = Ambi2DEncoderT[i][9]; + Ambi2DEncoderT[i][6] = Ambi2DEncoderT[i][15]; for(j = 7;j < MAX_AMBI_COEFFS;j++) - Ambi2DEncoder[i][j] = 0.0f; + Ambi2DEncoderT[i][j] = 0.0f; + } +} + + +/* This typedef is needed for SAFE_CONST to work. */ +typedef ALfloat ALfloatMAX_AMBI_COEFFS[MAX_AMBI_COEFFS]; + +static void GenUpsamplerGains(const ALfloat (*restrict EncoderT)[MAX_AMBI_COEFFS], + const ALfloat (*restrict Decoder)[FB_Max][MAX_AMBI_COEFFS], + ALsizei InChannels, + ALfloat (*restrict OutGains)[MAX_OUTPUT_CHANNELS][FB_Max], + ALsizei OutChannels) +{ + ALsizei i, j, k; + + /* Combine the matrices that do the in->virt and virt->out conversions so + * we get a single in->out conversion. NOTE: the Encoder matrix and output + * are transposed, so the input channels line up with the rows and the + * output channels line up with the columns. + */ + for(i = 0;i < 4;i++) + { + for(j = 0;j < OutChannels;j++) + { + ALfloat hfgain=0.0f, lfgain=0.0f; + for(k = 0;k < InChannels;k++) + { + hfgain += Decoder[k][FB_HighFreq][i]*EncoderT[k][j]; + lfgain += Decoder[k][FB_LowFreq][i]*EncoderT[k][j]; + } + OutGains[i][j][FB_HighFreq] = hfgain; + OutGains[i][j][FB_LowFreq] = lfgain; + } } } @@ -272,7 +305,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, const ALfloat *coeff_scale = UnitScale; ALfloat distgain[MAX_OUTPUT_CHANNELS]; ALfloat maxdist, ratio; - ALuint i, j, k; + ALuint i; al_free(dec->Samples); dec->Samples = NULL; @@ -300,39 +333,16 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, memset(dec->UpSampler.Gains, 0, sizeof(dec->UpSampler.Gains)); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - /* Combine the matrices that do the in->virt and virt->out conversions - * so we get a single in->out conversion. - */ - for(i = 0;i < 4;i++) - { - for(j = 0;j < dec->NumChannels;j++) - { - ALfloat *gains = dec->UpSampler.Gains[i][j]; - for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - { - gains[FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*Ambi3DEncoder[k][j]; - gains[FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*Ambi3DEncoder[k][j]; - } - } - } - + GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,Ambi3DEncoderT), + Ambi3DDecoder, COUNTOF(Ambi3DDecoder), + dec->UpSampler.Gains, dec->NumChannels); dec->Periphonic = AL_TRUE; } else { - for(i = 0;i < 4;i++) - { - for(j = 0;j < dec->NumChannels;j++) - { - ALfloat *gains = dec->UpSampler.Gains[i][j]; - for(k = 0;k < COUNTOF(Ambi2DDecoder);k++) - { - gains[FB_HighFreq] += Ambi2DDecoder[k][FB_HighFreq][i]*Ambi2DEncoder[k][j]; - gains[FB_LowFreq] += Ambi2DDecoder[k][FB_LowFreq][i]*Ambi2DEncoder[k][j]; - } - } - } - + GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,Ambi2DEncoderT), + Ambi2DDecoder, COUNTOF(Ambi2DDecoder), + dec->UpSampler.Gains, dec->NumChannels); dec->Periphonic = AL_FALSE; } @@ -627,27 +637,19 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { ALfloat gains[8][MAX_OUTPUT_CHANNELS]; ALfloat ratio; - ALuint i, j, k; + ALuint i; ratio = 400.0f / (ALfloat)device->Frequency; for(i = 0;i < 4;i++) bandsplit_init(&ambiup->XOver[i], ratio); - for(i = 0;i < COUNTOF(Ambi3DEncoder);i++) - ComputePanningGains(device->Dry, Ambi3DEncoder[i], 1.0f, gains[i]); + for(i = 0;i < COUNTOF(Ambi3DEncoderT);i++) + ComputePanningGains(device->Dry, Ambi3DEncoderT[i], 1.0f, gains[i]); memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); - for(i = 0;i < 4;i++) - { - for(j = 0;j < device->Dry.NumChannels;j++) - { - for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - { - ambiup->Gains[i][j][FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*gains[k][j]; - ambiup->Gains[i][j][FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*gains[k][j]; - } - } - } + GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,gains), + Ambi3DDecoder, COUNTOF(Ambi3DDecoder), + ambiup->Gains, device->Dry.NumChannels); } void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) -- cgit v1.2.3 From 02a6031d03870847aa6b11628b80585004b45194 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 25 Nov 2016 23:25:16 -0800 Subject: Use atomic flags for boolean atomic locks --- common/rwlock.c | 10 +++++----- include/atomic.h | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- include/rwlock.h | 9 ++++----- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/common/rwlock.c b/common/rwlock.c index f1a86fa6..67cf3acf 100644 --- a/common/rwlock.c +++ b/common/rwlock.c @@ -11,19 +11,19 @@ /* A simple spinlock. Yield the thread while the given integer is set by * another. Could probably be improved... */ #define LOCK(l) do { \ - while(ATOMIC_EXCHANGE(int, &(l), true, almemory_order_acq_rel) == true) \ + while(ATOMIC_FLAG_TEST_AND_SET(&(l), almemory_order_acq_rel) == true) \ althrd_yield(); \ } while(0) -#define UNLOCK(l) ATOMIC_STORE(&(l), false, almemory_order_release) +#define UNLOCK(l) ATOMIC_FLAG_CLEAR(&(l), almemory_order_release) void RWLockInit(RWLock *lock) { InitRef(&lock->read_count, 0); InitRef(&lock->write_count, 0); - ATOMIC_INIT(&lock->read_lock, false); - ATOMIC_INIT(&lock->read_entry_lock, false); - ATOMIC_INIT(&lock->write_lock, false); + ATOMIC_FLAG_CLEAR(&lock->read_lock, almemory_order_relaxed); + ATOMIC_FLAG_CLEAR(&lock->read_entry_lock, almemory_order_relaxed); + ATOMIC_FLAG_CLEAR(&lock->write_lock, almemory_order_relaxed); } void ReadLock(RWLock *lock) diff --git a/include/atomic.h b/include/atomic.h index 3a662f8e..4dff05da 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -22,9 +22,11 @@ extern "C" { #define almemory_order_seq_cst memory_order_seq_cst #define ATOMIC(T) T _Atomic +#define ATOMIC_FLAG atomic_flag #define ATOMIC_INIT(_val, _newval) atomic_init((_val), (_newval)) #define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval) +/*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ #define PARAM2(f, a, b, ...) (f((a), (b))) #define PARAM3(f, a, b, c, ...) (f((a), (b), (c))) @@ -42,6 +44,11 @@ extern "C" { #define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \ PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) +#define ATOMIC_FLAG_TEST_AND_SET(...) \ + PARAM2(atomic_flag_test_and_set_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_FLAG_CLEAR(...) \ + PARAM2(atomic_flag_clear_explicit, __VA_ARGS__, memory_order_seq_cst) + #define ATOMIC_THREAD_FENCE atomic_thread_fence /* Atomics using GCC intrinsics */ @@ -57,9 +64,11 @@ enum almemory_order { }; #define ATOMIC(T) struct { T volatile value; } +#define ATOMIC_FLAG ATOMIC(int) #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} +#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) #define ATOMIC_LOAD(_val, ...) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ @@ -76,6 +85,7 @@ enum almemory_order { #define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ + __asm__ __volatile__("" ::: "memory"); \ __sync_lock_test_and_set(&(_val)->value, (_newval)); \ }) #define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \ @@ -85,6 +95,16 @@ enum almemory_order { *(_oldval) == _o; \ }) +#define ATOMIC_FLAG_TEST_AND_SET(_val, ...) __extension__({ \ + __asm__ __volatile__("" ::: "memory"); \ + __sync_lock_test_and_set(&(_val)->value, 1); \ +}) +#define ATOMIC_FLAG_CLEAR(_val, ...) __extension__({ \ + __sync_lock_release(&(_val)->value); \ + __asm__ __volatile__("" ::: "memory"); \ +}) + + #define ATOMIC_THREAD_FENCE(order) do { \ enum { must_be_constant = (order) }; \ const int _o = must_be_constant; \ @@ -297,19 +317,23 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC(T) T +#define ATOMIC_INIT(_val, _newval) ((void)0) #define ATOMIC_INIT_STATIC(_newval) (0) -#define ATOMIC_LOAD_UNSAFE(_val) (0) -#define ATOMIC_STORE_UNSAFE(_val, _newval) ((void)0) +#define ATOMIC_LOAD(...) (0) +#define ATOMIC_STORE(...) ((void)0) -#define ATOMIC_LOAD(_val, ...) (0) -#define ATOMIC_STORE(_val, _newval, ...) ((void)0) +#define ATOMIC_ADD(...) (0) +#define ATOMIC_SUB(...) (0) -#define ATOMIC_ADD(_val, _incr, ...) (0) -#define ATOMIC_SUB(_val, _decr, ...) (0) +#define ATOMIC_EXCHANGE(T, ...) (0) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) (0) +#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) (0) -#define ATOMIC_EXCHANGE(T, _val, _newval, ...) (0) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0) +#define ATOMIC_FLAG_TEST_AND_SET(...) (0) +#define ATOMIC_FLAG_CLEAR(...) ((void)0) + +#define ATOMIC_THREAD_FENCE ((void)0) #endif /* If no weak cmpxchg is provided (not all systems will have one), substitute a @@ -318,6 +342,18 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG #endif +/* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange + * and store ops. + */ +#ifndef ATOMIC_FLAG +#define ATOMIC_FLAG ATOMIC(int) +#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) +#define ATOMIC_FLAG_TEST_AND_SET_(_val, ...) ATOMIC_EXCHANGE(int, _val, 1, __VA_ARGS__) +#define ATOMIC_FLAG_TEST_AND_SET(...) ATOMIC_FLAG_TEST_AND_SET_(__VA_ARGS__, almemory_order_seq_cst) +#define ATOMIC_FLAG_CLEAR_(_val, ...) ATOMIC_STORE(_val, 0, __VA_ARGS__) +#define ATOMIC_FLAG_CLEAR(...) ATOMIC_FLAG_CLEAR_(__VA_ARGS__, almemory_order_seq_cst) +#endif + typedef unsigned int uint; typedef ATOMIC(uint) RefCount; diff --git a/include/rwlock.h b/include/rwlock.h index 158a0670..8e36fa1a 100644 --- a/include/rwlock.h +++ b/include/rwlock.h @@ -11,13 +11,12 @@ extern "C" { typedef struct { RefCount read_count; RefCount write_count; - ATOMIC(int) read_lock; - ATOMIC(int) read_entry_lock; - ATOMIC(int) write_lock; + ATOMIC_FLAG read_lock; + ATOMIC_FLAG read_entry_lock; + ATOMIC_FLAG write_lock; } RWLock; #define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ - ATOMIC_INIT_STATIC(false), ATOMIC_INIT_STATIC(false), \ - ATOMIC_INIT_STATIC(false) } + ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT } void RWLockInit(RWLock *lock); void ReadLock(RWLock *lock); -- cgit v1.2.3 From 338e0d72b447e5d8825b05e19790c997a3eaa8fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Dec 2016 18:11:52 -0800 Subject: Ensure OSS devices are enumerated when a name is requested. --- Alc/backends/oss.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 432c75f2..2dca9232 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -320,10 +320,15 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) struct oss_device *dev = &oss_playback; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - if(!name) + if(!name || strcmp(name, dev->handle) == 0) name = dev->handle; else { + if(!dev->next) + { + ALCossListPopulate(&oss_playback, NULL); + dev = &oss_playback; + } while (dev != NULL) { if (strcmp(dev->handle, name) == 0) @@ -574,10 +579,15 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) int ossSpeed; char *err; - if(!name) + if(!name || strcmp(name, dev->handle) == 0) name = dev->handle; else { + if(!dev->next) + { + ALCossListPopulate(NULL, &oss_capture); + dev = &oss_capture; + } while (dev != NULL) { if (strcmp(dev->handle, name) == 0) -- cgit v1.2.3 From 66569295e5ac27dcddb4f20d25a30801af7ca992 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Dec 2016 18:26:18 -0800 Subject: Minor cleanup for ALCossListPopulate --- Alc/backends/oss.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 2dca9232..41f2c39f 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -88,7 +88,7 @@ static struct oss_device oss_capture = { #ifdef ALC_OSS_COMPAT -static void ALCossListPopulate(struct oss_device *UNUSED(playback), struct oss_device *UNUSED(capture)) +static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) { } @@ -153,7 +153,7 @@ static void ALCossListAppend(struct oss_device *list, const char *handle, size_t TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path); } -static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture) +static void ALCossListPopulate(struct oss_device *devlist, int type_flag) { struct oss_sysinfo si; struct oss_audioinfo ai; @@ -193,10 +193,9 @@ static void ALCossListPopulate(struct oss_device *playback, struct oss_device *c len = strnlen(ai.name, sizeof(ai.name)); handle = ai.name; } - if((ai.caps&DSP_CAP_INPUT) && capture != NULL) - ALCossListAppend(capture, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); - if((ai.caps&DSP_CAP_OUTPUT) && playback != NULL) - ALCossListAppend(playback, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode))); + if((ai.caps&type_flag)) + ALCossListAppend(devlist, handle, len, ai.devnode, + strnlen(ai.devnode, sizeof(ai.devnode))); } done: @@ -326,7 +325,7 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { if(!dev->next) { - ALCossListPopulate(&oss_playback, NULL); + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); dev = &oss_playback; } while (dev != NULL) @@ -585,7 +584,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { if(!dev->next) { - ALCossListPopulate(NULL, &oss_capture); + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); dev = &oss_capture; } while (dev != NULL) @@ -780,33 +779,30 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type) { + struct oss_device *cur; switch(type) { case ALL_DEVICE_PROBE: - { - struct oss_device *cur = &oss_playback; - ALCossListFree(cur); - ALCossListPopulate(cur, NULL); - while (cur != NULL) + ALCossListFree(&oss_playback); + ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); + cur = &oss_playback; + while(cur != NULL) { AppendAllDevicesList(cur->handle); cur = cur->next; } - } - break; + break; case CAPTURE_DEVICE_PROBE: - { - struct oss_device *cur = &oss_capture; - ALCossListFree(cur); - ALCossListPopulate(NULL, cur); - while (cur != NULL) + ALCossListFree(&oss_capture); + ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); + cur = &oss_capture; + while(cur != NULL) { AppendCaptureDeviceList(cur->handle); cur = cur->next; } - } - break; + break; } } -- cgit v1.2.3 From 70378925b0a9dbc58cc49e7888afcf4b7d55a17c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Dec 2016 18:34:29 -0800 Subject: Warn when a given device name isn't found for OSS --- Alc/backends/oss.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 41f2c39f..689a5c71 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -328,14 +328,17 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); dev = &oss_playback; } - while (dev != NULL) + while(dev != NULL) { if (strcmp(dev->handle, name) == 0) break; dev = dev->next; } - if (dev == NULL) + if(dev == NULL) + { + WARN("Could not find \"%s\" in device list\n", name); return ALC_INVALID_VALUE; + } } self->killNow = 0; @@ -587,14 +590,17 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); dev = &oss_capture; } - while (dev != NULL) + while(dev != NULL) { if (strcmp(dev->handle, name) == 0) break; dev = dev->next; } - if (dev == NULL) + if(dev == NULL) + { + WARN("Could not find \"%s\" in device list\n", name); return ALC_INVALID_VALUE; + } } self->fd = open(dev->path, O_RDONLY); -- cgit v1.2.3 From f0c2c23ad1e2427ff060db1bae0294703f742a68 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 20 Dec 2016 22:34:00 +0100 Subject: Explicitly disable use of GNU89 inline semantics --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a02a48f..34e55377 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,8 @@ ENDIF() # Make sure we have C99-style inline semantics with GCC (4.3 or newer). IF(CMAKE_COMPILER_IS_GNUCC) + SET(CMAKE_C_FLAGS "-fno-gnu89-inline ${CMAKE_C_FLAGS}") + SET(OLD_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") # Force no inlining for the next test. SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -fno-inline") -- cgit v1.2.3 From 8f581c0e66e52a6f24e85763b39ed3be29a3e792 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Dec 2016 20:49:37 -0800 Subject: Use separate macros for atomics that don't take a memory order --- Alc/ALc.c | 70 +++++++++++++++++----------------- Alc/ALu.c | 14 +++---- Alc/helpers.c | 8 ++-- Alc/mixer.c | 4 +- OpenAL32/alAuxEffectSlot.c | 22 +++++------ OpenAL32/alBuffer.c | 18 ++++----- OpenAL32/alError.c | 4 +- OpenAL32/alListener.c | 4 +- OpenAL32/alSource.c | 61 +++++++++++++++-------------- OpenAL32/alThunk.c | 8 ++-- include/atomic.h | 95 ++++++++++++++++++++++++---------------------- 11 files changed, 159 insertions(+), 149 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2e7c1e7f..95d5e178 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1173,7 +1173,7 @@ static void alc_cleanup(void) free(alcCaptureDefaultDeviceSpecifier); alcCaptureDefaultDeviceSpecifier = NULL; - if((dev=ATOMIC_EXCHANGE(ALCdevice*, &DeviceList, NULL)) != NULL) + if((dev=ATOMIC_EXCHANGE_SEQ(ALCdevice*, &DeviceList, NULL)) != NULL) { ALCuint num = 0; do { @@ -1587,7 +1587,7 @@ extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS */ void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type) { - ATOMIC_STORE(&context->DeferUpdates, type); + ATOMIC_STORE_SEQ(&context->DeferUpdates, type); } /* ALCcontext_ProcessUpdates @@ -1599,7 +1599,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) ALCdevice *device = context->Device; ReadLock(&context->PropLock); - if(ATOMIC_EXCHANGE(ALenum, &context->DeferUpdates, AL_FALSE)) + if(ATOMIC_EXCHANGE_SEQ(ALenum, &context->DeferUpdates, AL_FALSE)) { ALsizei pos; uint updates; @@ -1607,7 +1607,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ - ATOMIC_STORE(&context->HoldUpdates, AL_TRUE); + ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_TRUE); while(((updates=ReadRef(&context->UpdateCount))&1) != 0) althrd_yield(); @@ -1642,7 +1642,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) /* Now with all updates declared, let the mixer continue applying them * so they all happen at once. */ - ATOMIC_STORE(&context->HoldUpdates, AL_FALSE); + ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); } ReadUnlock(&context->PropLock); } @@ -1666,9 +1666,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } if(device) - ATOMIC_STORE(&device->LastError, errorCode); + ATOMIC_STORE_SEQ(&device->LastError, errorCode); else - ATOMIC_STORE(&LastNullDeviceError, errorCode); + ATOMIC_STORE_SEQ(&LastNullDeviceError, errorCode); } @@ -2098,7 +2098,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateEffectSlotProps(slot); } - context = ATOMIC_LOAD(&device->ContextList); + context = ATOMIC_LOAD_SEQ(&device->ContextList); while(context) { ALsizei pos; @@ -2260,7 +2260,7 @@ static ALCboolean VerifyDevice(ALCdevice **device) ALCdevice *tmpDevice; LockLists(); - tmpDevice = ATOMIC_LOAD(&DeviceList); + tmpDevice = ATOMIC_LOAD_SEQ(&DeviceList); while(tmpDevice) { if(tmpDevice == *device) @@ -2413,12 +2413,13 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) } origctx = context; - if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &GlobalContext, &origctx, NULL)) + if(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &GlobalContext, &origctx, NULL)) ALCcontext_DecRef(context); ALCdevice_Lock(device); origctx = context; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, context->next)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &device->ContextList, + &origctx, context->next)) { ALCcontext *volatile*list = &origctx->next; while(*list) @@ -2466,10 +2467,10 @@ static ALCboolean VerifyContext(ALCcontext **context) ALCdevice *dev; LockLists(); - dev = ATOMIC_LOAD(&DeviceList); + dev = ATOMIC_LOAD_SEQ(&DeviceList); while(dev) { - ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList); + ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList, almemory_order_acquire); while(ctx) { if(ctx == *context) @@ -2504,7 +2505,7 @@ ALCcontext *GetContextRef(void) else { LockLists(); - context = ATOMIC_LOAD(&GlobalContext); + context = ATOMIC_LOAD_SEQ(&GlobalContext); if(context) ALCcontext_IncRef(context); UnlockLists(); @@ -2528,11 +2529,11 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) if(VerifyDevice(&device)) { - errorCode = ATOMIC_EXCHANGE(ALCenum, &device->LastError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(ALCenum, &device->LastError, ALC_NO_ERROR); ALCdevice_DecRef(device); } else - errorCode = ATOMIC_EXCHANGE(ALCenum, &LastNullDeviceError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(ALCenum, &LastNullDeviceError, ALC_NO_ERROR); return errorCode; } @@ -3178,7 +3179,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin almtx_lock(&device->BackendLock); UnlockLists(); - ATOMIC_STORE(&device->LastError, ALC_NO_ERROR); + ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)); if(ALContext) @@ -3251,10 +3252,11 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin UpdateListenerProps(ALContext); { - ALCcontext *head = ATOMIC_LOAD(&device->ContextList); + ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); do { ALContext->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCcontext*, &device->ContextList, &head, ALContext)); + } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCcontext*, + &device->ContextList, &head, ALContext) == 0); } almtx_unlock(&device->BackendLock); @@ -3279,7 +3281,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) { almtx_lock(&Device->BackendLock); ReleaseContext(context, Device); - if(!ATOMIC_LOAD(&Device->ContextList)) + if(!ATOMIC_LOAD_SEQ(&Device->ContextList)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; @@ -3297,7 +3299,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { ALCcontext *Context = altss_get(LocalContext); - if(!Context) Context = ATOMIC_LOAD(&GlobalContext); + if(!Context) Context = ATOMIC_LOAD_SEQ(&GlobalContext); return Context; } @@ -3325,7 +3327,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) return ALC_FALSE; } /* context's reference count is already incremented */ - context = ATOMIC_EXCHANGE(ALCcontext*, &GlobalContext, context); + context = ATOMIC_EXCHANGE_SEQ(ALCcontext*, &GlobalContext, context); if(context) ALCcontext_DecRef(context); if((context=altss_get(LocalContext)) != NULL) @@ -3606,10 +3608,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } { - ALCdevice *head = ATOMIC_LOAD(&DeviceList); + ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); } TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); @@ -3626,7 +3628,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ALCcontext *ctx; LockLists(); - iter = ATOMIC_LOAD(&DeviceList); + iter = ATOMIC_LOAD_SEQ(&DeviceList); do { if(iter == device) break; @@ -3640,7 +3642,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) almtx_lock(&device->BackendLock); origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, device->next)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCdevice*, &DeviceList, &origdev, device->next)) { ALCdevice *volatile*list = &origdev->next; while(*list) @@ -3655,7 +3657,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) } UnlockLists(); - ctx = ATOMIC_LOAD(&device->ContextList); + ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx != NULL) { ALCcontext *next = ctx->next; @@ -3766,10 +3768,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, almtx_init(&device->BackendLock, almtx_plain); { - ALCdevice *head = ATOMIC_LOAD(&DeviceList); + ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); } TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); @@ -3781,7 +3783,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) ALCdevice *iter, *origdev; LockLists(); - iter = ATOMIC_LOAD(&DeviceList); + iter = ATOMIC_LOAD_SEQ(&DeviceList); do { if(iter == device) break; @@ -3794,7 +3796,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, device->next)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCdevice*, &DeviceList, &origdev, device->next)) { ALCdevice *volatile*list = &origdev->next; while(*list) @@ -3973,10 +3975,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN V(device->Backend,open)("Loopback"); { - ALCdevice *head = ATOMIC_LOAD(&DeviceList); + ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); } TRACE("Created device %p\n", device); @@ -4062,7 +4064,7 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) if((device->Flags&DEVICE_PAUSED)) { device->Flags &= ~DEVICE_PAUSED; - if(ATOMIC_LOAD(&device->ContextList) != NULL) + if(ATOMIC_LOAD_SEQ(&device->ContextList) != NULL) { if(V0(device->Backend,start)() != ALC_FALSE) device->Flags |= DEVICE_RUNNING; diff --git a/Alc/ALu.c b/Alc/ALu.c index b90a3983..db032057 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1347,7 +1347,7 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) ALsource *source; IncrementRef(&ctx->UpdateCount); - if(!ATOMIC_LOAD(&ctx->HoldUpdates)) + if(!ATOMIC_LOAD(&ctx->HoldUpdates, almemory_order_acquire)) { ALboolean force = CalcListenerParams(ctx); while(slot) @@ -1461,12 +1461,12 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); } - ctx = ATOMIC_LOAD(&device->ContextList); + ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire); while(ctx) { ALeffectslot *slotroot; - slotroot = ATOMIC_LOAD(&ctx->ActiveAuxSlotList); + slotroot = ATOMIC_LOAD(&ctx->ActiveAuxSlotList, almemory_order_acquire); UpdateContextSources(ctx, slotroot); slot = slotroot; @@ -1631,7 +1631,7 @@ ALvoid aluHandleDisconnect(ALCdevice *device) device->Connected = ALC_FALSE; - Context = ATOMIC_LOAD(&device->ContextList); + Context = ATOMIC_LOAD_SEQ(&device->ContextList); while(Context) { ALvoice *voice, *voice_end; @@ -1646,9 +1646,9 @@ ALvoid aluHandleDisconnect(ALCdevice *device) if(source && source->state == AL_PLAYING) { source->state = AL_STOPPED; - ATOMIC_STORE(&source->current_buffer, NULL); - ATOMIC_STORE(&source->position, 0); - ATOMIC_STORE(&source->position_fraction, 0); + ATOMIC_STORE(&source->current_buffer, NULL, almemory_order_relaxed); + ATOMIC_STORE(&source->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&source->position_fraction, 0, almemory_order_release); } voice++; diff --git a/Alc/helpers.c b/Alc/helpers.c index 0a6982e9..ef0c8e88 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -558,7 +558,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) vector_al_string results = VECTOR_INIT_STATIC(); size_t i; - while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + while(ATOMIC_EXCHANGE_SEQ(uint, &search_lock, 1) == 1) althrd_yield(); /* If the path is absolute, use it directly. */ @@ -629,7 +629,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) al_string_deinit(&path); } - ATOMIC_STORE(&search_lock, 0); + ATOMIC_STORE_SEQ(&search_lock, 0); return results; } @@ -834,7 +834,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); - while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + while(ATOMIC_EXCHANGE_SEQ(uint, &search_lock, 1) == 1) althrd_yield(); if(subdir[0] == '/') @@ -903,7 +903,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) al_string_deinit(&path); } - ATOMIC_STORE(&search_lock, 0); + ATOMIC_STORE_SEQ(&search_lock, 0); return results; } diff --git a/Alc/mixer.c b/Alc/mixer.c index dba429a0..be6a137c 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -532,7 +532,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } tmpiter = tmpiter->next; if(!tmpiter && Looping) - tmpiter = ATOMIC_LOAD(&Source->queue); + tmpiter = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); else if(!tmpiter) { SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); @@ -675,7 +675,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam if(!(BufferListItem=BufferListItem->next)) { if(Looping) - BufferListItem = ATOMIC_LOAD(&Source->queue); + BufferListItem = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); else { State = AL_STOPPED; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 4f1601ed..a7bc0f32 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -114,11 +114,11 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo } if(last != NULL) { - ALeffectslot *root = ATOMIC_LOAD(&context->ActiveAuxSlotList); + ALeffectslot *root = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); do { ATOMIC_STORE(&last->next, root, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALeffectslot*, &context->ActiveAuxSlotList, - &root, first)); + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALeffectslot*, &context->ActiveAuxSlotList, + &root, first)); } done: @@ -436,14 +436,14 @@ static void RemoveEffectSlotList(ALCcontext *context, ALeffectslot *slot) ALeffectslot *root, *next; root = slot; - next = ATOMIC_LOAD(&slot->next); - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &context->ActiveAuxSlotList, &root, next)) + next = ATOMIC_LOAD_SEQ(&slot->next); + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALeffectslot*, &context->ActiveAuxSlotList, &root, next)) { ALeffectslot *cur; do { cur = root; root = slot; - } while(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALeffectslot*, &cur->next, &root, next)); + } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALeffectslot*, &cur->next, &root, next)); } /* Wait for any mix that may be using these effect slots to finish. */ while((ReadRef(&device->MixCount)&1) != 0) @@ -527,7 +527,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e EffectSlot->Effect.Props = effect->Props; /* Remove state references from old effect slot property updates. */ - props = ATOMIC_LOAD(&EffectSlot->FreeList); + props = ATOMIC_LOAD_SEQ(&EffectSlot->FreeList); while(props) { State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); @@ -605,7 +605,7 @@ void DeinitEffectSlot(ALeffectslot *slot) ALeffectState *state; size_t count = 0; - props = ATOMIC_LOAD(&slot->Update); + props = ATOMIC_LOAD_SEQ(&slot->Update); if(props) { state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); @@ -671,10 +671,10 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* If there was an unused update container, put it back in the * freelist. */ - struct ALeffectslotProps *first = ATOMIC_LOAD(&slot->FreeList); + struct ALeffectslotProps *first = ATOMIC_LOAD_SEQ(&slot->FreeList); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(struct ALeffectslotProps*, &slot->FreeList, &first, props) == 0); } @@ -687,7 +687,7 @@ void UpdateAllEffectSlotProps(ALCcontext *context) ALeffectslot *slot; LockEffectSlotsRead(context); - slot = ATOMIC_LOAD(&context->ActiveAuxSlotList); + slot = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); while(slot) { if(slot->NeedsUpdate) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 193cfeaa..24470d64 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -161,7 +161,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - align = ATOMIC_LOAD(&albuf->UnpackAlign); + align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); if(SanitizeAlignment(srctype, &align) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(srctype) @@ -311,7 +311,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = ATOMIC_LOAD(&albuf->UnpackAlign); + align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); if(SanitizeAlignment(srctype, &align) == AL_FALSE) { WriteUnlock(&albuf->lock); @@ -390,7 +390,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - align = ATOMIC_LOAD(&albuf->UnpackAlign); + align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if((samples%align) != 0) @@ -428,7 +428,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = ATOMIC_LOAD(&albuf->UnpackAlign); + align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) { WriteUnlock(&albuf->lock); @@ -483,7 +483,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); ReadLock(&albuf->lock); - align = ATOMIC_LOAD(&albuf->PackAlign); + align = ATOMIC_LOAD_SEQ(&albuf->PackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) { ReadUnlock(&albuf->lock); @@ -630,13 +630,13 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - ATOMIC_STORE(&albuf->UnpackAlign, value); + ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - ATOMIC_STORE(&albuf->PackAlign, value); + ATOMIC_STORE_SEQ(&albuf->PackAlign, value); break; default: @@ -878,11 +878,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD(&albuf->UnpackAlign); + *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = ATOMIC_LOAD(&albuf->PackAlign); + *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign); break; default: diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index b38d8dfe..6b7684ce 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -46,7 +46,7 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode) raise(SIGTRAP); #endif } - ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &Context->LastError, &curerr, errorCode); + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Context->LastError, &curerr, errorCode); } AL_API ALenum AL_APIENTRY alGetError(void) @@ -69,7 +69,7 @@ AL_API ALenum AL_APIENTRY alGetError(void) return AL_INVALID_OPERATION; } - errorCode = ATOMIC_EXCHANGE(ALenum, &Context->LastError, AL_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(ALenum, &Context->LastError, AL_NO_ERROR); ALCcontext_DecRef(Context); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 4e99f24e..f05c20d1 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -506,10 +506,10 @@ void UpdateListenerProps(ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ - struct ALlistenerProps *first = ATOMIC_LOAD(&listener->FreeList); + struct ALlistenerProps *first = ATOMIC_LOAD_SEQ(&listener->FreeList); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, + } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(struct ALlistenerProps*, &listener->FreeList, &first, props) == 0); } } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 81cd44cd..9f60c545 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -658,7 +658,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); WriteLock(&Source->queue_lock); - ATOMIC_STORE(&Source->looping, *values); + ATOMIC_STORE_SEQ(&Source->looping, *values); WriteUnlock(&Source->queue_lock); return AL_TRUE; @@ -700,8 +700,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->SourceType = AL_UNDETERMINED; newlist = NULL; } - oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist); - ATOMIC_STORE(&Source->current_buffer, newlist); + oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist); + ATOMIC_STORE_SEQ(&Source->current_buffer, newlist); WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -1097,7 +1097,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) + if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) *values = 0; else { @@ -1214,13 +1214,14 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_LOOPING: - *values = ATOMIC_LOAD(&Source->looping); + *values = ATOMIC_LOAD_SEQ(&Source->looping); return AL_TRUE; case AL_BUFFER: ReadLock(&Source->queue_lock); - BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) : - ATOMIC_LOAD(&Source->current_buffer); + BufferList = (Source->SourceType == AL_STATIC) ? + ATOMIC_LOAD_SEQ(&Source->queue) : + ATOMIC_LOAD_SEQ(&Source->current_buffer); *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0; ReadUnlock(&Source->queue_lock); return AL_TRUE; @@ -1231,7 +1232,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BYTE_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) + if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) *values = 0; else { @@ -1270,7 +1271,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) + if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) *values = 0; else { @@ -1286,7 +1287,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFERS_QUEUED: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) + if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) *values = 0; else { @@ -1301,7 +1302,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFERS_PROCESSED: ReadLock(&Source->queue_lock); - if(ATOMIC_LOAD(&Source->looping) || Source->SourceType != AL_STREAMING) + if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING) { /* Buffers on a looping source are in a perpetual state of * PENDING, so don't report any as PROCESSED */ @@ -1309,8 +1310,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } else { - const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue); - const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer); + const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue); + const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer); ALsizei played = 0; while(BufferList && BufferList != Current) { @@ -2499,7 +2500,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu } /* Check for a valid Buffer, for its frequency and format */ - BufferList = ATOMIC_LOAD(&source->queue); + BufferList = ATOMIC_LOAD_SEQ(&source->queue); while(BufferList) { if(BufferList->buffer) @@ -2588,7 +2589,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu source->SourceType = AL_STREAMING; BufferList = NULL; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart)) + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue, + &BufferList, BufferListStart)) { /* Queue head is not NULL, append to the end of the queue */ while(BufferList->next != NULL) @@ -2599,7 +2601,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu * buffers. */ BufferList = NULL; - ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart); + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer, + &BufferList, BufferListStart); WriteUnlock(&source->queue_lock); done: @@ -2630,7 +2633,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); WriteLock(&source->queue_lock); - if(ATOMIC_LOAD(&source->looping) || source->SourceType != AL_STREAMING) + if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING) { WriteUnlock(&source->queue_lock); /* Trying to unqueue buffers on a looping or non-streaming source. */ @@ -2638,8 +2641,8 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Find the new buffer queue head */ - OldTail = ATOMIC_LOAD(&source->queue); - Current = ATOMIC_LOAD(&source->current_buffer); + OldTail = ATOMIC_LOAD_SEQ(&source->queue); + Current = ATOMIC_LOAD_SEQ(&source->current_buffer); if(OldTail != Current) { for(i = 1;i < nb;i++) @@ -2657,7 +2660,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Swap it, and cut the new head from the old. */ - OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, OldTail->next); + OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next); if(OldTail->next) { ALCdevice *device = context->Device; @@ -2788,7 +2791,7 @@ static void DeinitSource(ALsource *source) size_t count = 0; size_t i; - props = ATOMIC_LOAD(&source->Update); + props = ATOMIC_LOAD_SEQ(&source->Update); if(props) al_free(props); props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed); @@ -2806,7 +2809,7 @@ static void DeinitSource(ALsource *source) if(count > 3) WARN("Freed "SZFMT" Source property objects\n", count); - BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NULL); + BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL); while(BufferList != NULL) { ALbufferlistitem *next = BufferList->next; @@ -2910,7 +2913,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) /* If there was an unused update container, put it back in the * freelist. */ - struct ALsourceProps *first = ATOMIC_LOAD(&source->FreeList); + struct ALsourceProps *first = ATOMIC_LOAD_SEQ(&source->FreeList); do { ATOMIC_STORE(&props->next, first, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, @@ -2956,7 +2959,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) /* Check that there is a queue containing at least one valid, non zero * length Buffer. */ - BufferList = ATOMIC_LOAD(&Source->queue); + BufferList = ATOMIC_LOAD_SEQ(&Source->queue); while(BufferList) { ALbuffer *buffer; @@ -3052,7 +3055,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_INITIAL) { Source->state = AL_STOPPED; - ATOMIC_STORE(&Source->current_buffer, NULL); + ATOMIC_STORE_SEQ(&Source->current_buffer, NULL); } Source->OffsetType = AL_NONE; Source->Offset = 0.0; @@ -3062,10 +3065,10 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->state != AL_INITIAL) { Source->state = AL_INITIAL; - ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue), + ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue), almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0); + ATOMIC_STORE_SEQ(&Source->position_fraction, 0); } Source->OffsetType = AL_NONE; Source->Offset = 0.0; @@ -3304,7 +3307,7 @@ ALboolean ApplyOffset(ALsource *Source) return AL_FALSE; totalBufferLen = 0; - BufferList = ATOMIC_LOAD(&Source->queue); + BufferList = ATOMIC_LOAD_SEQ(&Source->queue); while(BufferList && totalBufferLen <= offset) { Buffer = BufferList->buffer; @@ -3343,7 +3346,7 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) ALdouble dbloff, dblfrac; /* Find the first valid Buffer in the Queue */ - BufferList = ATOMIC_LOAD(&Source->queue); + BufferList = ATOMIC_LOAD_SEQ(&Source->queue); while(BufferList) { if(BufferList->buffer) diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c index 72fc0dcb..d3892c97 100644 --- a/OpenAL32/alThunk.c +++ b/OpenAL32/alThunk.c @@ -54,7 +54,7 @@ ALenum NewThunkEntry(ALuint *index) ReadLock(&ThunkLock); for(i = 0;i < ThunkArraySize;i++) { - if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE) + if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE, almemory_order_acq_rel) == AL_FALSE) { ReadUnlock(&ThunkLock); *index = i+1; @@ -69,7 +69,7 @@ ALenum NewThunkEntry(ALuint *index) */ for(;i < ThunkArraySize;i++) { - if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE) + if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE, almemory_order_acq_rel) == AL_FALSE) { WriteUnlock(&ThunkLock); *index = i+1; @@ -89,7 +89,7 @@ ALenum NewThunkEntry(ALuint *index) ThunkArray = NewList; ThunkArraySize *= 2; - ATOMIC_STORE(&ThunkArray[i], AL_TRUE); + ATOMIC_STORE_SEQ(&ThunkArray[i], AL_TRUE); WriteUnlock(&ThunkLock); *index = i+1; @@ -100,6 +100,6 @@ void FreeThunkEntry(ALuint index) { ReadLock(&ThunkLock); if(index > 0 && index <= ThunkArraySize) - ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE); + ATOMIC_STORE_SEQ(&ThunkArray[index-1], AL_FALSE); ReadUnlock(&ThunkLock); } diff --git a/include/atomic.h b/include/atomic.h index 4dff05da..4783defe 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -28,26 +28,20 @@ extern "C" { #define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval) /*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ -#define PARAM2(f, a, b, ...) (f((a), (b))) -#define PARAM3(f, a, b, c, ...) (f((a), (b), (c))) -#define PARAM5(f, a, b, c, d, e, ...) (f((a), (b), (c), (d), (e))) +#define ATOMIC_LOAD(_val, _MO) atomic_load_explicit(_val, _MO) +#define ATOMIC_STORE(_val, _newval, _MO) atomic_store_explicit(_val, _newval, _MO) -#define ATOMIC_LOAD(...) PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_STORE(...) PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_ADD(_val, _incr, _MO) atomic_fetch_add_explicit(_val, _incr, _MO) +#define ATOMIC_SUB(_val, _decr, _MO) atomic_fetch_sub_explicit(_val, _decr, _MO) -#define ATOMIC_ADD(...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_SUB(...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) atomic_exchange_explicit(_val, _newval, _MO) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _orig, _newval, _MO1, _MO2) \ + atomic_compare_exchange_strong_explicit(_val, _orig, _newval, _MO1, _MO2) +#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _orig, _newval, _MO1, _MO2) \ + atomic_compare_exchange_weak_explicit(_val, _orig, _newval, _MO1, _MO2) -#define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) \ - PARAM5(atomic_compare_exchange_strong_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \ - PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) - -#define ATOMIC_FLAG_TEST_AND_SET(...) \ - PARAM2(atomic_flag_test_and_set_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_FLAG_CLEAR(...) \ - PARAM2(atomic_flag_clear_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) atomic_flag_test_and_set_explicit(_val, _MO) +#define ATOMIC_FLAG_CLEAR(_val, _MO) atomic_flag_clear_explicit(_val, _MO) #define ATOMIC_THREAD_FENCE atomic_thread_fence @@ -70,36 +64,36 @@ enum almemory_order { #define ATOMIC_INIT_STATIC(_newval) {(_newval)} #define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) -#define ATOMIC_LOAD(_val, ...) __extension__({ \ +#define ATOMIC_LOAD(_val, _MO) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ __asm__ __volatile__("" ::: "memory"); \ _r; \ }) -#define ATOMIC_STORE(_val, _newval, ...) do { \ +#define ATOMIC_STORE(_val, _newval, _MO) do { \ __asm__ __volatile__("" ::: "memory"); \ (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(_val, _incr, ...) __sync_fetch_and_add(&(_val)->value, (_incr)) -#define ATOMIC_SUB(_val, _decr, ...) __sync_fetch_and_sub(&(_val)->value, (_decr)) +#define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr)) +#define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr)) -#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ +#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ __asm__ __volatile__("" ::: "memory"); \ __sync_lock_test_and_set(&(_val)->value, (_newval)); \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _o = *(_oldval); \ *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ *(_oldval) == _o; \ }) -#define ATOMIC_FLAG_TEST_AND_SET(_val, ...) __extension__({ \ +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) __extension__({ \ __asm__ __volatile__("" ::: "memory"); \ __sync_lock_test_and_set(&(_val)->value, 1); \ }) -#define ATOMIC_FLAG_CLEAR(_val, ...) __extension__({ \ +#define ATOMIC_FLAG_CLEAR(_val, _MO) __extension__({ \ __sync_lock_release(&(_val)->value); \ __asm__ __volatile__("" ::: "memory"); \ }) @@ -156,24 +150,24 @@ enum almemory_order { #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_LOAD(_val, ...) __extension__({ \ +#define ATOMIC_LOAD(_val, _MO) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ __asm__ __volatile__("" ::: "memory"); \ _r; \ }) -#define ATOMIC_STORE(_val, _newval, ...) do { \ +#define ATOMIC_STORE(_val, _newval, _MO) do { \ __asm__ __volatile__("" ::: "memory"); \ (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(_val, _incr, ...) __extension__({ \ +#define ATOMIC_ADD(_val, _incr, _MO) __extension__({ \ static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ __typeof((_val)->value) _r; \ if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \ else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \ _r; \ }) -#define ATOMIC_SUB(_val, _decr, ...) __extension__({ \ +#define ATOMIC_SUB(_val, _decr, _MO) __extension__({ \ static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ __typeof((_val)->value) _r; \ if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \ @@ -181,7 +175,7 @@ enum almemory_order { _r; \ }) -#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ +#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) __extension__({ \ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _r; \ @@ -189,7 +183,7 @@ enum almemory_order { else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \ _r; \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) __extension__({ \ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _old = *(_oldval); \ @@ -279,27 +273,27 @@ enum almemory_order { #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_LOAD(_val, ...) ((_val)->value) -#define ATOMIC_STORE(_val, _newval, ...) do { \ +#define ATOMIC_LOAD(_val, _MO) ((_val)->value) +#define ATOMIC_STORE(_val, _newval, _MO) do { \ (_val)->value = (_newval); \ } while(0) int _al_invalid_atomic_size(); /* not defined */ -#define ATOMIC_ADD(_val, _incr, ...) \ +#define ATOMIC_ADD(_val, _incr, _MO) \ ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \ _al_invalid_atomic_size()) -#define ATOMIC_SUB(_val, _decr, ...) \ +#define ATOMIC_SUB(_val, _decr, _MO) \ ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ _al_invalid_atomic_size()) -#define ATOMIC_EXCHANGE(T, _val, _newval, ...) \ +#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) \ ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \ (sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \ (T)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) \ ((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ (bool)_al_invalid_atomic_size()) @@ -333,7 +327,7 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_FLAG_TEST_AND_SET(...) (0) #define ATOMIC_FLAG_CLEAR(...) ((void)0) -#define ATOMIC_THREAD_FENCE ((void)0) +#define ATOMIC_THREAD_FENCE(...) ((void)0) #endif /* If no weak cmpxchg is provided (not all systems will have one), substitute a @@ -348,24 +342,35 @@ int _al_invalid_atomic_size(); /* not defined */ #ifndef ATOMIC_FLAG #define ATOMIC_FLAG ATOMIC(int) #define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) -#define ATOMIC_FLAG_TEST_AND_SET_(_val, ...) ATOMIC_EXCHANGE(int, _val, 1, __VA_ARGS__) -#define ATOMIC_FLAG_TEST_AND_SET(...) ATOMIC_FLAG_TEST_AND_SET_(__VA_ARGS__, almemory_order_seq_cst) -#define ATOMIC_FLAG_CLEAR_(_val, ...) ATOMIC_STORE(_val, 0, __VA_ARGS__) -#define ATOMIC_FLAG_CLEAR(...) ATOMIC_FLAG_CLEAR_(__VA_ARGS__, almemory_order_seq_cst) +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(int, _val, 1, _MO) +#define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO) #endif +#define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) +#define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) + +#define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) +#define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) + +#define ATOMIC_EXCHANGE_SEQ(T, _val, _newval) ATOMIC_EXCHANGE(T, _val, _newval, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(T, _val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(T, _val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) + + typedef unsigned int uint; typedef ATOMIC(uint) RefCount; inline void InitRef(RefCount *ptr, uint value) { ATOMIC_INIT(ptr, value); } inline uint ReadRef(RefCount *ptr) -{ return ATOMIC_LOAD(ptr); } +{ return ATOMIC_LOAD_SEQ(ptr); } inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD(ptr, 1)+1; } +{ return ATOMIC_ADD_SEQ(ptr, 1)+1; } inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB(ptr, 1)-1; } +{ return ATOMIC_SUB_SEQ(ptr, 1)-1; } #ifdef __cplusplus -- cgit v1.2.3 From bcb6dfee71ef0ce4a0b9e7ceccb943f7f28704c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 01:08:33 -0800 Subject: Trace the commit ID and branch the library was built from --- Alc/ALc.c | 4 ++++ CMakeLists.txt | 22 ++++++++++++++++++++++ OpenAL32/alState.c | 2 ++ config.h.in | 3 --- utils/alsoft-config/mainwindow.cpp | 5 ++++- version.h.in | 8 ++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 version.h.in diff --git a/Alc/ALc.c b/Alc/ALc.c index 95d5e178..f1e1ad1f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -20,6 +20,8 @@ #include "config.h" +#include "version.h" + #include #include #include @@ -900,6 +902,8 @@ static void alc_initconfig(void) else ERR("Failed to open log file '%s'\n", str); } + TRACE("Initializing library v%s-%s %s\n", ALSOFT_VERSION, + ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); { char buf[1024] = ""; int len = snprintf(buf, sizeof(buf), "%s", BackendList[0].name); diff --git a/CMakeLists.txt b/CMakeLists.txt index 34e55377..e1e9a851 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1174,6 +1174,25 @@ IF(LIBTYPE STREQUAL "STATIC") SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS}) ENDIF() +IF(EXISTS "${OpenAL_SOURCE_DIR}/.git") + # Get the current working branch and its latest abbreviated commit hash + EXECUTE_PROCESS( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND git log -1 --format=%h + WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +ELSE() + SET(GIT_BRANCH "UNKNOWN") + SET(GIT_COMMIT_HASH "unknown") +ENDIF() + # Needed for openal.pc.in SET(prefix ${CMAKE_INSTALL_PREFIX}) SET(exec_prefix "\${prefix}") @@ -1183,6 +1202,9 @@ SET(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") SET(PACKAGE_VERSION "${LIB_VERSION}") # End configuration +CONFIGURE_FILE( + "${OpenAL_SOURCE_DIR}/version.h.in" + "${OpenAL_BINARY_DIR}/version.h") CONFIGURE_FILE( "${OpenAL_SOURCE_DIR}/config.h.in" "${OpenAL_BINARY_DIR}/config.h") diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 3d8e6c40..e633a86b 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -20,6 +20,8 @@ #include "config.h" +#include "version.h" + #include #include "alMain.h" #include "AL/alc.h" diff --git a/config.h.in b/config.h.in index a06c2039..4f22e5c8 100644 --- a/config.h.in +++ b/config.h.in @@ -2,9 +2,6 @@ #define AL_API ${EXPORT_DECL} #define ALC_API ${EXPORT_DECL} -/* Define to the library version */ -#define ALSOFT_VERSION "${LIB_VERSION}" - /* Define any available alignment declaration */ #define ALIGN(x) ${ALIGN_DECL} diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 309c4d7b..8d5dfe02 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1,6 +1,8 @@ #include "config.h" +#include "version.h" + #include #include @@ -461,7 +463,8 @@ void MainWindow::cancelCloseAction() void MainWindow::showAboutPage() { QMessageBox::information(this, tr("About"), - tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+(ALSOFT_VERSION ".") + tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+ + (ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch).") ); } diff --git a/version.h.in b/version.h.in new file mode 100644 index 00000000..56f738a3 --- /dev/null +++ b/version.h.in @@ -0,0 +1,8 @@ +/* Define to the library version */ +#define ALSOFT_VERSION "${LIB_VERSION}" + +/* Define the branch being built */ +#define ALSOFT_GIT_BRANCH "${GIT_BRANCH}" + +/* Define the hash of the head commit */ +#define ALSOFT_GIT_COMMIT_HASH "${GIT_COMMIT_HASH}" -- cgit v1.2.3 From e270a9784bdacecedb98312a4e2e9ef75ef7df62 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 10:54:19 -0800 Subject: Add missing macros for OSS3/Free compatibility --- Alc/backends/oss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 689a5c71..62563235 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -88,6 +88,8 @@ static struct oss_device oss_capture = { #ifdef ALC_OSS_COMPAT +#define DSP_CAP_OUTPUT 0x00020000 +#define DSP_CAP_INPUT 0x00010000 static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag)) { } -- cgit v1.2.3 From 1b104dd77baeb6d991ec2ff279c87e6e46527d44 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 11:41:45 -0800 Subject: More robustly generate the git commit ID and branch --- CMakeLists.txt | 29 +++++++++++++++-------------- utils/alsoft-config/CMakeLists.txt | 3 +++ version.cmake | 11 +++++++++++ 3 files changed, 29 insertions(+), 14 deletions(-) create mode 100644 version.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e1e9a851..55c832ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1174,23 +1174,24 @@ IF(LIBTYPE STREQUAL "STATIC") SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS}) ENDIF() -IF(EXISTS "${OpenAL_SOURCE_DIR}/.git") +FIND_PACKAGE(Git) +IF(GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") # Get the current working branch and its latest abbreviated commit hash - EXECUTE_PROCESS( - COMMAND git rev-parse --abbrev-ref HEAD + ADD_CUSTOM_TARGET(version + ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} + -D LIB_VERSION=${LIB_VERSION} + -D SRC=${OpenAL_SOURCE_DIR}/version.h.in + -D DST=${OpenAL_BINARY_DIR}/version.h + -P ${OpenAL_SOURCE_DIR}/version.cmake WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" - OUTPUT_VARIABLE GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - EXECUTE_PROCESS( - COMMAND git log -1 --format=%h - WORKING_DIRECTORY "${OpenAL_SOURCE_DIR}" - OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE + VERBATIM ) ELSE() SET(GIT_BRANCH "UNKNOWN") SET(GIT_COMMIT_HASH "unknown") + CONFIGURE_FILE( + "${OpenAL_SOURCE_DIR}/version.h.in" + "${OpenAL_BINARY_DIR}/version.h") ENDIF() # Needed for openal.pc.in @@ -1202,9 +1203,6 @@ SET(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") SET(PACKAGE_VERSION "${LIB_VERSION}") # End configuration -CONFIGURE_FILE( - "${OpenAL_SOURCE_DIR}/version.h.in" - "${OpenAL_BINARY_DIR}/version.h") CONFIGURE_FILE( "${OpenAL_SOURCE_DIR}/config.h.in" "${OpenAL_BINARY_DIR}/config.h") @@ -1296,6 +1294,9 @@ IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") ENDIF() TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS}) +IF(TARGET version) + ADD_DEPENDENCIES(${LIBNAME} version) +ENDIF() IF(ALSOFT_INSTALL) # Add an install target here diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 578273a5..6d7be8be 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -21,6 +21,9 @@ if(QT4_FOUND) target_link_libraries(alsoft-config ${QT_LIBRARIES}) set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) + if(TARGET version) + add_dependencies(alsoft-config version) + endif() install(TARGETS alsoft-config RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/version.cmake b/version.cmake new file mode 100644 index 00000000..af7ff0a6 --- /dev/null +++ b/version.cmake @@ -0,0 +1,11 @@ +EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE +) +EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} log -1 --format=%h + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) +CONFIGURE_FILE(${SRC} ${DST}) -- cgit v1.2.3 From dedc782222bf2f7f9a2210b686ebb1e922585bd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 12:05:26 -0800 Subject: Avoid duplicate HRTF entries in the UI Similar to how the library handles it, duplicate entries of the same file are ignored. This could happen if, for example, XDG_DATA_DIRS contains the same path multiple times. --- utils/alsoft-config/mainwindow.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 8d5dfe02..e1212f2f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -472,6 +472,7 @@ void MainWindow::showAboutPage() QStringList MainWindow::collectHrtfs() { QStringList ret; + QStringList processed; for(int i = 0;i < ui->hrtfFileList->count();i++) { @@ -481,13 +482,17 @@ QStringList MainWindow::collectHrtfs() { if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) continue; + QString fullname = dir.absoluteFilePath(fname); + if(processed.contains(fullname)) + continue; + processed.push_back(fullname); QString name = fname.left(fname.length()-4); if(!ret.contains(name)) ret.push_back(name); else { - size_t i = 1; + size_t i = 2; do { QString s = name+" #"+QString::number(i); if(!ret.contains(s)) @@ -512,13 +517,17 @@ QStringList MainWindow::collectHrtfs() { if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) continue; + QString fullname = dir.absoluteFilePath(fname); + if(processed.contains(fullname)) + continue; + processed.push_back(fullname); QString name = fname.left(fname.length()-4); if(!ret.contains(name)) ret.push_back(name); else { - size_t i = 1; + size_t i = 2; do { QString s = name+" #"+QString::number(i); if(!ret.contains(s)) -- cgit v1.2.3 From 315bd556acdc4b8b67b073f64d472f243a96544d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 17:20:11 -0800 Subject: Convert the SndIO backend to the updated API --- Alc/ALc.c | 2 +- Alc/backends/base.h | 1 + Alc/backends/sndio.c | 204 ++++++++++++++++++++++++++++------------------ OpenAL32/Include/alMain.h | 3 - 4 files changed, 128 insertions(+), 82 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f1e1ad1f..1690c9fe 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -81,7 +81,7 @@ static struct BackendInfo BackendList[] = { { "solaris", ALCsolarisBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_SNDIO - { "sndio", NULL, alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs }, + { "sndio", ALCsndioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_QSA { "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 04795b36..94177405 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -140,6 +140,7 @@ ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); +ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 52bff13a..af519794 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -28,19 +28,16 @@ #include "alu.h" #include "threads.h" -#include +#include "backends/base.h" +#include -static const ALCchar sndio_device[] = "SndIO Default"; -static ALCboolean sndio_load(void) -{ - return ALC_TRUE; -} +typedef struct ALCsndioBackend { + DERIVE_FROM_TYPE(ALCbackend); -typedef struct { struct sio_hdl *sndHandle; ALvoid *mix_data; @@ -48,13 +45,53 @@ typedef struct { volatile int killNow; althrd_t thread; -} sndio_data; +} ALCsndioBackend; + +static int ALCsndioBackend_mixerProc(void *ptr); + +static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device); +static void ALCsndioBackend_Destruct(ALCsndioBackend *self); +static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name); +static void ALCsndioBackend_close(ALCsndioBackend *self); +static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self); +static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self); +static void ALCsndioBackend_stop(ALCsndioBackend *self); +static DECLARE_FORWARD2(ALCsndioBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCsndioBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend); + + +static const ALCchar sndio_device[] = "SndIO Default"; + + +static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCsndioBackend, ALCbackend, self); +} + +static void ALCsndioBackend_Destruct(ALCsndioBackend *self) +{ + if(self->sndHandle) + sio_close(self->sndHandle); + self->sndHandle = NULL; + + al_free(self->mix_data); + self->mix_data = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} -static int sndio_proc(void *ptr) +static int ALCsndioBackend_mixerProc(void *ptr) { - ALCdevice *device = ptr; - sndio_data *data = device->ExtraData; + ALCsndioBackend *self = (ALCsndioBackend*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALsizei frameSize; size_t wrote; @@ -63,15 +100,15 @@ static int sndio_proc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - while(!data->killNow && device->Connected) + while(!self->killNow && device->Connected) { - ALsizei len = data->data_size; - ALubyte *WritePtr = data->mix_data; + ALsizei len = self->data_size; + ALubyte *WritePtr = self->mix_data; aluMixData(device, WritePtr, len/frameSize); - while(len > 0 && !data->killNow) + while(len > 0 && !self->killNow) { - wrote = sio_write(data->sndHandle, WritePtr, len); + wrote = sio_write(self->sndHandle, WritePtr, len); if(wrote == 0) { ERR("sio_write failed\n"); @@ -90,45 +127,36 @@ static int sndio_proc(void *ptr) } - -static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName) +static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) { - sndio_data *data; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - if(!deviceName) - deviceName = sndio_device; - else if(strcmp(deviceName, sndio_device) != 0) + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) return ALC_INVALID_VALUE; - data = calloc(1, sizeof(*data)); - data->killNow = 0; - - data->sndHandle = sio_open(NULL, SIO_PLAY, 0); - if(data->sndHandle == NULL) + self->sndHandle = sio_open(NULL, SIO_PLAY, 0); + if(self->sndHandle == NULL) { - free(data); ERR("Could not open device\n"); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; + al_string_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } -static void sndio_close_playback(ALCdevice *device) +static void ALCsndioBackend_close(ALCsndioBackend *self) { - sndio_data *data = device->ExtraData; - - sio_close(data->sndHandle); - free(data); - device->ExtraData = NULL; + sio_close(self->sndHandle); + self->sndHandle = NULL; } -static ALCboolean sndio_reset_playback(ALCdevice *device) +static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self) { - sndio_data *data = device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; struct sio_par par; sio_initpar(&par); @@ -170,7 +198,7 @@ static ALCboolean sndio_reset_playback(ALCdevice *device) par.appbufsz = device->UpdateSize * (device->NumUpdates-1); if(!par.appbufsz) par.appbufsz = device->UpdateSize; - if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par)) + if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) { ERR("Failed to set device parameters\n"); return ALC_FALSE; @@ -211,77 +239,84 @@ static ALCboolean sndio_reset_playback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean sndio_start_playback(ALCdevice *device) +static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) { - sndio_data *data = device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - if(!sio_start(data->sndHandle)) + self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + al_free(self->mix_data); + self->mix_data = al_calloc(16, self->data_size); + + if(!sio_start(self->sndHandle)) { ERR("Error starting playback\n"); return ALC_FALSE; } - data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - data->mix_data = calloc(1, data->data_size); - - data->killNow = 0; - if(althrd_create(&data->thread, sndio_proc, device) != althrd_success) + self->killNow = 0; + if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success) { - sio_stop(data->sndHandle); - free(data->mix_data); - data->mix_data = NULL; + sio_stop(self->sndHandle); return ALC_FALSE; } return ALC_TRUE; } -static void sndio_stop_playback(ALCdevice *device) +static void ALCsndioBackend_stop(ALCsndioBackend *self) { - sndio_data *data = device->ExtraData; int res; - if(data->killNow) + if(self->killNow) return; - data->killNow = 1; - althrd_join(data->thread, &res); + self->killNow = 1; + althrd_join(self->thread, &res); - if(!sio_stop(data->sndHandle)) + if(!sio_stop(self->sndHandle)) ERR("Error stopping device\n"); - free(data->mix_data); - data->mix_data = NULL; + al_free(self->mix_data); + self->mix_data = NULL; } -static const BackendFuncs sndio_funcs = { - sndio_open_playback, - sndio_close_playback, - sndio_reset_playback, - sndio_start_playback, - sndio_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -ALCboolean alc_sndio_init(BackendFuncs *func_list) +typedef struct ALCsndioBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCsndioBackendFactory; +#define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } } + +ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); + +static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory *self); +static DECLARE_FORWARD(ALCsndioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory *self, ALCbackend_Type type); +static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsndioBackendFactory); + + +ALCbackendFactory *ALCsndioBackendFactory_getFactory(void) { - if(!sndio_load()) - return ALC_FALSE; - *func_list = sndio_funcs; + static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self)) +{ + /* No dynamic loading */ return ALC_TRUE; } -void alc_sndio_deinit(void) +static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; } -void alc_sndio_probe(enum DevProbe type) +static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -292,3 +327,16 @@ void alc_sndio_probe(enum DevProbe type) break; } } + +static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCsndioBackend *backend; + NEW_OBJ(backend, ALCsndioBackend)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 837e1082..5a5c3923 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -401,9 +401,6 @@ typedef struct { ALCuint (*AvailableSamples)(ALCdevice*); } BackendFuncs; -ALCboolean alc_sndio_init(BackendFuncs *func_list); -void alc_sndio_deinit(void); -void alc_sndio_probe(enum DevProbe type); ALCboolean alc_ca_init(BackendFuncs *func_list); void alc_ca_deinit(void); void alc_ca_probe(enum DevProbe type); -- cgit v1.2.3 From 4c33818dde702128be13040f9fc8bd0a5b835c76 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 19:58:03 -0800 Subject: Avoid duplicating code using a macro --- Alc/ALu.c | 41 +++-------------------------------------- OpenAL32/alAuxEffectSlot.c | 6 +----- OpenAL32/alListener.c | 6 +----- OpenAL32/alSource.c | 7 +------ include/atomic.h | 12 ++++++++++++ 5 files changed, 18 insertions(+), 54 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index db032057..dc979522 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -239,7 +239,6 @@ static ALboolean CalcListenerParams(ALCcontext *Context) { ALlistener *Listener = Context->Listener; ALfloat N[3], V[3], U[3], P[3]; - struct ALlistenerProps *first; struct ALlistenerProps *props; aluVector vel; @@ -288,24 +287,12 @@ static ALboolean CalcListenerParams(ALCcontext *Context) Listener->Params.SourceDistanceModel = ATOMIC_LOAD(&props->SourceDistanceModel, almemory_order_relaxed); Listener->Params.DistanceModel = ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed); - /* WARNING: A livelock is theoretically possible if another thread keeps - * changing the freelist head without giving this a chance to actually swap - * in the old container (practically impossible with this little code, - * but...). - */ - first = ATOMIC_LOAD(&Listener->FreeList, almemory_order_acquire); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, - &Listener->FreeList, &first, props, almemory_order_acq_rel, - almemory_order_acquire) == 0); - + ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Listener->FreeList, props); return AL_TRUE; } static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) { - struct ALeffectslotProps *first; struct ALeffectslotProps *props; ALeffectState *state; @@ -337,18 +324,7 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) V(state,update)(device, slot, &props->Props); - /* WARNING: A livelock is theoretically possible if another thread keeps - * changing the freelist head without giving this a chance to actually swap - * in the old container (practically impossible with this little code, - * but...). - */ - first = ATOMIC_LOAD(&slot->FreeList, almemory_order_acquire); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, - &slot->FreeList, &first, props, almemory_order_acq_rel, - almemory_order_acquire) == 0); - + ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &slot->FreeList, props); return AL_TRUE; } @@ -1301,7 +1277,6 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc { ALsource *source = voice->Source; const ALbufferlistitem *BufferListItem; - struct ALsourceProps *first; struct ALsourceProps *props; props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); @@ -1311,17 +1286,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc { voice->Props = *props; - /* WARNING: A livelock is theoretically possible if another thread - * keeps changing the freelist head without giving this a chance to - * actually swap in the old container (practically impossible with this - * little code, but...). - */ - first = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props, almemory_order_acq_rel, - almemory_order_acquire) == 0); + ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props); } BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index a7bc0f32..e6b4ff68 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -671,11 +671,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) /* If there was an unused update container, put it back in the * freelist. */ - struct ALeffectslotProps *first = ATOMIC_LOAD_SEQ(&slot->FreeList); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(struct ALeffectslotProps*, - &slot->FreeList, &first, props) == 0); + ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &slot->FreeList, props); } if(oldstate) diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index f05c20d1..9c237e99 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -506,10 +506,6 @@ void UpdateListenerProps(ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ - struct ALlistenerProps *first = ATOMIC_LOAD_SEQ(&listener->FreeList); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(struct ALlistenerProps*, - &listener->FreeList, &first, props) == 0); + ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &listener->FreeList, props); } } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 9f60c545..e3d3cf1b 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2913,12 +2913,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) /* If there was an unused update container, put it back in the * freelist. */ - struct ALsourceProps *first = ATOMIC_LOAD_SEQ(&source->FreeList); - do { - ATOMIC_STORE(&props->next, first, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &first, props, almemory_order_acq_rel, - almemory_order_acquire) == 0); + ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props); } } diff --git a/include/atomic.h b/include/atomic.h index 4783defe..57609c33 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -373,6 +373,18 @@ inline uint DecrementRef(RefCount *ptr) { return ATOMIC_SUB_SEQ(ptr, 1)-1; } +/* WARNING: A livelock is theoretically possible if another thread keeps + * changing the head without giving this a chance to actually swap in the new + * one (practically impossible with this little code, but...). + */ +#define ATOMIC_REPLACE_HEAD(T, _head, _entry) do { \ + T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ + do { \ + ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ + } while(ATOMIC_COMPARE_EXCHANGE_WEAK(T, _head, &_first, _entry, \ + almemory_order_acq_rel, almemory_order_acquire) == 0); \ +} while(0) + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 080b0cea8ba4c21f898c18b70187822cd18f2eb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 21:35:50 -0800 Subject: Reorder filter coefficients --- Alc/effects/equalizer.c | 16 ++++++++-------- Alc/effects/modulator.c | 4 ++-- OpenAL32/Include/alFilter.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 1a63b418..13826a3b 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -146,11 +146,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - state->filter[0][i].a1 = state->filter[0][0].a1; - state->filter[0][i].a2 = state->filter[0][0].a2; state->filter[0][i].b0 = state->filter[0][0].b0; state->filter[0][i].b1 = state->filter[0][0].b1; state->filter[0][i].b2 = state->filter[0][0].b2; + state->filter[0][i].a1 = state->filter[0][0].a1; + state->filter[0][i].a2 = state->filter[0][0].a2; } gain = props->Equalizer.Mid1Gain; @@ -162,11 +162,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - state->filter[1][i].a1 = state->filter[1][0].a1; - state->filter[1][i].a2 = state->filter[1][0].a2; state->filter[1][i].b0 = state->filter[1][0].b0; state->filter[1][i].b1 = state->filter[1][0].b1; state->filter[1][i].b2 = state->filter[1][0].b2; + state->filter[1][i].a1 = state->filter[1][0].a1; + state->filter[1][i].a2 = state->filter[1][0].a2; } gain = props->Equalizer.Mid2Gain; @@ -178,11 +178,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - state->filter[2][i].a1 = state->filter[2][0].a1; - state->filter[2][i].a2 = state->filter[2][0].a2; state->filter[2][i].b0 = state->filter[2][0].b0; state->filter[2][i].b1 = state->filter[2][0].b1; state->filter[2][i].b2 = state->filter[2][0].b2; + state->filter[2][i].a1 = state->filter[2][0].a1; + state->filter[2][i].a2 = state->filter[2][0].a2; } gain = sqrtf(props->Equalizer.HighGain); @@ -192,11 +192,11 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - state->filter[3][i].a1 = state->filter[3][0].a1; - state->filter[3][i].a2 = state->filter[3][0].a2; state->filter[3][i].b0 = state->filter[3][0].b0; state->filter[3][i].b1 = state->filter[3][0].b1; state->filter[3][i].b2 = state->filter[3][0].b2; + state->filter[3][i].a1 = state->filter[3][0].a1; + state->filter[3][i].a2 = state->filter[3][0].a2; } } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 247cdf61..6d096048 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -137,11 +137,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - state->Filter[i].a1 = -a; - state->Filter[i].a2 = 0.0f; state->Filter[i].b0 = a; state->Filter[i].b1 = -a; state->Filter[i].b2 = 0.0f; + state->Filter[i].a1 = -a; + state->Filter[i].a2 = 0.0f; } STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer; diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 1f7095bc..bec4d46b 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -42,8 +42,8 @@ typedef enum ALfilterType { typedef struct ALfilterState { ALfloat x[2]; /* History of two last input samples */ ALfloat y[2]; /* History of two last output samples */ - ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ + ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ } ALfilterState; /* Currently only a C-based filter process method is implemented. */ #define ALfilterState_process ALfilterState_processC -- cgit v1.2.3 From 40f359d1592263245da409c790c2a48b98a1e815 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Dec 2016 21:56:51 -0800 Subject: Rename the version target for systems that have a version lib --- CMakeLists.txt | 6 +++--- utils/alsoft-config/CMakeLists.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55c832ad..839bf183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1177,7 +1177,7 @@ ENDIF() FIND_PACKAGE(Git) IF(GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") # Get the current working branch and its latest abbreviated commit hash - ADD_CUSTOM_TARGET(version + ADD_CUSTOM_TARGET(build_version ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D LIB_VERSION=${LIB_VERSION} -D SRC=${OpenAL_SOURCE_DIR}/version.h.in @@ -1294,8 +1294,8 @@ IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") ENDIF() TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS}) -IF(TARGET version) - ADD_DEPENDENCIES(${LIBNAME} version) +IF(TARGET build_version) + ADD_DEPENDENCIES(${LIBNAME} build_version) ENDIF() IF(ALSOFT_INSTALL) diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 6d7be8be..37fd7ba5 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -21,8 +21,8 @@ if(QT4_FOUND) target_link_libraries(alsoft-config ${QT_LIBRARIES}) set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) - if(TARGET version) - add_dependencies(alsoft-config version) + if(TARGET build_version) + add_dependencies(alsoft-config build_version) endif() install(TARGETS alsoft-config -- cgit v1.2.3 From fcdf1cea70027468e7a77301e9d6de5d28e3a547 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Dec 2016 12:37:48 -0800 Subject: Avoid writing to the same buffer that's read from Also clean up comment formatting a bit. --- Alc/effects/distortion.c | 72 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index bc1e7d84..84063e84 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -78,25 +78,26 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ALfloat cutoff; ALfloat edge; - /* Store distorted signal attenuation settings */ + /* Store distorted signal attenuation settings. */ state->attenuation = props->Distortion.Gain; - /* Store waveshaper edge settings */ + /* Store waveshaper edge settings. */ edge = sinf(props->Distortion.Edge * (F_PI_2)); edge = minf(edge, 0.99f); state->edge_coeff = 2.0f * edge / (1.0f-edge); - /* Lowpass filter */ cutoff = props->Distortion.LowpassCutoff; - /* Bandwidth value is constant in octaves */ + /* Bandwidth value is constant in octaves. */ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); + /* Multiply sampling frequency by the amount of oversampling done during + * processing. + */ ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - /* Bandpass filter */ cutoff = props->Distortion.EQCenter; - /* Convert bandwidth in Hz to octaves */ + /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) @@ -110,7 +111,6 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples const ALfloat fc = state->edge_coeff; ALuint base; ALuint it; - ALuint ot; ALuint kt; for(base = 0;base < SamplesToDo;) @@ -118,49 +118,49 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples float buffer[2][64 * 4]; ALuint td = minu(64, SamplesToDo-base); - /* 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. */ + /* 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 */ + /* Fill oversample buffer using zero stuffing. */ for(it = 0;it < td;it++) { - buffer[0][it*4 + 0] = SamplesIn[0][it+base]; + /* Multiply the sample by the amount of oversampling to maintain + * the signal's power. + */ + buffer[0][it*4 + 0] = SamplesIn[0][it+base] * 4.0f; buffer[0][it*4 + 1] = 0.0f; buffer[0][it*4 + 2] = 0.0f; buffer[0][it*4 + 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. */ + /* 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. + */ ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4); - /* 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(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(it = 0;it < td*4;it++) { - for(ot = 0;ot < 4;ot++) - { - /* Restore signal power by multiplying sample by amount of oversampling */ - ALfloat smp = buffer[1][it*4 + ot] * 4.0f; + ALfloat smp = buffer[1][it]; - 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)); + 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)); - buffer[1][it*4 + ot] = smp; - } + buffer[0][it] = smp; } - /* Third step, do bandpass filtering of distorted signal */ - ALfilterState_process(&state->bandpass, buffer[0], buffer[1], td*4); + /* Third step, do bandpass filtering of distorted signal. */ + ALfilterState_process(&state->bandpass, buffer[1], buffer[0], td*4); for(kt = 0;kt < NumChannels;kt++) { @@ -172,7 +172,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples continue; for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * buffer[0][it*4]; + SamplesOut[kt][base+it] += gain * buffer[1][it*4]; } base += td; -- cgit v1.2.3 From da4f0c65c303ac3cffb0fe4da240b7bec573009a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 4 Jan 2017 21:53:28 -0800 Subject: Update the B-Format HRTF coefficients to use the pseudo-inverse matrix It's hard to tell which is ultimately better, although this way does make the FOA output somewhat louder which will help when it's combined with direct HRTF rendering. --- Alc/hrtf.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index b3b795ac..3249868d 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -158,23 +158,21 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { - { { 0.078851598f, 0.000000000f, 0.070561967f, 0.000000000f }, { 0.0714285714f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, - { { 0.124051278f, 0.059847972f, 0.059847972f, 0.059847972f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, 0.0714285714f } }, - { { 0.124051278f, -0.059847972f, 0.059847972f, 0.059847972f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, 0.0714285714f } }, - { { 0.124051278f, -0.059847972f, 0.059847972f, -0.059847972f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, -0.0714285714f } }, - { { 0.124051278f, 0.059847972f, 0.059847972f, -0.059847972f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, -0.0714285714f } }, - { { 0.078851598f, 0.000000000f, 0.000000000f, 0.070561967f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, - { { 0.078851598f, -0.070561967f, 0.000000000f, 0.000000000f }, { 0.0714285714f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.078851598f, 0.000000000f, 0.000000000f, -0.070561967f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, - { { 0.078851598f, 0.070561967f, 0.000000000f, 0.000000000f }, { 0.0714285714f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.124051278f, 0.059847972f, -0.059847972f, 0.059847972f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, 0.0714285714f } }, - { { 0.124051278f, -0.059847972f, -0.059847972f, 0.059847972f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, 0.0714285714f } }, - { { 0.124051278f, -0.059847972f, -0.059847972f, -0.059847972f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, -0.0714285714f } }, - { { 0.124051278f, 0.059847972f, -0.059847972f, -0.059847972f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, -0.0714285714f } }, - { { 0.078851598f, 0.000000000f, -0.070561967f, 0.000000000f }, { 0.0714285714f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, + { { 0.1889822365f, 0.0000000000f, 0.1889822365f, 0.0000000000f }, { 0.0714285714f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, + { { 0.1889822365f, 0.1091089451f, 0.1091089451f, 0.1091089451f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, 0.0714285714f } }, + { { 0.1889822365f, -0.1091089451f, 0.1091089451f, 0.1091089451f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, 0.0714285714f } }, + { { 0.1889822365f, -0.1091089451f, 0.1091089451f, -0.1091089451f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, -0.0714285714f } }, + { { 0.1889822365f, 0.1091089451f, 0.1091089451f, -0.1091089451f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, -0.0714285714f } }, + { { 0.1889822365f, 0.0000000000f, 0.0000000000f, 0.1889822365f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, + { { 0.1889822365f, -0.1889822365f, 0.0000000000f, 0.0000000000f }, { 0.0714285714f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.1889822365f, 0.0000000000f, 0.0000000000f, -0.1889822365f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, + { { 0.1889822365f, 0.1889822365f, 0.0000000000f, 0.0000000000f }, { 0.0714285714f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, + { { 0.1889822365f, 0.1091089451f, -0.1091089451f, 0.1091089451f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, 0.0714285714f } }, + { { 0.1889822365f, -0.1091089451f, -0.1091089451f, 0.1091089451f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, 0.0714285714f } }, + { { 0.1889822365f, -0.1091089451f, -0.1091089451f, -0.1091089451f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, -0.0714285714f } }, + { { 0.1889822365f, 0.1091089451f, -0.1091089451f, -0.1091089451f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, -0.0714285714f } }, + { { 0.1889822365f, 0.0000000000f, -0.1889822365f, 0.0000000000f }, { 0.0714285714f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, }; -#define AMBIHF_GAIN 1.0f -#define AMBILF_GAIN 0.553914423f /* -5.13dB */ /* Change this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -236,11 +234,6 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(i = 0;i < Hrtf->irSize;i++) temps[2][i] = fir[i] / 32767.0f; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - /* Scale the low and high frequency responses. */ - for(i = 0;i < HRIR_LENGTH;i++) - temps[0][i] *= AMBIHF_GAIN; - for(i = 0;i < HRIR_LENGTH;i++) - temps[1][i] *= AMBILF_GAIN; } /* Add to the left output coefficients with the specified delay. */ @@ -270,11 +263,6 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(i = 0;i < Hrtf->irSize;i++) temps[2][i] = fir[i] / 32767.0f; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - /* Scale the low and high frequency responses. */ - for(i = 0;i < HRIR_LENGTH;i++) - temps[0][i] *= AMBIHF_GAIN; - for(i = 0;i < HRIR_LENGTH;i++) - temps[1][i] *= AMBILF_GAIN; } /* Add to the right output coefficients with the specified delay. */ -- cgit v1.2.3 From 18bb46163af68a5d7299733cd1e5f194be61d496 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 5 Jan 2017 20:06:24 -0800 Subject: Add missing AL_EFFECTSLOT_ properties for al(c)GetEnumValue --- Alc/ALc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1690c9fe..c9507564 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -601,6 +601,11 @@ static const ALCenums enumeration[] = { DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), DECL(AL_EFFECT_DEDICATED_DIALOGUE), + DECL(AL_EFFECTSLOT_EFFECT), + DECL(AL_EFFECTSLOT_GAIN), + DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), + DECL(AL_EFFECTSLOT_NULL), + DECL(AL_EAXREVERB_DENSITY), DECL(AL_EAXREVERB_DIFFUSION), DECL(AL_EAXREVERB_GAIN), -- cgit v1.2.3 From 987b6e069bcb9947bf2739aca33d890ebad5bebc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 9 Jan 2017 06:36:02 -0800 Subject: One more update for the HRTF B-Format coefficients These should better represent the pseudo-inverse matrices with N3D scaling. --- Alc/hrtf.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3249868d..38cd0618 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -158,20 +158,20 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { - { { 0.1889822365f, 0.0000000000f, 0.1889822365f, 0.0000000000f }, { 0.0714285714f, 0.0000000000f, 0.1237180798f, 0.0000000000f } }, - { { 0.1889822365f, 0.1091089451f, 0.1091089451f, 0.1091089451f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, 0.0714285714f } }, - { { 0.1889822365f, -0.1091089451f, 0.1091089451f, 0.1091089451f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, 0.0714285714f } }, - { { 0.1889822365f, -0.1091089451f, 0.1091089451f, -0.1091089451f }, { 0.0714285714f, -0.0714285714f, 0.0714285714f, -0.0714285714f } }, - { { 0.1889822365f, 0.1091089451f, 0.1091089451f, -0.1091089451f }, { 0.0714285714f, 0.0714285714f, 0.0714285714f, -0.0714285714f } }, - { { 0.1889822365f, 0.0000000000f, 0.0000000000f, 0.1889822365f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, 0.1237180798f } }, - { { 0.1889822365f, -0.1889822365f, 0.0000000000f, 0.0000000000f }, { 0.0714285714f, -0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.1889822365f, 0.0000000000f, 0.0000000000f, -0.1889822365f }, { 0.0714285714f, 0.0000000000f, 0.0000000000f, -0.1237180798f } }, - { { 0.1889822365f, 0.1889822365f, 0.0000000000f, 0.0000000000f }, { 0.0714285714f, 0.1237180798f, 0.0000000000f, 0.0000000000f } }, - { { 0.1889822365f, 0.1091089451f, -0.1091089451f, 0.1091089451f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, 0.0714285714f } }, - { { 0.1889822365f, -0.1091089451f, -0.1091089451f, 0.1091089451f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, 0.0714285714f } }, - { { 0.1889822365f, -0.1091089451f, -0.1091089451f, -0.1091089451f }, { 0.0714285714f, -0.0714285714f, -0.0714285714f, -0.0714285714f } }, - { { 0.1889822365f, 0.1091089451f, -0.1091089451f, -0.1091089451f }, { 0.0714285714f, 0.0714285714f, -0.0714285714f, -0.0714285714f } }, - { { 0.1889822365f, 0.0000000000f, -0.1889822365f, 0.0000000000f }, { 0.0714285714f, 0.0000000000f, -0.1237180798f, 0.0000000000f } }, + { { 1.88982237e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f } }, + { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, + { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, + { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, + { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, + { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f } }, + { { 1.88982237e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, + { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f } }, + { { 1.88982237e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, + { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, + { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, + { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, + { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, + { { 1.88982237e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f } } }; /* Change this to 2 for dual-band HRTF processing. May require a higher quality -- cgit v1.2.3 From e20f0ae5a3c68767a7e08df96fbfa707f36ea6db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 Jan 2017 03:02:26 -0800 Subject: Hold Pulse's mainloop lock while calling capture functions Since commit c837484015e, the backend's lock is no longer implicitly held when calling capture functions. A separate mutex is used to ensure serial access, and its up to the backend to protect against races and reentrancy with the audio API. --- Alc/backends/pulseaudio.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index f46386e4..fa07da3e 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1558,17 +1558,20 @@ static void ALCpulseCapture_close(ALCpulseCapture *self) static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self) { pa_operation *o; + pa_threaded_mainloop_lock(self->loop); o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop); wait_for_operation(o, self->loop); - + pa_threaded_mainloop_unlock(self->loop); return ALC_TRUE; } static void ALCpulseCapture_stop(ALCpulseCapture *self) { pa_operation *o; + 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 ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples) @@ -1579,6 +1582,7 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu /* Capture is done in fragment-sized chunks, so we loop until we get all * that's available */ self->last_readable -= todo; + pa_threaded_mainloop_lock(self->loop); while(todo > 0) { size_t rem = todo; @@ -1618,6 +1622,7 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu self->cap_len = 0; } } + pa_threaded_mainloop_unlock(self->loop); if(todo > 0) memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); @@ -1631,7 +1636,9 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) if(device->Connected) { - ssize_t got = pa_stream_readable_size(self->stream); + ssize_t got; + pa_threaded_mainloop_lock(self->loop); + got = pa_stream_readable_size(self->stream); if(got < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); @@ -1639,6 +1646,7 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) } else if((size_t)got > self->cap_len) readable += got - self->cap_len; + pa_threaded_mainloop_unlock(self->loop); } if(self->last_readable < readable) -- cgit v1.2.3 From 43ab6075f9d40f0eabfaf15e37f6fed6e92b14f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 Jan 2017 03:17:23 -0800 Subject: Use proper atomics in the OSS backend --- Alc/backends/oss.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 62563235..2da096f6 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -243,7 +243,7 @@ typedef struct ALCplaybackOSS { ALubyte *mix_data; int data_size; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCplaybackOSS; @@ -277,13 +277,13 @@ static int ALCplaybackOSS_mixerProc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) { ALint len = self->data_size; ALubyte *WritePtr = self->mix_data; aluMixData(device, WritePtr, len/frameSize); - while(len > 0 && !self->killNow) + while(len > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) { wrote = write(self->fd, WritePtr, len); if(wrote < 0) @@ -314,6 +314,8 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); + + ATOMIC_INIT(&self->killNow, AL_FALSE); } static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) @@ -343,8 +345,6 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) } } - self->killNow = 0; - self->fd = open(dev->path, O_WRONLY); if(self->fd == -1) { @@ -459,7 +459,7 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); self->mix_data = calloc(1, self->data_size); - self->killNow = 0; + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success) { free(self->mix_data); @@ -474,10 +474,8 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE)) return; - - self->killNow = 1; althrd_join(self->thread, &res); if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) @@ -494,9 +492,9 @@ typedef struct ALCcaptureOSS { int fd; ll_ringbuffer_t *ring; - int doCapture; + ATOMIC(ALenum) doCapture; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCcaptureOSS; @@ -530,12 +528,12 @@ static int ALCcaptureOSS_recordProc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - while(!self->killNow) + while(!ATOMIC_LOAD_SEQ(&self->killNow)) { ll_ringbuffer_data_t vec[2]; amt = 0; - if(self->doCapture) + if(ATOMIC_LOAD_SEQ(&self->doCapture)) { ll_ringbuffer_get_write_vector(self->ring, vec); if(vec[0].len > 0) @@ -567,6 +565,9 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); + + ATOMIC_INIT(&self->doCapture, AL_FALSE); + ATOMIC_INIT(&self->killNow, AL_FALSE); } static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) @@ -689,7 +690,6 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - self->killNow = 0; if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) { ll_ringbuffer_free(self->ring); @@ -708,7 +708,7 @@ static void ALCcaptureOSS_close(ALCcaptureOSS *self) { int res; - self->killNow = 1; + ATOMIC_STORE_SEQ(&self->killNow, AL_TRUE); althrd_join(self->thread, &res); close(self->fd); @@ -720,13 +720,13 @@ static void ALCcaptureOSS_close(ALCcaptureOSS *self) static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { - self->doCapture = 1; + ATOMIC_STORE_SEQ(&self->doCapture, AL_TRUE); return ALC_TRUE; } static void ALCcaptureOSS_stop(ALCcaptureOSS *self) { - self->doCapture = 0; + ATOMIC_STORE_SEQ(&self->doCapture, AL_FALSE); } static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) -- cgit v1.2.3 From 58f84170b6237a3c847cdccaaa3c666e7ba710d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 10 Jan 2017 05:12:54 -0800 Subject: Avoid using some LP types --- Alc/backends/mmdevapi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 3882b08f..92089416 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -211,7 +211,7 @@ static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfac } -static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) +static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) { int count = 0; al_string tmpname; @@ -249,9 +249,9 @@ static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) AL_STRING_DEINIT(tmpname); } -static LPWSTR get_device_id(IMMDevice *device) +static WCHAR *get_device_id(IMMDevice *device) { - LPWSTR devid; + WCHAR *devid; HRESULT hr; hr = IMMDevice_GetId(device, &devid); @@ -268,7 +268,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve { IMMDeviceCollection *coll; IMMDevice *defdev = NULL; - LPWSTR defdevid = NULL; + WCHAR *defdevid = NULL; HRESULT hr; UINT count; UINT i; @@ -300,7 +300,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve for(i = 0;i < count;++i) { IMMDevice *device; - LPWSTR devid; + WCHAR *devid; hr = IMMDeviceCollection_Item(coll, i, &device); if(FAILED(hr)) continue; -- cgit v1.2.3 From 24de5127b1f1d25e507c6c0af5f2272c5baa8490 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jan 2017 10:09:39 -0800 Subject: Update binary search algorithm for uintmaps --- common/uintmap.c | 147 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/common/uintmap.c b/common/uintmap.c index d3b51923..7b27b36e 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -43,19 +43,18 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) WriteLock(&map->lock); if(map->size > 0) { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->keys[mid] < key) - low = mid + 1; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; else - high = mid; - } - if(map->keys[low] < key) - low++; - pos = low; + { + pos = i+1; + count -= step+1; + } + } while(count > 0); } if(pos == map->size || map->keys[pos] != key) @@ -126,25 +125,28 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) WriteLock(&map->lock); if(map->size > 0) { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->keys[mid] < key) - low = mid + 1; + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; else - high = mid; - } - if(map->keys[low] == key) + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) { - ptr = map->values[low]; - if(low < map->size-1) + ptr = map->values[pos]; + if(pos < map->size-1) { - memmove(&map->keys[low], &map->keys[low+1], - (map->size-1-low)*sizeof(map->keys[0])); - memmove(&map->values[low], &map->values[low+1], - (map->size-1-low)*sizeof(map->values[0])); + memmove(&map->keys[pos], &map->keys[pos+1], + (map->size-1-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos], &map->values[pos+1], + (map->size-1-pos)*sizeof(map->values[0])); } map->size--; } @@ -155,33 +157,36 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key) { + ALvoid *ptr = NULL; if(map->size > 0) { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->keys[mid] < key) - low = mid + 1; + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; else - high = mid; - } - if(map->keys[low] == key) + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) { - ALvoid *ptr = map->values[low]; - if(low < map->size-1) + ptr = map->values[pos]; + if(pos < map->size-1) { - memmove(&map->keys[low], &map->keys[low+1], - (map->size-1-low)*sizeof(map->keys[0])); - memmove(&map->values[low], &map->values[low+1], - (map->size-1-low)*sizeof(map->values[0])); + memmove(&map->keys[pos], &map->keys[pos+1], + (map->size-1-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos], &map->values[pos+1], + (map->size-1-pos)*sizeof(map->values[0])); } map->size--; - return ptr; } } - return NULL; + return ptr; } ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) @@ -190,18 +195,21 @@ ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) ReadLock(&map->lock); if(map->size > 0) { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->keys[mid] < key) - low = mid + 1; + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; else - high = mid; - } - if(map->keys[low] == key) - ptr = map->values[low]; + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + ptr = map->values[pos]; } ReadUnlock(&map->lock); return ptr; @@ -211,18 +219,21 @@ ALvoid *LookupUIntMapKeyNoLock(UIntMap *map, ALuint key) { if(map->size > 0) { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->keys[mid] < key) - low = mid + 1; + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; else - high = mid; - } - if(map->keys[low] == key) - return map->values[low]; + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + return map->values[pos]; } return NULL; } -- cgit v1.2.3 From 6e806848ebe1c32053aa3bad5603139acce012b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jan 2017 13:38:21 -0800 Subject: Use C++11 for alsoft-config --- CMakeLists.txt | 6 ++++++ utils/alsoft-config/mainwindow.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 839bf183..3e608146 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ INCLUDE(CheckIncludeFile) INCLUDE(CheckIncludeFiles) INCLUDE(CheckSymbolExists) INCLUDE(CheckCCompilerFlag) +INCLUDE(CheckCXXCompilerFlag) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckTypeSize) include(CheckStructHasMember) @@ -115,6 +116,11 @@ ELSE() ENDIF() ENDIF() +CHECK_CXX_COMPILER_FLAG(-std=c++11 HAVE_STD_CXX11) +IF(HAVE_STD_CXX11) + SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") +ENDIF() + if(NOT WIN32) # Check if _POSIX_C_SOURCE and _XOPEN_SOURCE needs to be set for POSIX functions CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index e1212f2f..370619bf 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -678,8 +678,8 @@ void MainWindow::loadConfig(const QString &fname) 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)); + for(QString &str : disabledCpuExts) + str = str.trimmed(); ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive)); ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive)); ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive)); @@ -689,8 +689,8 @@ void MainWindow::loadConfig(const QString &fname) QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); if(hrtf_paths.size() == 1) hrtf_paths = hrtf_paths[0].split(QChar(',')); - std::transform(hrtf_paths.begin(), hrtf_paths.end(), - hrtf_paths.begin(), std::mem_fun_ref(&QString::trimmed)); + for(QString &str : hrtf_paths) + str = str.trimmed(); if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty()) ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked); else @@ -745,8 +745,8 @@ void MainWindow::loadConfig(const QString &fname) { if(drivers.size() == 1) drivers = drivers[0].split(QChar(',')); - std::transform(drivers.begin(), drivers.end(), - drivers.begin(), std::mem_fun_ref(&QString::trimmed)); + for(QString &str : drivers) + str = str.trimmed(); bool lastWasEmpty = false; foreach(const QString &backend, drivers) @@ -798,8 +798,8 @@ void MainWindow::loadConfig(const QString &fname) 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)); + for(QString &str : excludefx) + str = str.trimmed(); ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive)); -- cgit v1.2.3 From e254a3f0c237634d8f1d329b74be67569c2c805a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 12 Jan 2017 23:45:39 -0800 Subject: Search for and use Qt5 for alsoft-config An option is provided to instead use Qt4.8 still if desired. --- utils/alsoft-config/CMakeLists.txt | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 37fd7ba5..4911b9d8 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -1,24 +1,23 @@ project(alsoft-config) -include_directories("${alsoft-config_BINARY_DIR}") +option(ALSOFT_NO_QT5 "Use Qt4 instead of Qt5 for alsoft-config" FALSE) -# 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}) +include_directories("${alsoft-config_BINARY_DIR}") - set(alsoft-config_SRCS main.cpp - mainwindow.cpp - ) +set(alsoft-config_SRCS main.cpp + mainwindow.cpp +) +set(alsoft-config_UIS mainwindow.ui) +set(alsoft-config_MOCS mainwindow.h) - set(alsoft-config_UIS mainwindow.ui) - QT4_WRAP_UI(UIS ${alsoft-config_UIS}) +find_package(Qt5Widgets) +if(Qt5Widgets_FOUND AND NOT ALSOFT_NO_QT5) + qt5_wrap_ui(UIS ${alsoft-config_UIS}) - set(alsoft-config_MOCS mainwindow.h) - QT4_WRAP_CPP(MOCS ${alsoft-config_MOCS}) + qt5_wrap_cpp(MOCS ${alsoft-config_MOCS}) add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) - target_link_libraries(alsoft-config ${QT_LIBRARIES}) + target_link_libraries(alsoft-config Qt5::Widgets) set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) if(TARGET build_version) @@ -30,4 +29,28 @@ if(QT4_FOUND) LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) +else() + # 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}) + + qt4_wrap_ui(UIS ${alsoft-config_UIS}) + + 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_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) + if(TARGET build_version) + add_dependencies(alsoft-config build_version) + endif() + + install(TARGETS alsoft-config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + endif() endif() -- cgit v1.2.3 From 8e868823fd0226a960259363cd7b49ea51ece426 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 13 Jan 2017 00:46:49 -0800 Subject: Replace range-based for loops with QList iterators Less than ideal, but some targets can't rely on C++11 --- utils/alsoft-config/mainwindow.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 370619bf..4ae89f09 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -678,8 +678,8 @@ void MainWindow::loadConfig(const QString &fname) QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); if(disabledCpuExts.size() == 1) disabledCpuExts = disabledCpuExts[0].split(QChar(',')); - for(QString &str : disabledCpuExts) - str = str.trimmed(); + for(QStringList::iterator iter = disabledCpuExts.begin();iter != disabledCpuExts.end();iter++) + *iter = iter->trimmed(); ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive)); ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive)); ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive)); @@ -689,8 +689,8 @@ void MainWindow::loadConfig(const QString &fname) QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); if(hrtf_paths.size() == 1) hrtf_paths = hrtf_paths[0].split(QChar(',')); - for(QString &str : hrtf_paths) - str = str.trimmed(); + for(QStringList::iterator iter = hrtf_paths.begin();iter != hrtf_paths.end();iter++) + *iter = iter->trimmed(); if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty()) ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked); else @@ -745,8 +745,8 @@ void MainWindow::loadConfig(const QString &fname) { if(drivers.size() == 1) drivers = drivers[0].split(QChar(',')); - for(QString &str : drivers) - str = str.trimmed(); + for(QStringList::iterator iter = drivers.begin();iter != drivers.end();iter++) + *iter = iter->trimmed(); bool lastWasEmpty = false; foreach(const QString &backend, drivers) @@ -798,8 +798,8 @@ void MainWindow::loadConfig(const QString &fname) QStringList excludefx = settings.value("excludefx").toStringList(); if(excludefx.size() == 1) excludefx = excludefx[0].split(QChar(',')); - for(QString &str : excludefx) - str = str.trimmed(); + for(QStringList::iterator iter = excludefx.begin();iter != excludefx.end();iter++) + *iter = iter->trimmed(); ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive)); -- cgit v1.2.3 From 9f23d17333c8faaa0a2b7a86df33c41874a929a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jan 2017 13:57:22 -0800 Subject: Use second-order ambisonics for basic HRTF rendering This should improve positional quality for relatively low cost. Full HRTF rendering still only uses first-order since the only use of the dry buffer there is for first-order content (B-Format buffers, effects). --- Alc/ALc.c | 11 ++++++--- Alc/ALu.c | 7 ++++++ Alc/hrtf.c | 39 +++++++++++++++++++++++--------- Alc/hrtf.h | 2 +- Alc/panning.c | 57 +++++++++++++++++++++++++++++++++++++++-------- OpenAL32/Include/alMain.h | 4 ++-- 6 files changed, 95 insertions(+), 25 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c9507564..0b558ff7 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2055,9 +2055,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2)) size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); else if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) + { size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); - else if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->AmbiUp) size += 4 * sizeof(device->Dry.Buffer[0]); + } + else if(device->AmbiUp) size += 4 * sizeof(device->Dry.Buffer[0]); + TRACE("Allocating "SZFMT" channels, "SZFMT" bytes\n", size/sizeof(device->Dry.Buffer[0]), size); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) { @@ -2076,8 +2080,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->RealOut.NumChannels = device->Dry.NumChannels; } - if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || - (device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3)) + if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || device->AmbiUp) { /* Higher-order rendering requires upsampling first-order content, so * make sure to mix it separately. @@ -2090,6 +2093,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FOAOut.Buffer = device->Dry.Buffer; device->FOAOut.NumChannels = device->Dry.NumChannels; } + TRACE("Channel config, Dry: %u, FOA: %u, Real: %u\n", device->Dry.NumChannels, + device->FOAOut.NumChannels, device->RealOut.NumChannels); SetMixerFPUMode(&oldMode); if(device->DefaultSlot) diff --git a/Alc/ALu.c b/Alc/ALu.c index dc979522..192f2a35 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1488,6 +1488,13 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + + if(device->AmbiUp) + ambiup_process(device->AmbiUp, + device->Dry.Buffer, device->Dry.NumChannels, + SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo + ); + if(lidx != -1 && ridx != -1) { HrtfDirectMixerFunc HrtfMix = SelectHrtfMixer(); diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 38cd0618..a6efa34b 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -136,12 +136,14 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels) +ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels, const ALuint *AmbiMap) { +#define HRTF_AMBI_CHAN_COUNT 14 + /* NOTE: azimuth goes clockwise. */ static const struct { ALfloat elevation; ALfloat azimuth; - } Ambi3DPoints[14] = { + } Ambi3DPoints[HRTF_AMBI_CHAN_COUNT] = { { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, @@ -157,7 +159,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; - static const ALfloat Ambi3DMatrix[14][2][MAX_AMBI_COEFFS] = { + static const ALfloat Ambi3DMatrixFOA[HRTF_AMBI_CHAN_COUNT][2][MAX_AMBI_COEFFS] = { { { 1.88982237e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f } }, { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, @@ -172,9 +174,25 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, { { 1.88982237e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f } } + }, Ambi3DMatrixHOA[HRTF_AMBI_CHAN_COUNT][2][MAX_AMBI_COEFFS] = { + { { 1.43315266e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, + { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, + { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, + { { 1.39644596e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, + { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, + { { 1.39644596e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, + { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, + { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, + { { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, }; + const ALfloat (*Ambi3DMatrix)[2][MAX_AMBI_COEFFS] = AmbiMap ? Ambi3DMatrixHOA : Ambi3DMatrixFOA; -/* Change this to 2 for dual-band HRTF processing. May require a higher quality +/* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the * tail generated by the filter. */ @@ -186,9 +204,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ ALuint max_length = 0; ALuint i, j, c, b; - assert(NumChannels == 4); - - for(c = 0;c < COUNTOF(Ambi3DPoints);c++) + for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) { ALuint evidx, azidx; ALuint evoffset; @@ -215,7 +231,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ memset(temps, 0, sizeof(temps)); bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); - for(c = 0;c < COUNTOF(Ambi3DMatrix);c++) + for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) { const ALshort *fir; ALuint delay; @@ -240,11 +256,12 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ delay = Hrtf->delays[lidx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { + const ALsizei a = AmbiMap ? AmbiMap[i] : i; for(b = 0;b < NUM_BANDS;b++) { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][i]; + coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][a]; } } max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -269,11 +286,12 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ delay = Hrtf->delays[ridx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { + const ALsizei a = AmbiMap ? AmbiMap[i] : i; for(b = 0;b < NUM_BANDS;b++) { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][i]; + coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][a]; } } max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -282,6 +300,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ #undef NUM_BANDS return max_length; +#undef HRTF_AMBI_CHAN_COUNT } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index ebba0d50..7620a3d2 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -47,6 +47,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * for first-order. Returns the maximum impulse-response length of the * generated coefficients. */ -ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels); +ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels, const ALuint *AmbiMap); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 4e4caf46..de9b8cb1 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -756,25 +756,45 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin } } -static void InitHrtfPanning(ALCdevice *device) +static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) { - size_t count = 4; + static const ALuint map_foa[] = { 0, 1, 2, 3 }; + static const ALuint map_hoa[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + const ALuint *ambi_map = hoa_mode ? map_hoa : map_foa; + size_t count = hoa_mode ? COUNTOF(map_hoa) : COUNTOF(map_foa); ALuint i; + static_assert(COUNTOF(map_hoa) <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); + for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = i; + device->Dry.Ambi.Map[i].Index = ambi_map[i]; } device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; + if(!hoa_mode) + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + } + else + { + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + device->FOAOut.CoeffCount = 0; + + ambiup_reset(device->AmbiUp, device); + } memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs)); device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle, - device->Hrtf.Coeffs, device->Dry.NumChannels + device->Hrtf.Coeffs, device->Dry.NumChannels, hoa_mode ? ambi_map : NULL ); /* Round up to the nearest multiple of 8 */ @@ -895,8 +915,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf return; } - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; @@ -964,6 +982,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Hrtf.Handle) { + bool hoa_mode; + device->Render_Mode = HrtfRender; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { @@ -975,11 +995,27 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ERR("Unexpected hrtf-mode: %s\n", mode); } + if(device->Render_Mode == HrtfRender) + { + /* Don't bother with HOA when using full HRTF rendering. Nothing + * needs it, and it eases the CPU/memory load. + */ + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; + hoa_mode = false; + } + else + { + if(!device->AmbiUp) + device->AmbiUp = ambiup_alloc(); + hoa_mode = true; + } + TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), al_string_get_cstr(device->Hrtf.Name) ); - InitHrtfPanning(device); + InitHrtfPanning(device, hoa_mode); return; } device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; @@ -987,6 +1023,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf no_hrtf: TRACE("HRTF disabled\n"); + ambiup_free(device->AmbiUp); + device->AmbiUp = NULL; + bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; if(device->Type != Loopback) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5a5c3923..975dd11e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -643,8 +643,8 @@ struct ALCdevice_struct const struct Hrtf *Handle; /* HRTF filter state for dry buffer content */ - alignas(16) ALfloat Values[4][HRIR_LENGTH][2]; - alignas(16) ALfloat Coeffs[4][HRIR_LENGTH][2]; + alignas(16) ALfloat Values[9][HRIR_LENGTH][2]; + alignas(16) ALfloat Coeffs[9][HRIR_LENGTH][2]; ALuint Offset; ALuint IrSize; } Hrtf; -- cgit v1.2.3 From cbb796bf31cd3acfba0ce35e71a51d03e7e26021 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jan 2017 07:45:07 -0800 Subject: Use ALsizei for sizes and offsets with the mixer Unsigned 32-bit offsets actually have some potential overhead on 64-bit targets for pointer/array accesses due to rules on integer wrapping. No idea how much impact it has in practice, but it's nice to be correct about it. --- Alc/ALu.c | 2 +- Alc/hrtf.c | 52 +++++++++++++++++----------------- Alc/hrtf.h | 6 ++-- Alc/mixer.c | 6 ++-- Alc/mixer_c.c | 32 ++++++++++----------- Alc/mixer_defs.h | 72 +++++++++++++++++++++++------------------------ Alc/mixer_inc.c | 36 ++++++++++++------------ Alc/mixer_neon.c | 40 +++++++++++++------------- Alc/mixer_sse.c | 48 +++++++++++++++---------------- Alc/panning.c | 48 +++++++++++++++---------------- OpenAL32/Include/alMain.h | 10 +++---- OpenAL32/Include/alu.h | 26 ++++++++--------- 12 files changed, 189 insertions(+), 189 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 192f2a35..7022f792 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1498,7 +1498,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(lidx != -1 && ridx != -1) { HrtfDirectMixerFunc HrtfMix = SelectHrtfMixer(); - ALuint irsize = device->Hrtf.IrSize; + ALsizei irsize = device->Hrtf.IrSize; for(c = 0;c < device->Dry.NumChannels;c++) { HrtfMix(device->RealOut.Buffer, lidx, ridx, diff --git a/Alc/hrtf.c b/Alc/hrtf.c index a6efa34b..05215628 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -60,32 +60,32 @@ static struct Hrtf *LoadedHrtfs = NULL; * will return an index between 0 and (evcount - 1). Assumes the FPU is in * round-to-zero mode. */ -static ALuint CalcEvIndex(ALuint evcount, ALfloat ev) +static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev) { ev = (F_PI_2 + ev) * (evcount-1) / F_PI; - return minu(fastf2u(ev + 0.5f), evcount-1); + return mini(fastf2i(ev + 0.5f), evcount-1); } /* Calculate the azimuth index given the polar azimuth in radians. This will * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to- * zero mode. */ -static ALuint CalcAzIndex(ALuint azcount, ALfloat az) +static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az) { az = (F_TAU + az) * azcount / F_TAU; - return fastf2u(az + 0.5f) % azcount; + return fastf2i(az + 0.5f) % azcount; } /* Calculates static HRIR coefficients and delays for the given polar elevation * and azimuth in radians. The coefficients are normalized and attenuated by * the specified gain. */ -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALsizei *delays) { - ALuint evidx, azidx, lidx, ridx; - ALuint azcount, evoffset; + ALsizei evidx, azidx, lidx, ridx; + ALsizei azcount, evoffset; ALfloat dirfact; - ALuint i; + ALsizei i; dirfact = 1.0f - (spread / F_TAU); @@ -102,8 +102,8 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ridx = evoffset + ((azcount-azidx) % azcount); /* Calculate the HRIR delays. */ - delays[0] = fastf2u(Hrtf->delays[lidx]*dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2u(Hrtf->delays[ridx]*dirfact + 0.5f) << HRTFDELAY_BITS; + delays[0] = fastf2i(Hrtf->delays[lidx]*dirfact + 0.5f) << HRTFDELAY_BITS; + delays[1] = fastf2i(Hrtf->delays[ridx]*dirfact + 0.5f) << HRTFDELAY_BITS; /* Calculate the sample offsets for the HRIR indices. */ lidx *= Hrtf->irSize; @@ -136,7 +136,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels, const ALuint *AmbiMap) +ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALsizei *AmbiMap) { #define HRTF_AMBI_CHAN_COUNT 14 /* NOTE: azimuth goes clockwise. */ @@ -199,10 +199,10 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ #define NUM_BANDS 2 BandSplitter splitter; ALfloat temps[3][HRIR_LENGTH]; - ALuint lidx[14], ridx[14]; - ALuint min_delay = HRTF_HISTORY_LENGTH; - ALuint max_length = 0; - ALuint i, j, c, b; + ALsizei lidx[14], ridx[14]; + ALsizei min_delay = HRTF_HISTORY_LENGTH; + ALsizei max_length = 0; + ALsizei i, j, c, b; for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) { @@ -211,22 +211,22 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ ALuint azcount; /* Calculate elevation index. */ - evidx = (ALuint)floorf((F_PI_2 + Ambi3DPoints[c].elevation) * - (Hrtf->evCount-1)/F_PI + 0.5f); - evidx = minu(evidx, Hrtf->evCount-1); + evidx = (ALsizei)floorf((F_PI_2 + Ambi3DPoints[c].elevation) * + (Hrtf->evCount-1)/F_PI + 0.5f); + evidx = mini(evidx, Hrtf->evCount-1); azcount = Hrtf->azCount[evidx]; evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - azidx = (ALuint)floorf((F_TAU+Ambi3DPoints[c].azimuth) * - azcount/F_TAU + 0.5f) % azcount; + azidx = (ALsizei)floorf((F_TAU+Ambi3DPoints[c].azimuth) * + azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ lidx[c] = evoffset + azidx; ridx[c] = evoffset + ((azcount-azidx) % azcount); - min_delay = minu(min_delay, minu(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); + min_delay = mini(min_delay, mini(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); } memset(temps, 0, sizeof(temps)); @@ -234,7 +234,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) { const ALshort *fir; - ALuint delay; + ALsizei delay; /* Convert the left FIR from shorts to float */ fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; @@ -259,12 +259,12 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ const ALsizei a = AmbiMap ? AmbiMap[i] : i; for(b = 0;b < NUM_BANDS;b++) { - ALuint k = 0; + ALsizei k = 0; for(j = delay;j < HRIR_LENGTH;++j) coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][a]; } } - max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); + max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); /* Convert the right FIR from shorts to float */ fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; @@ -294,9 +294,9 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][a]; } } - max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH)); + max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); } - TRACE("Skipped min delay: %u, new combined length: %u\n", min_delay, max_length); + TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); #undef NUM_BANDS return max_length; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 7620a3d2..5ac4a03d 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -9,7 +9,7 @@ struct Hrtf { ALuint sampleRate; - ALuint irSize; + ALsizei irSize; ALubyte evCount; const ALubyte *azCount; @@ -40,13 +40,13 @@ void FreeHrtfs(void); vector_HrtfEntry EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_HrtfEntry *list); -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALsizei *delays); /* Produces HRTF filter coefficients for decoding B-Format. The result will * have ACN ordering with N3D normalization. NumChannels must currently be 4, * for first-order. Returns the maximum impulse-response length of the * generated coefficients. */ -ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels, const ALuint *AmbiMap); +ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALsizei *AmbiMap); #endif /* ALC_HRTF_H */ diff --git a/Alc/mixer.c b/Alc/mixer.c index be6a137c..cfb975f4 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -589,7 +589,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { ALfloat delta = 1.0f / (ALfloat)Counter; ALfloat coeffdiff; - ALint delaydiff; + ALsizei delaydiff; for(j = 0;j < IrSize;j++) { coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; @@ -597,9 +597,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1]; hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta; } - delaydiff = (ALint)(parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]); + delaydiff = parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]; hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta); - delaydiff = (ALint)(parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]); + delaydiff = parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]; hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta); } hrtfparams.Target = &parms->Hrtf.Target; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 6ef818c7..8ddd07f3 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -135,16 +135,16 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const } -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], const ALfloat (*restrict CoeffStep)[2], ALfloat left, ALfloat right) { - ALuint c; + ALsizei c; for(c = 0;c < IrSize;c++) { - const ALuint off = (Offset+c)&HRIR_MASK; + const ALsizei 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]; @@ -152,15 +152,15 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], } } -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { - ALuint c; + ALsizei c; for(c = 0;c < IrSize;c++) { - const ALuint off = (Offset+c)&HRIR_MASK; + const ALsizei off = (Offset+c)&HRIR_MASK; Values[off][0] += Coeffs[c][0] * left; Values[off][1] += Coeffs[c][1] * right; } @@ -172,23 +172,23 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], #undef MixHrtf -void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize) +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) { ALfloat gain, delta, step; - ALuint c; + ALsizei c; delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) { - ALuint pos = 0; + ALsizei pos = 0; gain = CurrentGains[c]; step = (TargetGains[c] - gain) * delta; if(fabsf(step) > FLT_EPSILON) { - ALuint minsize = minu(BufferSize, Counter); + ALsizei minsize = mini(BufferSize, Counter); for(;pos < minsize;pos++) { OutBuffer[c][OutPos+pos] += data[pos]*gain; @@ -212,9 +212,9 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B * transform. And as the matrices are more or less static once set up, no * stepping is necessary. */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { - ALuint c, i; + ALsizei c, i; for(c = 0;c < InChans;c++) { diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 24916002..318df626 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -21,36 +21,36 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri /* C mixers */ -void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALuint BufferSize); -void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Offset, const ALuint IrSize, +void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALuint BufferSize); -void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize); + ALsizei BufferSize); +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint InPos, ALuint BufferSize); + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); /* SSE mixers */ -void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALuint BufferSize); -void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Offset, const ALuint IrSize, +void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALuint BufferSize); -void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize); + ALsizei BufferSize); +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint InPos, ALuint BufferSize); + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); /* SSE resamplers */ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size) @@ -92,19 +92,19 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *re ALuint numsamples); /* Neon mixers */ -void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALuint BufferSize); -void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Offset, const ALuint IrSize, +void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALuint BufferSize); -void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize); + ALsizei BufferSize); +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint InPos, ALuint BufferSize); + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index 25dc2b58..38b0242e 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -12,28 +12,28 @@ #define MAX_UPDATE_SAMPLES 128 -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint irSize, +static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei 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, +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei irSize, ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right); -void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, - ALuint BufferSize) +void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + ALsizei BufferSize) { ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; - ALuint Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; + ALsizei Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; ALfloat out[MAX_UPDATE_SAMPLES][2]; ALfloat left, right; - ALuint minsize; - ALuint pos, i; + ALsizei minsize; + ALsizei pos, i; pos = 0; if(Counter == 0) @@ -42,7 +42,7 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx minsize = minu(BufferSize, Counter); while(pos < minsize) { - ALuint todo = minu(minsize-pos, MAX_UPDATE_SAMPLES); + ALsizei todo = mini(minsize-pos, MAX_UPDATE_SAMPLES); for(i = 0;i < todo;i++) { @@ -90,7 +90,7 @@ skip_stepping: Delay[1] >>= HRTFDELAY_BITS; while(pos < BufferSize) { - ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES); + ALsizei todo = mini(BufferSize-pos, MAX_UPDATE_SAMPLES); for(i = 0;i < todo;i++) { @@ -115,18 +115,18 @@ skip_stepping: } } -void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Offset, const ALuint IrSize, +void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALuint BufferSize) + ALsizei BufferSize) { ALfloat out[MAX_UPDATE_SAMPLES][2]; ALfloat insample; - ALuint pos, i; + ALsizei pos, i; for(pos = 0;pos < BufferSize;) { - ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES); + ALsizei todo = mini(BufferSize-pos, MAX_UPDATE_SAMPLES); for(i = 0;i < todo;i++) { diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 6b506357..0fbcea67 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -9,13 +9,13 @@ #include "hrtf.h" -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], const ALfloat (*restrict CoeffStep)[2], ALfloat left, ALfloat right) { - ALuint c; + ALsizei c; float32x4_t leftright4; { float32x2_t leftright2 = vdup_n_f32(0.0); @@ -25,8 +25,8 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], } for(c = 0;c < IrSize;c += 2) { - const ALuint o0 = (Offset+c)&HRIR_MASK; - const ALuint o1 = (o0+1)&HRIR_MASK; + const ALsizei o0 = (Offset+c)&HRIR_MASK; + const ALsizei o1 = (o0+1)&HRIR_MASK; float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), vld1_f32((float32_t*)&Values[o1][0])); float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); @@ -41,12 +41,12 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], } } -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { - ALuint c; + ALsizei c; float32x4_t leftright4; { float32x2_t leftright2 = vdup_n_f32(0.0); @@ -56,8 +56,8 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } for(c = 0;c < IrSize;c += 2) { - const ALuint o0 = (Offset+c)&HRIR_MASK; - const ALuint o1 = (o0+1)&HRIR_MASK; + const ALsizei o0 = (Offset+c)&HRIR_MASK; + const ALsizei o1 = (o0+1)&HRIR_MASK; float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), vld1_f32((float32_t*)&Values[o1][0])); float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); @@ -75,24 +75,24 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], #undef MixHrtf -void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize) +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) { ALfloat gain, delta, step; float32x4_t gain4; - ALuint c; + ALsizei c; delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) { - ALuint pos = 0; + ALsizei pos = 0; gain = CurrentGains[c]; step = (TargetGains[c] - gain) * delta; if(fabsf(step) > FLT_EPSILON) { - ALuint minsize = minu(BufferSize, Counter); + ALsizei minsize = mini(BufferSize, Counter); /* Mix with applying gain steps in aligned multiples of 4. */ if(minsize-pos > 3) { @@ -127,7 +127,7 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = minu(BufferSize, (pos+3)&~3); + minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; } @@ -147,14 +147,14 @@ void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer } } -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { float32x4_t gain4; - ALuint c; + ALsizei c; for(c = 0;c < InChans;c++) { - ALuint pos = 0; + ALsizei pos = 0; ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index f5e21e23..bad08e2d 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -72,8 +72,8 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest } -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], const ALfloat (*restrict CoeffStep)[2], ALfloat left, ALfloat right) @@ -81,12 +81,12 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const __m128 lrlr = _mm_setr_ps(left, right, left, right); __m128 coeffs, deltas, imp0, imp1; __m128 vals = _mm_setzero_ps(); - ALuint i; + ALsizei i; if((Offset&1)) { - const ALuint o0 = Offset&HRIR_MASK; - const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; + const ALsizei o0 = Offset&HRIR_MASK; + const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; coeffs = _mm_load_ps(&Coeffs[0][0]); deltas = _mm_load_ps(&CoeffStep[0][0]); @@ -98,7 +98,7 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], _mm_storel_pi((__m64*)&Values[o0][0], vals); for(i = 1;i < IrSize-1;i += 2) { - const ALuint o2 = (Offset+i)&HRIR_MASK; + const ALsizei o2 = (Offset+i)&HRIR_MASK; coeffs = _mm_load_ps(&Coeffs[i+1][0]); deltas = _mm_load_ps(&CoeffStep[i+1][0]); @@ -120,7 +120,7 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], { for(i = 0;i < IrSize;i += 2) { - const ALuint o = (Offset + i)&HRIR_MASK; + const ALsizei o = (Offset + i)&HRIR_MASK; coeffs = _mm_load_ps(&Coeffs[i][0]); deltas = _mm_load_ps(&CoeffStep[i][0]); @@ -134,20 +134,20 @@ static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], } } -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { const __m128 lrlr = _mm_setr_ps(left, right, left, right); __m128 vals = _mm_setzero_ps(); __m128 coeffs; - ALuint i; + ALsizei i; if((Offset&1)) { - const ALuint o0 = Offset&HRIR_MASK; - const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; + const ALsizei o0 = Offset&HRIR_MASK; + const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; __m128 imp0, imp1; coeffs = _mm_load_ps(&Coeffs[0][0]); @@ -157,7 +157,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], _mm_storel_pi((__m64*)&Values[o0][0], vals); for(i = 1;i < IrSize-1;i += 2) { - const ALuint o2 = (Offset+i)&HRIR_MASK; + const ALsizei o2 = (Offset+i)&HRIR_MASK; coeffs = _mm_load_ps(&Coeffs[i+1][0]); vals = _mm_load_ps(&Values[o2][0]); @@ -176,7 +176,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], { for(i = 0;i < IrSize;i += 2) { - const ALuint o = (Offset + i)&HRIR_MASK; + const ALsizei o = (Offset + i)&HRIR_MASK; coeffs = _mm_load_ps(&Coeffs[i][0]); vals = _mm_load_ps(&Values[o][0]); @@ -192,24 +192,24 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], #undef MixHrtf -void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize) +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) { ALfloat gain, delta, step; __m128 gain4; - ALuint c; + ALsizei c; delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) { - ALuint pos = 0; + ALsizei pos = 0; gain = CurrentGains[c]; step = (TargetGains[c] - gain) * delta; if(fabsf(step) > FLT_EPSILON) { - ALuint minsize = minu(BufferSize, Counter); + ALsizei minsize = mini(BufferSize, Counter); /* Mix with applying gain steps in aligned multiples of 4. */ if(minsize-pos > 3) { @@ -246,7 +246,7 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = minu(BufferSize, (pos+3)&~3); + minsize = mini(BufferSize, (pos+3)&~3); for(;pos < minsize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; } @@ -266,14 +266,14 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) } } -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize) +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { __m128 gain4; - ALuint c; + ALsizei c; for(c = 0;c < InChans;c++) { - ALuint pos = 0; + ALsizei pos = 0; ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/panning.c b/Alc/panning.c index de9b8cb1..06c0d9cc 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -45,7 +45,7 @@ extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread #define THIRD_ORDER_SCALE (1.0f / 1.30657f) -static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = { +static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { 0, /* W */ 3, /* X */ 1, /* Y */ @@ -63,7 +63,7 @@ static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = { 15, /* P */ 9, /* Q */ }; -static const ALuint ACN2ACN[MAX_AMBI_COEFFS] = { +static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; @@ -345,7 +345,7 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff const ChannelMap *chanmap, size_t count, ALuint *outcount, ALboolean isfuma) { - const ALuint *acnmap = isfuma ? FuMa2ACN : ACN2ACN; + const ALsizei *acnmap = isfuma ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = isfuma ? FuMa2N3DScale : UnitScale; size_t j, k; ALuint i; @@ -366,7 +366,7 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff for(k = 0;k < MAX_AMBI_COEFFS;++k) { - ALuint acn = acnmap[k]; + ALsizei acn = acnmap[k]; ambicoeffs[i][acn] = chanmap[j].Config[k] / n3dscale[acn]; } break; @@ -514,10 +514,10 @@ static const ChannelMap MonoCfg[1] = { static void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; - ALuint coeffcount = 0; + ALsizei coeffcount = 0; ALfloat ambiscale; - size_t count = 0; - ALuint i, j; + ALsizei count = 0; + ALsizei i, j; ambiscale = 1.0f; switch(device->FmtChans) @@ -579,7 +579,7 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { - const ALuint *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; + const ALsizei *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : (device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale : /*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale; @@ -589,7 +589,7 @@ static void InitPanning(ALCdevice *device) (device->FmtChans == DevFmtAmbi1) ? 4 : 1; for(i = 0;i < count;i++) { - ALuint acn = acnmap[i]; + ALsizei acn = acnmap[i]; device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn]; device->Dry.Ambi.Map[i].Index = acn; } @@ -624,7 +624,7 @@ static void InitPanning(ALCdevice *device) device->Dry.CoeffCount = coeffcount; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < device->Dry.NumChannels;i++) + for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; for(j = 1;j < 4;j++) @@ -639,7 +639,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = UnitScale; ALfloat ambiscale = 1.0f; - ALuint i, j; + ALsizei i, j; if(conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", @@ -659,11 +659,11 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A else if(conf->CoeffScale == ADS_FuMa) coeff_scale = FuMa2N3DScale; - for(i = 0;i < conf->NumSpeakers;i++) + for(i = 0;i < (ALsizei)conf->NumSpeakers;i++) { - ALuint chan = speakermap[i]; + ALsizei chan = speakermap[i]; ALfloat gain; - ALuint k = 0; + ALsizei k = 0; for(j = 0;j < MAX_AMBI_COEFFS;j++) chanmap[i].Config[j] = 0.0f; @@ -686,7 +686,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A (conf->ChanMask > 0xf) ? 9 : 4; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < device->Dry.NumChannels;i++) + for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++) { device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; for(j = 1;j < 4;j++) @@ -700,7 +700,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin const char *devname; int decflags = 0; size_t count; - ALuint i; + size_t i; devname = al_string_get_cstr(device->DeviceName); if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) @@ -758,11 +758,11 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuin static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) { - static const ALuint map_foa[] = { 0, 1, 2, 3 }; - static const ALuint map_hoa[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; - const ALuint *ambi_map = hoa_mode ? map_hoa : map_foa; + static const ALsizei map_foa[] = { 0, 1, 2, 3 }; + static const ALsizei map_hoa[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + const ALsizei *ambi_map = hoa_mode ? map_hoa : map_foa; size_t count = hoa_mode ? COUNTOF(map_hoa) : COUNTOF(map_foa); - ALuint i; + size_t i; static_assert(COUNTOF(map_hoa) <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); @@ -803,12 +803,12 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) static void InitUhjPanning(ALCdevice *device) { - size_t count = 3; - ALuint i; + ALsizei count = 3; + ALsizei i; for(i = 0;i < count;i++) { - ALuint acn = FuMa2ACN[i]; + ALsizei acn = FuMa2ACN[i]; device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn]; device->Dry.Ambi.Map[i].Index = acn; } @@ -1065,7 +1065,7 @@ no_hrtf: void aluInitEffectPanning(ALeffectslot *slot) { - ALuint i; + ALsizei i; memset(slot->ChanMap, 0, sizeof(slot->ChanMap)); slot->NumChannels = 0; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 975dd11e..fca98be9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -562,7 +562,7 @@ enum RenderMode { typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; typedef struct BFChannelConfig { ALfloat Scale; - ALuint Index; + ALsizei Index; } BFChannelConfig; typedef union AmbiConfig { @@ -584,7 +584,7 @@ typedef struct HrtfState { typedef struct HrtfParams { alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - ALuint Delay[2]; + ALsizei Delay[2]; } HrtfParams; @@ -593,7 +593,7 @@ typedef struct HrtfParams { * 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. */ -#define BUFFERSIZE (2048u) +#define BUFFERSIZE 2048 struct ALCdevice_struct { @@ -645,8 +645,8 @@ struct ALCdevice_struct /* HRTF filter state for dry buffer content */ alignas(16) ALfloat Values[9][HRIR_LENGTH][2]; alignas(16) ALfloat Coeffs[9][HRIR_LENGTH][2]; - ALuint Offset; - ALuint IrSize; + ALsizei Offset; + ALsizei IrSize; } Hrtf; /* UHJ encoder state */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index ae8645fa..cd2170cf 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -115,7 +115,7 @@ typedef struct MixHrtfParams { HrtfParams *Current; struct { alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - ALint Delay[2]; + ALsizei Delay[2]; } Steps; } MixHrtfParams; @@ -152,21 +152,21 @@ typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen ); -typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, +typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, - const ALfloat *TargetGains, ALuint Counter, ALuint OutPos, - ALuint BufferSize); + const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, - ALuint InPos, ALuint BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx, - const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, - const ALuint IrSize, const MixHrtfParams *hrtfparams, - HrtfState *hrtfstate, ALuint BufferSize); + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); +typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, + const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const MixHrtfParams *hrtfparams, + HrtfState *hrtfstate, ALsizei BufferSize); typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Offset, - const ALuint IrSize, ALfloat (*restrict Coeffs)[2], - ALfloat (*restrict Values)[2], ALuint BufferSize); + ALsizei lidx, ALsizei ridx, const ALfloat *data, ALsizei Offset, + const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], + ALfloat (*restrict Values)[2], ALsizei BufferSize); #define GAIN_MIX_MAX (16.0f) /* +24dB */ -- cgit v1.2.3 From 325a49975a762744638b56b6a7ddd2ccd40fda55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jan 2017 08:54:30 -0800 Subject: Use ALsizei and ALint for sizes and offsets with resamplers and filters --- Alc/mixer.c | 2 +- Alc/mixer_c.c | 24 +++++++++++------------ Alc/mixer_defs.h | 47 +++++++++++++++++++++++---------------------- Alc/mixer_sse.c | 9 ++++----- Alc/mixer_sse2.c | 10 +++++----- Alc/mixer_sse3.c | 20 +++++++++---------- Alc/mixer_sse41.c | 30 ++++++++++++++--------------- OpenAL32/Include/alFilter.h | 4 ++-- OpenAL32/Include/alu.h | 3 ++- OpenAL32/alFilter.c | 2 +- 10 files changed, 76 insertions(+), 75 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index cfb975f4..e759482e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -41,7 +41,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size); +extern inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); alignas(16) union ResamplerCoeffs ResampleCoeffs; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 8ddd07f3..15c603ca 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -18,8 +18,9 @@ static inline ALfloat fir8_32(const ALfloat *restrict vals, ALuint frac) { return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); } -const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *restrict src, ALuint UNUSED(frac), - ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples) +const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), + const ALfloat *restrict src, ALuint UNUSED(frac), ALint UNUSED(increment), + ALfloat *restrict dst, ALsizei numsamples) { #if defined(HAVE_SSE) || defined(HAVE_NEON) /* Avoid copying the source data if it's aligned like the destination. */ @@ -32,10 +33,10 @@ const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat #define DECL_TEMPLATE(Sampler) \ const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \ - const ALfloat *restrict src, ALuint frac, ALuint increment, \ - ALfloat *restrict dst, ALuint numsamples) \ + const ALfloat *restrict src, ALuint frac, ALint increment, \ + ALfloat *restrict dst, ALsizei numsamples) \ { \ - ALuint i; \ + ALsizei i; \ for(i = 0;i < numsamples;i++) \ { \ dst[i] = Sampler(src, frac); \ @@ -55,16 +56,15 @@ DECL_TEMPLATE(fir8_32) #undef DECL_TEMPLATE const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint dstlen) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen) { const ALfloat *fil, *scd, *phd, *spd; const ALfloat sf = state->sf; - const ALuint m = state->m; + const ALsizei m = state->m; const ALint l = state->l; - ALuint j_f, pi, i; + ALsizei j_s, j_f, pi, i; ALfloat pf, r; - ALint j_s; for(i = 0;i < dstlen;i++) { @@ -94,9 +94,9 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples) +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { - ALuint i; + ALsizei i; if(numsamples > 1) { dst[0] = filter->b0 * src[0] + diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 318df626..6d2b3c04 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -12,12 +12,12 @@ struct MixHrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); /* C mixers */ @@ -53,43 +53,44 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALsizei InPos, ALsizei BufferSize); /* SSE resamplers */ -inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size) +inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) { - ALuint i; + ALsizei i; pos_arr[0] = 0; frac_arr[0] = frac; for(i = 1;i < size;i++) { - ALuint frac_tmp = frac_arr[i-1] + increment; + ALint frac_tmp = frac_arr[i-1] + increment; pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); frac_arr[i] = frac_tmp&FRACTIONMASK; } } -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, ALuint frac, - ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen); const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples); + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); /* Neon mixers */ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index bad08e2d..96228b47 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -13,16 +13,15 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint dstlen) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen) { const __m128 sf4 = _mm_set1_ps(state->sf); - const ALuint m = state->m; + const ALsizei m = state->m; const ALint l = state->l; const ALfloat *fil, *scd, *phd, *spd; - ALuint pi, j_f, i; + ALsizei j_s, pi, j_f, i; ALfloat pf; - ALint j_s; __m128 r4; for(i = 0;i < dstlen;i++) diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index 22a18ef3..5cf4c8a0 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -28,17 +28,17 @@ const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i; + ALint pos; + ALsizei i; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 66005e53..34121d71 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -32,16 +32,16 @@ const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i; + ALint pos; + ALsizei i; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); @@ -97,16 +97,16 @@ const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfl } const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i, j; + ALsizei i, j; + ALint pos; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index 7a4db6cf..a531ca77 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -29,17 +29,17 @@ const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i; + ALint pos; + ALsizei i; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); @@ -86,16 +86,16 @@ const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfl } const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i; + ALint pos; + ALsizei i; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); @@ -154,16 +154,16 @@ const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALf } const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALuint increment, ALfloat *restrict dst, - ALuint numsamples) + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALuint i[4]; float f[4]; } pos_; + union { alignas(16) ALint i[4]; float f[4]; } pos_; union { alignas(16) ALuint i[4]; float f[4]; } frac_; __m128i frac4, pos4; - ALuint pos; - ALuint i, j; + ALsizei i, j; + ALint pos; InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index bec4d46b..019e40d3 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -77,9 +77,9 @@ inline void ALfilterState_clear(ALfilterState *filter) void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples); +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); -inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples) +inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples) { if(numsamples >= 2) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index cd2170cf..4a424246 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -149,7 +149,8 @@ typedef struct SendParams { typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, - const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei dstlen ); typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index c675d344..150d84b5 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -36,7 +36,7 @@ extern inline void UnlockFiltersWrite(ALCdevice *device); extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); -extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALuint numsamples); +extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); -- cgit v1.2.3 From 959812ee13e4869309e3c2cf507f6b0458ad8618 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jan 2017 08:59:08 -0800 Subject: Use ALsizei in a few more places --- Alc/bformatdec.c | 4 ++-- Alc/bformatdec.h | 2 +- Alc/uhjfilter.c | 10 +++++----- Alc/uhjfilter.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 5556c2ef..c18376b5 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -32,11 +32,11 @@ void bandsplit_clear(BandSplitter *splitter) } void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, - const ALfloat *input, ALuint count) + const ALfloat *input, ALsizei count) { ALfloat coeff, d, x; ALfloat z1, z2; - ALuint i; + ALsizei i; coeff = splitter->coeff*0.5f + 0.5f; z1 = splitter->lp_z1; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index e78d89a7..2fd38ac5 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -44,6 +44,6 @@ typedef struct BandSplitter { void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult); void bandsplit_clear(BandSplitter *splitter); void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, - const ALfloat *input, ALuint count); + const ALfloat *input, ALsizei count); #endif /* BFORMATDEC_H */ diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index 0a702873..8e2febae 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -16,9 +16,9 @@ static const ALfloat Filter2Coeff[4] = { 0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f }; -static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALuint todo) +static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo) { - ALuint i; + ALsizei i; if(todo > 1) { @@ -62,15 +62,15 @@ static void allpass_process(AllPassState *state, ALfloat *restrict dst, const AL * know which is the intended result. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES]; ALfloat temp[2][MAX_UPDATE_SAMPLES]; - ALuint base, i; + ALsizei base, i; for(base = 0;base < SamplesToDo;) { - ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES); + ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); /* D = 0.6554516*Y */ for(i = 0;i < todo;i++) diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index cec3463e..48c2fde6 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -44,6 +44,6 @@ typedef struct Uhj2Encoder { /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input * signal. The input must use FuMa channel ordering and scaling. */ -void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); #endif /* UHJFILTER_H */ -- cgit v1.2.3 From f1f93a593a62b1a06f900d809628b5678eab4d8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jan 2017 09:04:58 -0800 Subject: Fix a couple hard-coded array sizes --- Alc/hrtf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 05215628..3fbb2eb1 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -198,9 +198,9 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] */ #define NUM_BANDS 2 BandSplitter splitter; - ALfloat temps[3][HRIR_LENGTH]; - ALsizei lidx[14], ridx[14]; + ALsizei lidx[HRTF_AMBI_CHAN_COUNT], ridx[HRTF_AMBI_CHAN_COUNT]; ALsizei min_delay = HRTF_HISTORY_LENGTH; + ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; ALsizei i, j, c, b; -- cgit v1.2.3 From e9009968fbfe3f89b308f6f2880e3bbafbb27884 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jan 2017 09:37:55 -0800 Subject: More ALsizei, with the B-Format decoder --- Alc/ambdec.c | 21 +++++++++++++++------ Alc/ambdec.h | 2 +- Alc/bformatdec.c | 26 +++++++++++++------------- Alc/bformatdec.h | 8 ++++---- Alc/panning.c | 4 ++-- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Alc/ambdec.c b/Alc/ambdec.c index 255011d5..719b509c 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -90,6 +90,15 @@ static char *my_strtok_r(char *str, const char *delim, char **saveptr) return str; } +static char *read_int(ALint *num, const char *line, int base) +{ + char *end; + *num = strtol(line, &end, base); + if(end && *end != '\0') + end = lstrip(end); + return end; +} + static char *read_uint(ALuint *num, const char *line, int base) { char *end; @@ -131,7 +140,7 @@ char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen) static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr) { - ALuint cur = 0; + ALsizei cur = 0; while(cur < conf->NumSpeakers) { const char *cmd = my_strtok_r(NULL, " \t", saveptr); @@ -184,10 +193,10 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t return 1; } -static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALuint maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) +static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr) { int gotgains = 0; - ALuint cur = 0; + ALsizei cur = 0; while(cur < maxrow) { const char *cmd = my_strtok_r(NULL, " \t", saveptr); @@ -269,7 +278,7 @@ static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS] void ambdec_init(AmbDecConf *conf) { - ALuint i; + ALsizei i; memset(conf, 0, sizeof(*conf)); AL_STRING_INIT(conf->Description); @@ -282,7 +291,7 @@ void ambdec_init(AmbDecConf *conf) void ambdec_deinit(AmbDecConf *conf) { - ALuint i; + ALsizei i; al_string_deinit(&conf->Description); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -370,7 +379,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) else if(strcmp(dec, "speakers") == 0) { line = my_strtok_r(NULL, "", &saveptr); - line = read_uint(&conf->NumSpeakers, line, 10); + line = read_int(&conf->NumSpeakers, line, 10); if(line && *line != '\0') { ERR("Extra junk after speakers: %s\n", line); diff --git a/Alc/ambdec.h b/Alc/ambdec.h index 8a3befc1..0bb84072 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -17,7 +17,7 @@ typedef struct AmbDecConf { ALuint ChanMask; ALuint FreqBands; /* Must be 1 or 2 */ - ALuint NumSpeakers; + ALsizei NumSpeakers; enum AmbDecScaleType CoeffScale; ALfloat XOverFreq; diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index c18376b5..fa7d2e19 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -246,7 +246,7 @@ typedef struct BFormatDec { struct { alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; - ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ + ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ } Delay[MAX_OUTPUT_CHANNELS]; struct { @@ -255,7 +255,7 @@ typedef struct BFormatDec { ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max]; } UpSampler; - ALuint NumChannels; + ALsizei NumChannels; ALboolean DualBand; ALboolean Periphonic; } BFormatDec; @@ -297,7 +297,7 @@ int bformatdec_getOrder(const struct BFormatDec *dec) return 0; } -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags) +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags) { static const ALuint map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 @@ -305,7 +305,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, const ALfloat *coeff_scale = UnitScale; ALfloat distgain[MAX_OUTPUT_CHANNELS]; ALfloat maxdist, ratio; - ALuint i; + ALsizei i; al_free(dec->Samples); dec->Samples = NULL; @@ -375,7 +375,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)); distgain[i] = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan, + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i] ); } @@ -492,9 +492,9 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, } -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { - ALuint chan, i; + ALsizei chan, i; if(dec->DualBand) { @@ -519,7 +519,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU if(dec->Delay[chan].Length > 0) { - const ALuint base = dec->Delay[chan].Length; + const ALsizei base = dec->Delay[chan].Length; if(SamplesToDo >= base) { for(i = 0;i < base;i++) @@ -556,7 +556,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU if(dec->Delay[chan].Length > 0) { - const ALuint base = dec->Delay[chan].Length; + const ALsizei base = dec->Delay[chan].Length; if(SamplesToDo >= base) { for(i = 0;i < base;i++) @@ -583,9 +583,9 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU } -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo) +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) { - ALuint i, j; + ALsizei i, j; /* This up-sampler is very simplistic. It essentially decodes the first- * order content to a square channel array (or cube if height is desired), @@ -652,9 +652,9 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) ambiup->Gains, device->Dry.NumChannels); } -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo) +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) { - ALuint i, j; + ALsizei i, j; for(i = 0;i < 4;i++) { diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 2fd38ac5..3f240e54 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -14,13 +14,13 @@ enum BFormatDecFlags { struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); -void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags); +void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags); /* Decodes the ambisonic input to the given output channels. */ -void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); /* Up-samples a first-order input to the decoder's configuration. */ -void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo); +void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo); /* Stand-alone first-order upsampler. Kept here because it shares some stuff @@ -30,7 +30,7 @@ struct AmbiUpsampler *ambiup_alloc(); void ambiup_free(struct AmbiUpsampler *ambiup); void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); -void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo); +void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); /* Band splitter. Splits a signal into two phase-matching frequency bands. */ diff --git a/Alc/panning.c b/Alc/panning.c index 06c0d9cc..e1ad6d0b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -379,7 +379,7 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS]) { - ALuint i; + ALsizei i; for(i = 0;i < conf->NumSpeakers;i++) { @@ -659,7 +659,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A else if(conf->CoeffScale == ADS_FuMa) coeff_scale = FuMa2N3DScale; - for(i = 0;i < (ALsizei)conf->NumSpeakers;i++) + for(i = 0;i < conf->NumSpeakers;i++) { ALsizei chan = speakermap[i]; ALfloat gain; -- cgit v1.2.3 From bfb7a6e4c85838bf2f6ed28fba452c55ad50c566 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jan 2017 11:35:19 -0800 Subject: Small update for the "virtual" Ambi2DDecoder coefficients --- Alc/bformatdec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index fa7d2e19..f3cc476f 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -130,10 +130,10 @@ static const ALfloat Ambi2DPoints[4][3] = { { 0.707106781f, 0.0f, 0.707106781f }, }; static const ALfloat Ambi2DDecoder[4][FB_Max][MAX_AMBI_COEFFS] = { - { { 0.353553f, 0.204094f, 0.0f, 0.204094f }, { 0.25f, 0.204094f, 0.0f, 0.204094f } }, - { { 0.353553f, -0.204094f, 0.0f, 0.204094f }, { 0.25f, -0.204094f, 0.0f, 0.204094f } }, - { { 0.353553f, 0.204094f, 0.0f, -0.204094f }, { 0.25f, 0.204094f, 0.0f, -0.204094f } }, - { { 0.353553f, -0.204094f, 0.0f, -0.204094f }, { 0.25f, -0.204094f, 0.0f, -0.204094f } }, + { { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f }, { 0.25f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f }, { 0.25f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f }, { 0.25f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, + { { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f }, { 0.25f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } }, }; static ALfloat Ambi2DEncoderT[4][MAX_AMBI_COEFFS]; @@ -168,7 +168,7 @@ static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT; static void init_bformatdec(void) { - ALuint i, j; + size_t i, j; MixMatrixRow = SelectRowMixer(); -- cgit v1.2.3 From ba0944af9ba8d851bc5b6ad99f314bbdac269716 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jan 2017 16:49:26 -0800 Subject: Pass the left and right buffers to the hrtf mixers directly --- Alc/ALu.c | 30 ++++++++++++++++-------------- Alc/mixer.c | 10 ++++++---- Alc/mixer_defs.h | 12 ++++++------ Alc/mixer_inc.c | 16 ++++++++-------- OpenAL32/Include/alu.h | 10 +++++----- 5 files changed, 41 insertions(+), 37 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 7022f792..02b4ffe8 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1486,8 +1486,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(device->Hrtf.Handle) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + HrtfDirectMixerFunc HrtfMix; + ALsizei irsize; + int lidx, ridx; if(device->AmbiUp) ambiup_process(device->AmbiUp, @@ -1495,20 +1496,21 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo ); - if(lidx != -1 && ridx != -1) + lidx = GetChannelIdxByName(device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + HrtfMix = SelectHrtfMixer(); + irsize = device->Hrtf.IrSize; + for(c = 0;c < device->Dry.NumChannels;c++) { - HrtfDirectMixerFunc HrtfMix = SelectHrtfMixer(); - ALsizei irsize = device->Hrtf.IrSize; - for(c = 0;c < device->Dry.NumChannels;c++) - { - HrtfMix(device->RealOut.Buffer, lidx, ridx, - device->Dry.Buffer[c], device->Hrtf.Offset, irsize, - device->Hrtf.Coeffs[c], device->Hrtf.Values[c], - SamplesToDo - ); - } - device->Hrtf.Offset += SamplesToDo; + HrtfMix(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer[c], device->Hrtf.Offset, irsize, + device->Hrtf.Coeffs[c], device->Hrtf.Values[c], + SamplesToDo + ); } + device->Hrtf.Offset += SamplesToDo; } else if(device->AmbiDecoder) { diff --git a/Alc/mixer.c b/Alc/mixer.c index e759482e..2d804b1f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -589,7 +589,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { ALfloat delta = 1.0f / (ALfloat)Counter; ALfloat coeffdiff; - ALsizei delaydiff; + ALint delaydiff; for(j = 0;j < IrSize;j++) { coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; @@ -609,9 +609,11 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ridx = GetChannelIdxByName(Device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); - MixHrtfSamples(voice->DirectOut.Buffer, lidx, ridx, samples, Counter, - voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, DstBufferSize); + MixHrtfSamples( + voice->DirectOut.Buffer[lidx], voice->DirectOut.Buffer[ridx], + samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf.State, DstBufferSize + ); } } diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 6d2b3c04..64da7680 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -21,11 +21,11 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri /* C mixers */ -void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); @@ -37,11 +37,11 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, ALsizei InPos, ALsizei BufferSize); /* SSE mixers */ -void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); @@ -93,11 +93,11 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *re ALsizei numsamples); /* Neon mixers */ -void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index 38b0242e..8215743e 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -23,7 +23,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], ALfloat left, ALfloat right); -void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) @@ -67,9 +67,9 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ri } for(i = 0;i < todo;i++) - OutBuffer[lidx][OutPos+i] += out[i][0]; + LeftOut[OutPos+i] += out[i][0]; for(i = 0;i < todo;i++) - OutBuffer[ridx][OutPos+i] += out[i][1]; + RightOut[OutPos+i] += out[i][1]; OutPos += todo; } @@ -108,14 +108,14 @@ skip_stepping: } for(i = 0;i < todo;i++) - OutBuffer[lidx][OutPos+i] += out[i][0]; + LeftOut[OutPos+i] += out[i][0]; for(i = 0;i < todo;i++) - OutBuffer[ridx][OutPos+i] += out[i][1]; + RightOut[OutPos+i] += out[i][1]; OutPos += todo; } } -void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize) @@ -141,9 +141,9 @@ void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsi } for(i = 0;i < todo;i++) - OutBuffer[lidx][pos+i] += out[i][0]; + LeftOut[pos+i] += out[i][0]; for(i = 0;i < todo;i++) - OutBuffer[ridx][pos+i] += out[i][1]; + RightOut[pos+i] += out[i][1]; pos += todo; } } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 4a424246..21b787d2 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -160,14 +160,14 @@ typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); -typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei lidx, ALsizei ridx, +typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); -typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALsizei lidx, ALsizei ridx, const ALfloat *data, ALsizei Offset, - const ALsizei IrSize, ALfloat (*restrict Coeffs)[2], - ALfloat (*restrict Values)[2], ALsizei BufferSize); +typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize); #define GAIN_MIX_MAX (16.0f) /* +24dB */ -- cgit v1.2.3 From d2e5aa79ddc79bccde67d375cffea8f9922ca611 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jan 2017 07:13:23 -0800 Subject: Use ALsizei in more places --- Alc/ALc.c | 8 ++--- Alc/ALu.c | 2 +- Alc/backends/solaris.c | 6 ++-- Alc/mixer.c | 66 +++++++++++++++++++------------------- Alc/panning.c | 28 ++++++++-------- OpenAL32/Include/alAuxEffectSlot.h | 4 +-- OpenAL32/Include/alBuffer.h | 16 ++++----- OpenAL32/Include/alMain.h | 16 ++++----- OpenAL32/Include/alSource.h | 8 ++--- OpenAL32/Include/alu.h | 14 ++++---- OpenAL32/alBuffer.c | 20 ++++++------ 11 files changed, 94 insertions(+), 94 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0b558ff7..80378d91 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1310,8 +1310,8 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) return "(unknown channels)"; } -extern inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type); -ALuint BytesFromDevFmt(enum DevFmtType type) +extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type); +ALsizei BytesFromDevFmt(enum DevFmtType type) { switch(type) { @@ -1325,7 +1325,7 @@ ALuint BytesFromDevFmt(enum DevFmtType type) } return 0; } -ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) +ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans) { switch(chans) { @@ -2093,7 +2093,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FOAOut.Buffer = device->Dry.Buffer; device->FOAOut.NumChannels = device->Dry.NumChannels; } - TRACE("Channel config, Dry: %u, FOA: %u, Real: %u\n", device->Dry.NumChannels, + TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, device->FOAOut.NumChannels, device->RealOut.NumChannels); SetMixerFPUMode(&oldMode); diff --git a/Alc/ALu.c b/Alc/ALu.c index 02b4ffe8..9b03b85a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1400,7 +1400,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALsource *source; ALCcontext *ctx; FPUCtl oldMode; - ALuint i, c; + ALsizei i, c; SetMixerFPUMode(&oldMode); diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 01472e6a..792f717a 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -177,8 +177,8 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; audio_info_t info; - ALuint frameSize; - int numChannels; + ALsizei frameSize; + ALsizei numChannels; AUDIO_INITINFO(&info); @@ -220,7 +220,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) return ALC_FALSE; } - if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels) + if(ChannelsFromDevFmt(device->FmtChans) != (ALsizei)info.play.channels) { ERR("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels); return ALC_FALSE; diff --git a/Alc/mixer.c b/Alc/mixer.c index 2d804b1f..58192055 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -307,9 +307,9 @@ static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\ +static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\ { \ - ALuint i; \ + ALsizei i; \ for(i = 0;i < samples;i++) \ dst[i] = Sample_##T(src[i*srcstep]); \ } @@ -320,7 +320,7 @@ DECL_TEMPLATE(ALfloat) #undef DECL_TEMPLATE -static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples) +static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum FmtType srctype, ALsizei samples) { switch(srctype) { @@ -336,9 +336,9 @@ static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum Fm } } -static inline void SilenceSamples(ALfloat *dst, ALuint samples) +static inline void SilenceSamples(ALfloat *dst, ALsizei samples) { - ALuint i; + ALsizei i; for(i = 0;i < samples;i++) dst[i] = 0.0f; } @@ -346,9 +346,9 @@ static inline void SilenceSamples(ALfloat *dst, ALuint samples) static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter, ALfloat *restrict dst, const ALfloat *restrict src, - ALuint numsamples, enum ActiveFilters type) + ALsizei numsamples, enum ActiveFilters type) { - ALuint i; + ALsizei i; switch(type) { case AF_None: @@ -369,7 +369,7 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter for(i = 0;i < numsamples;) { ALfloat temp[256]; - ALuint todo = minu(256, numsamples-i); + ALsizei todo = mini(256, numsamples-i); ALfilterState_process(lpfilter, temp, src+i, todo); ALfilterState_process(hpfilter, dst+i, temp, todo); @@ -381,21 +381,22 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter } -ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) +ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { ResamplerFunc Resample; ALbufferlistitem *BufferListItem; ALuint DataPosInt, DataPosFrac; ALboolean Looping; - ALuint increment; + ALint increment; ALenum State; - ALuint OutPos; - ALuint NumChannels; - ALuint SampleSize; + ALsizei OutPos; + ALsizei NumChannels; + ALsizei SampleSize; ALint64 DataSize64; - ALuint Counter; - ALuint IrSize; - ALuint chan, send, j; + ALsizei Counter; + ALsizei IrSize; + ALsizei chan, j; + ALuint send; /* Get source info */ State = AL_PLAYING; /* Only called while playing. */ @@ -415,7 +416,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam Counter = voice->Moving ? SamplesToDo : 0; OutPos = 0; do { - ALuint SrcBufferSize, DstBufferSize; + ALsizei SrcBufferSize, DstBufferSize; /* Figure out how many buffer samples will be needed */ DataSize64 = SamplesToDo-OutPos; @@ -424,7 +425,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam DataSize64 >>= FRACTIONBITS; DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES; - SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE); + SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); /* Figure out how many samples we can actually mix from this. */ DataSize64 = SrcBufferSize; @@ -432,8 +433,8 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; - DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment); - DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos)); + DstBufferSize = (ALsizei)((DataSize64+(increment-1)) / increment); + DstBufferSize = mini(DstBufferSize, (SamplesToDo-OutPos)); /* Some mixers like having a multiple of 4, so try to give that unless * this is the last update. */ @@ -444,7 +445,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { const ALfloat *ResampledData; ALfloat *SrcData = Device->SourceData; - ALuint SrcDataSize; + ALsizei SrcDataSize; /* Load the previous samples into the source data first. */ memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat)); @@ -454,7 +455,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { const ALbuffer *ALBuffer = BufferListItem->buffer; const ALubyte *Data = ALBuffer->data; - ALuint DataSize; + ALsizei DataSize; /* Offset buffer data to current channel */ Data += chan*SampleSize; @@ -478,13 +479,12 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } else { - ALuint LoopStart = ALBuffer->LoopStart; - ALuint LoopEnd = ALBuffer->LoopEnd; + ALsizei LoopStart = ALBuffer->LoopStart; + ALsizei LoopEnd = ALBuffer->LoopEnd; /* Load what's left of this loop iteration, then load * repeats of the loop section */ - DataSize = LoopEnd - DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt); LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); @@ -493,7 +493,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam DataSize = LoopEnd-LoopStart; while(SrcBufferSize > SrcDataSize) { - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + DataSize = mini(SrcBufferSize - SrcDataSize, DataSize); LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); @@ -645,22 +645,22 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos += DstBufferSize; voice->Offset += DstBufferSize; - Counter = maxu(DstBufferSize, Counter) - DstBufferSize; + Counter = maxi(DstBufferSize, Counter) - DstBufferSize; /* Handle looping sources */ while(1) { const ALbuffer *ALBuffer; - ALuint DataSize = 0; - ALuint LoopStart = 0; - ALuint LoopEnd = 0; + ALsizei DataSize = 0; + ALsizei LoopStart = 0; + ALsizei LoopEnd = 0; if((ALBuffer=BufferListItem->buffer) != NULL) { DataSize = ALBuffer->SampleLen; LoopStart = ALBuffer->LoopStart; LoopEnd = ALBuffer->LoopEnd; - if(LoopEnd > DataPosInt) + if((ALuint)LoopEnd > DataPosInt) break; } @@ -671,7 +671,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam break; } - if(DataSize > DataPosInt) + if((ALuint)DataSize > DataPosInt) break; if(!(BufferListItem=BufferListItem->next)) diff --git a/Alc/panning.c b/Alc/panning.c index e1ad6d0b..a0576e0d 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -209,9 +209,9 @@ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat } -void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - ALuint i; + ALsizei i; for(i = 0;i < numchans;i++) { @@ -224,10 +224,10 @@ void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALf gains[i] = 0.0f; } -void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALfloat gain = 0.0f; - ALuint i; + ALsizei i; for(i = 0;i < numchans;i++) { @@ -239,9 +239,9 @@ void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfl gains[i] = 0.0f; } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - ALuint i, j; + ALsizei i, j; for(i = 0;i < numchans;i++) { @@ -254,9 +254,9 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALu gains[i] = 0.0f; } -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - ALuint i; + ALsizei i; for(i = 0;i < numchans;i++) gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain; @@ -264,9 +264,9 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons gains[i] = 0.0f; } -void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - ALuint i, j; + ALsizei i, j; for(i = 0;i < numchans;i++) { @@ -279,9 +279,9 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, gains[i] = 0.0f; } -void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - ALuint i; + ALsizei i; for(i = 0;i < numchans;i++) gains[i] = chanmap[i].Scale * mtx[chanmap[i].Index] * ingain; @@ -342,13 +342,13 @@ typedef struct ChannelMap { } ChannelMap; static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs, - const ChannelMap *chanmap, size_t count, ALuint *outcount, + const ChannelMap *chanmap, size_t count, ALsizei *outcount, ALboolean isfuma) { const ALsizei *acnmap = isfuma ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = isfuma ? FuMa2N3DScale : UnitScale; size_t j, k; - ALuint i; + ALsizei i; for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++) { diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 70fcac5c..40ff1393 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -18,7 +18,7 @@ typedef struct ALeffectState { const struct ALeffectStateVtable *vtbl; ALfloat (*OutBuffer)[BUFFERSIZE]; - ALuint OutChannels; + ALsizei OutChannels; } ALeffectState; void ALeffectState_Construct(ALeffectState *state); @@ -120,7 +120,7 @@ typedef struct ALeffectslot { /* Self ID */ ALuint id; - ALuint NumChannels; + ALsizei NumChannels; BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS]; /* Wet buffer configuration is ACN channel order with N3D scaling: * * Channel 0 is the unattenuated mono signal. diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index e99af050..062be452 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -36,9 +36,9 @@ enum UserFmtChannels { UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */ }; -ALuint BytesFromUserFmt(enum UserFmtType type); -ALuint ChannelsFromUserFmt(enum UserFmtChannels chans); -inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type) +ALsizei BytesFromUserFmt(enum UserFmtType type); +ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans); +inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type) { return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type); } @@ -63,9 +63,9 @@ enum FmtChannels { }; #define MAX_INPUT_CHANNELS (8) -ALuint BytesFromFmt(enum FmtType type); -ALuint ChannelsFromFmt(enum FmtChannels chans); -inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) +ALsizei BytesFromFmt(enum FmtType type); +ALsizei ChannelsFromFmt(enum FmtChannels chans); +inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) { return ChannelsFromFmt(chans) * BytesFromFmt(type); } @@ -87,8 +87,8 @@ typedef struct ALbuffer { ALsizei OriginalSize; ALsizei OriginalAlign; - ALsizei LoopStart; - ALsizei LoopEnd; + ALsizei LoopStart; + ALsizei LoopEnd; ATOMIC(ALsizei) UnpackAlign; ATOMIC(ALsizei) PackAlign; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fca98be9..fd90a49a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -499,9 +499,9 @@ enum DevFmtChannels { }; #define MAX_OUTPUT_CHANNELS (16) -ALuint BytesFromDevFmt(enum DevFmtType type); -ALuint ChannelsFromDevFmt(enum DevFmtChannels chans); -inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type) +ALsizei BytesFromDevFmt(enum DevFmtType type); +ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans); +inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type) { return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); } @@ -682,20 +682,20 @@ struct ALCdevice_struct * first-order, 9 for second-order, etc). If the count is 0, Ambi.Map * is used instead to map each output to a coefficient index. */ - ALuint CoeffCount; + ALsizei CoeffCount; ALfloat (*Buffer)[BUFFERSIZE]; - ALuint NumChannels; + ALsizei NumChannels; } Dry; /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ struct { AmbiConfig Ambi; /* Will only be 4 or 0. */ - ALuint CoeffCount; + ALsizei CoeffCount; ALfloat (*Buffer)[BUFFERSIZE]; - ALuint NumChannels; + ALsizei NumChannels; } FOAOut; /* "Real" output, which will be written to the device buffer. May alias the @@ -705,7 +705,7 @@ struct ALCdevice_struct enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; - ALuint NumChannels; + ALsizei NumChannels; } RealOut; /* Running count of the mixer invocations, in 31.1 fixed point. This diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 8b793102..4f04efe2 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -96,12 +96,12 @@ typedef struct ALvoice { struct { ALfloat (*Buffer)[BUFFERSIZE]; - ALuint Channels; + ALsizei Channels; } DirectOut; struct { ALfloat (*Buffer)[BUFFERSIZE]; - ALuint Channels; + ALsizei Channels; } SendOut[MAX_SENDS]; struct { @@ -194,8 +194,8 @@ typedef struct ALsource { ATOMIC(ALboolean) looping; /** Current buffer sample info. */ - ALuint NumChannels; - ALuint SampleSize; + ALsizei NumChannels; + ALsizei SampleSize; ALenum NeedsUpdate; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 21b787d2..dba167d4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -313,8 +313,8 @@ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat else \ ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \ } while (0) -void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputePanningGains @@ -328,8 +328,8 @@ void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfl else \ ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \ } while (0) -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeFirstOrderGains @@ -344,11 +344,11 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons else \ ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \ } while (0) -void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo); +ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALsizei SamplesToDo); ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); /* Caller must lock the device. */ diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 24470d64..45a8cb5b 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -42,8 +42,8 @@ extern inline void LockBuffersWrite(ALCdevice *device); extern inline void UnlockBuffersWrite(ALCdevice *device); 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); +extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); +extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); static ALboolean IsValidType(ALenum type); static ALboolean IsValidChannels(ALenum channels); @@ -145,7 +145,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi ALCcontext *context; ALbuffer *albuf; ALenum newformat = AL_NONE; - ALuint framesize; + ALsizei framesize; ALsizei align; ALenum err; @@ -293,9 +293,9 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALCdevice *device; ALCcontext *context; ALbuffer *albuf; - ALuint byte_align; - ALuint channels; - ALuint bytes; + ALsizei byte_align; + ALsizei channels; + ALsizei bytes; ALsizei align; context = GetContextRef(); @@ -1074,7 +1074,7 @@ ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, } -ALuint BytesFromUserFmt(enum UserFmtType type) +ALsizei BytesFromUserFmt(enum UserFmtType type) { switch(type) { @@ -1095,7 +1095,7 @@ ALuint BytesFromUserFmt(enum UserFmtType type) } return 0; } -ALuint ChannelsFromUserFmt(enum UserFmtChannels chans) +ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) { switch(chans) { @@ -1190,7 +1190,7 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, return AL_FALSE; } -ALuint BytesFromFmt(enum FmtType type) +ALsizei BytesFromFmt(enum FmtType type) { switch(type) { @@ -1200,7 +1200,7 @@ ALuint BytesFromFmt(enum FmtType type) } return 0; } -ALuint ChannelsFromFmt(enum FmtChannels chans) +ALsizei ChannelsFromFmt(enum FmtChannels chans) { switch(chans) { -- cgit v1.2.3 From e8ac0e5bfd659a88538abed66e13e52b40f3ad12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jan 2017 07:19:43 -0800 Subject: Replace some ALvoid with void --- Alc/ALu.c | 4 ++-- Alc/mixer.c | 2 +- OpenAL32/Include/alu.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9b03b85a..67f61f07 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1392,7 +1392,7 @@ DECL_TEMPLATE(ALbyte, aluF2B) #undef DECL_TEMPLATE -ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) +void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALuint SamplesToDo; ALvoice *voice, *voice_end; @@ -1599,7 +1599,7 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } -ALvoid aluHandleDisconnect(ALCdevice *device) +void aluHandleDisconnect(ALCdevice *device) { ALCcontext *Context; diff --git a/Alc/mixer.c b/Alc/mixer.c index 58192055..0ee1edd6 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -381,7 +381,7 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter } -ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) +void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { ResamplerFunc Resample; ALbufferlistitem *BufferListItem; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index dba167d4..642fb944 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -348,11 +348,11 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALsizei SamplesToDo); +void MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo); -ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); +void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); /* Caller must lock the device. */ -ALvoid aluHandleDisconnect(ALCdevice *device); +void aluHandleDisconnect(ALCdevice *device); extern ALfloat ConeScale; extern ALfloat ZScale; -- cgit v1.2.3 From aa56af1ecbf30b9f41d1cf9b0ede1c50f5757639 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jan 2017 19:16:24 -0800 Subject: Move the B-Format HRTF virtual speaker stuff to InitHrtfPanning This keeps the decoder matrices and coefficient mapping together for if it changes in the future. --- Alc/hrtf.c | 75 ++++++----------------------------------------- Alc/hrtf.h | 27 ++++++++--------- Alc/panning.c | 62 ++++++++++++++++++++++++++++++++++----- OpenAL32/Include/alMain.h | 32 ++++++++++++-------- 4 files changed, 96 insertions(+), 100 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3fbb2eb1..d79168e1 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -136,82 +136,28 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALsizei *AmbiMap) +ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount) { -#define HRTF_AMBI_CHAN_COUNT 14 - /* NOTE: azimuth goes clockwise. */ - static const struct { - ALfloat elevation; - ALfloat azimuth; - } Ambi3DPoints[HRTF_AMBI_CHAN_COUNT] = { - { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, - { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, - { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, - }; - static const ALfloat Ambi3DMatrixFOA[HRTF_AMBI_CHAN_COUNT][2][MAX_AMBI_COEFFS] = { - { { 1.88982237e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f } }, - { { 1.88982237e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f } }, - { { 1.88982237e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f } } - }, Ambi3DMatrixHOA[HRTF_AMBI_CHAN_COUNT][2][MAX_AMBI_COEFFS] = { - { { 1.43315266e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, - { { 1.39644596e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, - { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, - { { 1.39644596e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, - { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - }; - const ALfloat (*Ambi3DMatrix)[2][MAX_AMBI_COEFFS] = AmbiMap ? Ambi3DMatrixHOA : Ambi3DMatrixFOA; - /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the * tail generated by the filter. */ #define NUM_BANDS 2 BandSplitter splitter; - ALsizei lidx[HRTF_AMBI_CHAN_COUNT], ridx[HRTF_AMBI_CHAN_COUNT]; + ALsizei lidx[HRTF_AMBI_MAX_CHANNELS], ridx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; ALsizei i, j, c, b; - for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) + for(c = 0;c < AmbiCount;c++) { ALuint evidx, azidx; ALuint evoffset; ALuint azcount; /* Calculate elevation index. */ - evidx = (ALsizei)floorf((F_PI_2 + Ambi3DPoints[c].elevation) * + evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) * (Hrtf->evCount-1)/F_PI + 0.5f); evidx = mini(evidx, Hrtf->evCount-1); @@ -219,7 +165,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - azidx = (ALsizei)floorf((F_TAU+Ambi3DPoints[c].azimuth) * + azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) * azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ @@ -231,7 +177,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] memset(temps, 0, sizeof(temps)); bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); - for(c = 0;c < HRTF_AMBI_CHAN_COUNT;c++) + for(c = 0;c < AmbiCount;c++) { const ALshort *fir; ALsizei delay; @@ -256,12 +202,11 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] delay = Hrtf->delays[lidx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { - const ALsizei a = AmbiMap ? AmbiMap[i] : i; for(b = 0;b < NUM_BANDS;b++) { ALsizei k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][0] += temps[b][k++] * Ambi3DMatrix[c][b][a]; + coeffs[i][j][0] += temps[b][k++] * AmbiMatrix[c][b][i]; } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -286,21 +231,19 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] delay = Hrtf->delays[ridx[c]] - min_delay; for(i = 0;i < NumChannels;++i) { - const ALsizei a = AmbiMap ? AmbiMap[i] : i; for(b = 0;b < NUM_BANDS;b++) { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][1] += temps[b][k++] * Ambi3DMatrix[c][b][a]; + coeffs[i][j][1] += temps[b][k++] * AmbiMatrix[c][b][i]; } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); } TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); -#undef NUM_BANDS return max_length; -#undef HRTF_AMBI_CHAN_COUNT +#undef NUM_BANDS } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 5ac4a03d..83cc64d1 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -4,6 +4,7 @@ #include "AL/al.h" #include "AL/alc.h" +#include "alMain.h" #include "alstring.h" @@ -21,20 +22,15 @@ struct Hrtf { struct Hrtf *next; }; -typedef struct HrtfEntry { - al_string name; - - const struct Hrtf *hrtf; -} HrtfEntry; -TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry) - -#define HRIR_BITS (7) -#define HRIR_LENGTH (1<Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); + static_assert(9 <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); + static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = ambi_map[i]; + device->Dry.Ambi.Map[i].Index = i; } device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -794,7 +841,8 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs)); device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle, - device->Hrtf.Coeffs, device->Dry.NumChannels, hoa_mode ? ambi_map : NULL + device->Hrtf.Coeffs, device->Dry.NumChannels, + AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints) ); /* Round up to the nearest multiple of 8 */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fd90a49a..1fb1dcf5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -20,16 +20,6 @@ #include "AL/alc.h" #include "AL/alext.h" - -#if defined(_WIN64) -#define SZFMT "%I64u" -#elif defined(_WIN32) -#define SZFMT "%u" -#else -#define SZFMT "%zu" -#endif - - #include "static_assert.h" #include "align.h" #include "atomic.h" @@ -39,8 +29,6 @@ #include "almalloc.h" #include "threads.h" -#include "hrtf.h" - #ifndef ALC_SOFT_device_clock #define ALC_SOFT_device_clock 1 typedef int64_t ALCint64SOFT; @@ -128,6 +116,15 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif +#if defined(_WIN64) +#define SZFMT "%I64u" +#elif defined(_WIN32) +#define SZFMT "%u" +#else +#define SZFMT "%zu" +#endif + + #ifdef __GNUC__ /* Because of a long-standing deficiency in C, you're not allowed to implicitly * cast a pointer-to-type-array to a pointer-to-const-type-array. For example, @@ -577,6 +574,10 @@ typedef union AmbiConfig { #define HRTF_HISTORY_LENGTH (1< Date: Sat, 21 Jan 2017 11:05:05 -0800 Subject: Update the default basic B-Format decoders This also converts them to ACN/N3D format. --- Alc/panning.c | 83 ++++++++++++++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 8073bb20..ba7a38db 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -342,11 +342,8 @@ typedef struct ChannelMap { } ChannelMap; static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs, - const ChannelMap *chanmap, size_t count, ALsizei *outcount, - ALboolean isfuma) + const ChannelMap *chanmap, size_t count, ALsizei *outcount) { - const ALsizei *acnmap = isfuma ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = isfuma ? FuMa2N3DScale : UnitScale; size_t j, k; ALsizei i; @@ -365,10 +362,7 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff continue; for(k = 0;k < MAX_AMBI_COEFFS;++k) - { - ALsizei acn = acnmap[k]; - ambicoeffs[i][acn] = chanmap[j].Config[k] / n3dscale[acn]; - } + ambicoeffs[i][k] = chanmap[j].Config[k]; break; } if(j == count) @@ -468,47 +462,42 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe } -/* NOTE: These decoder coefficients are using FuMa channel ordering and - * normalization, since that's what was produced by the Ambisonic Decoder - * Toolbox. SetChannelMap will convert them to N3D. - */ static const ChannelMap MonoCfg[1] = { - { FrontCenter, { 1.414213562f } }, + { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { - { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, - { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 0.0f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 0.0f } }, }, QuadCfg[4] = { - { FrontLeft, { 0.353553f, 0.306186f, 0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.125000f } }, - { FrontRight, { 0.353553f, 0.306186f, -0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.125000f } }, - { BackLeft, { 0.353553f, -0.306186f, 0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.125000f } }, - { BackRight, { 0.353553f, -0.306186f, -0.306186f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.125000f } }, + { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, + { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } }, + { BackRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } }, }, X51SideCfg[5] = { - { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, - { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, - { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, - { SideLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, - { SideRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, + { SideLeft, { 3.33001372e-1f, 1.89085671e-1f, 0.0f, -2.00041334e-1f, -2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } }, + { FrontLeft, { 1.47751298e-1f, 1.28994110e-1f, 0.0f, 1.15190495e-1f, 7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } }, + { FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } }, + { FrontRight, { 1.47751298e-1f, -1.28994110e-1f, 0.0f, 1.15190495e-1f, -7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } }, + { SideRight, { 3.33001372e-1f, -1.89085671e-1f, 0.0f, -2.00041334e-1f, 2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } }, }, X51RearCfg[5] = { - { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } }, - { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } }, - { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } }, - { BackLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } }, - { BackRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } }, + { BackLeft, { 3.33001372e-1f, 1.89085671e-1f, 0.0f, -2.00041334e-1f, -2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } }, + { FrontLeft, { 1.47751298e-1f, 1.28994110e-1f, 0.0f, 1.15190495e-1f, 7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } }, + { FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } }, + { FrontRight, { 1.47751298e-1f, -1.28994110e-1f, 0.0f, 1.15190495e-1f, -7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } }, + { BackRight, { 3.33001372e-1f, -1.89085671e-1f, 0.0f, -2.00041334e-1f, 2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } }, }, X61Cfg[6] = { - { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, - { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } }, - { SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } }, - { SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } }, -}, X71Cfg[7] = { - { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, - { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, - { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, - { BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } }, - { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, - { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, - { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, + { SideLeft, { 2.04462744e-1f, 2.17178497e-1f, 0.0f, -4.39990188e-2f, -2.60787329e-2f, 0.0f, 0.0f, 0.0f, -6.87238843e-2f } }, + { FrontLeft, { 1.18130342e-1f, 9.34633906e-2f, 0.0f, 1.08553749e-1f, 6.80658795e-2f, 0.0f, 0.0f, 0.0f, 1.08999485e-2f } }, + { FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } }, + { FrontRight, { 1.18130342e-1f, -9.34633906e-2f, 0.0f, 1.08553749e-1f, -6.80658795e-2f, 0.0f, 0.0f, 0.0f, 1.08999485e-2f } }, + { SideRight, { 2.04462744e-1f, -2.17178497e-1f, 0.0f, -4.39990188e-2f, 2.60787329e-2f, 0.0f, 0.0f, 0.0f, -6.87238843e-2f } }, + { BackCenter, { 2.50001688e-1f, 0.00000000e+0f, 0.0f, -2.50000094e-1f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 6.05133395e-2f } }, +}, X71Cfg[6] = { + { BackLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, -1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, 1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, 1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, + { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, }; static void InitPanning(ALCdevice *device) @@ -539,7 +528,7 @@ static void InitPanning(ALCdevice *device) case DevFmtQuad: count = COUNTOF(QuadCfg); chanmap = QuadCfg; - ambiscale = SECOND_ORDER_SCALE; + ambiscale = FIRST_ORDER_SCALE; coeffcount = 9; break; @@ -560,7 +549,7 @@ static void InitPanning(ALCdevice *device) case DevFmtX61: count = COUNTOF(X61Cfg); chanmap = X61Cfg; - ambiscale = THIRD_ORDER_SCALE; + ambiscale = SECOND_ORDER_SCALE; coeffcount = 16; break; @@ -620,7 +609,7 @@ static void InitPanning(ALCdevice *device) else { SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, - chanmap, count, &device->Dry.NumChannels, AL_TRUE); + chanmap, count, &device->Dry.NumChannels); device->Dry.CoeffCount = coeffcount; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); @@ -681,7 +670,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A } SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, - conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE); + conf->NumSpeakers, &device->Dry.NumChannels); device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 : (conf->ChanMask > 0xf) ? 9 : 4; -- cgit v1.2.3 From 7025660e8be552a4784913e910b9bd65740c1427 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jan 2017 11:54:22 -0800 Subject: Use a flat sqrt(2) scale for non-directional ambient gains --- Alc/panning.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index ba7a38db..c263a20e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -214,12 +214,7 @@ void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL ALsizei i; for(i = 0;i < numchans;i++) - { - // The W coefficients are based on a mathematical average of the - // output. The square root of the base average provides for a more - // perceptual average volume, better suited to non-directional gains. - gains[i] = sqrtf(chancoeffs[i][0]) * ingain; - } + gains[i] = chancoeffs[i][0] * 1.414213562f * ingain; for(;i < MAX_OUTPUT_CHANNELS;i++) gains[i] = 0.0f; } @@ -465,8 +460,8 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint spe static const ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 0.0f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 0.0f } }, + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 0.00000000e+0f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 0.00000000e+0f } }, }, QuadCfg[4] = { { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, -- cgit v1.2.3 From f4d52f43d87c02769c7649b91ba4afc967e121d2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jan 2017 12:28:54 -0800 Subject: Fix coefficient counts for the built-in B-Format decoders --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index c263a20e..32227b04 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -524,7 +524,7 @@ static void InitPanning(ALCdevice *device) count = COUNTOF(QuadCfg); chanmap = QuadCfg; ambiscale = FIRST_ORDER_SCALE; - coeffcount = 9; + coeffcount = 4; break; case DevFmtX51: @@ -545,7 +545,7 @@ static void InitPanning(ALCdevice *device) count = COUNTOF(X61Cfg); chanmap = X61Cfg; ambiscale = SECOND_ORDER_SCALE; - coeffcount = 16; + coeffcount = 9; break; case DevFmtX71: -- cgit v1.2.3 From 1ebfce4cac35731f1df5702ce613eada81f6ffa5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Jan 2017 19:03:51 -0800 Subject: Improve the ambisonic upscaling methods This now takes advantage of the differences seen in generated decoder matrices for first-order compared to second- and third-order, such that with the appropriate frequency-dependent scaling applied to first-order content, the result is identical with a higher-order decoder matrix compared to a first- order matrix for the same layout. --- Alc/bformatdec.c | 216 +++++++++++++++++++++++++++++-------------------------- Alc/bformatdec.h | 18 +++++ Alc/panning.c | 69 ++++++++++-------- 3 files changed, 174 insertions(+), 129 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index f3cc476f..86300f7b 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -122,21 +122,6 @@ enum FreqBand { FB_Max }; -/* These points are in AL coordinates! */ -static const ALfloat Ambi2DPoints[4][3] = { - { -0.707106781f, 0.0f, -0.707106781f }, - { 0.707106781f, 0.0f, -0.707106781f }, - { -0.707106781f, 0.0f, 0.707106781f }, - { 0.707106781f, 0.0f, 0.707106781f }, -}; -static const ALfloat Ambi2DDecoder[4][FB_Max][MAX_AMBI_COEFFS] = { - { { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f }, { 0.25f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, - { { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f }, { 0.25f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } }, - { { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f }, { 0.25f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, - { { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f }, { 0.25f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } }, -}; -static ALfloat Ambi2DEncoderT[4][MAX_AMBI_COEFFS]; - /* These points are in AL coordinates! */ static const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, 0.577350269f, -0.577350269f }, @@ -158,7 +143,6 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, }; -static ALfloat Ambi3DEncoderT[8][MAX_AMBI_COEFFS]; static RowMixerFunc MixMatrixRow = MixRow_C; @@ -168,64 +152,14 @@ static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT; static void init_bformatdec(void) { - size_t i, j; - MixMatrixRow = SelectRowMixer(); - - for(i = 0;i < COUNTOF(Ambi3DPoints);i++) - CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoderT[i]); - - for(i = 0;i < COUNTOF(Ambi2DPoints);i++) - { - CalcDirectionCoeffs(Ambi2DPoints[i], 0.0f, Ambi2DEncoderT[i]); - - /* Remove the skipped height-related coefficients for 2D rendering. */ - Ambi2DEncoderT[i][2] = Ambi2DEncoderT[i][3]; - Ambi2DEncoderT[i][3] = Ambi2DEncoderT[i][4]; - Ambi2DEncoderT[i][4] = Ambi2DEncoderT[i][8]; - Ambi2DEncoderT[i][5] = Ambi2DEncoderT[i][9]; - Ambi2DEncoderT[i][6] = Ambi2DEncoderT[i][15]; - for(j = 7;j < MAX_AMBI_COEFFS;j++) - Ambi2DEncoderT[i][j] = 0.0f; - } -} - - -/* This typedef is needed for SAFE_CONST to work. */ -typedef ALfloat ALfloatMAX_AMBI_COEFFS[MAX_AMBI_COEFFS]; - -static void GenUpsamplerGains(const ALfloat (*restrict EncoderT)[MAX_AMBI_COEFFS], - const ALfloat (*restrict Decoder)[FB_Max][MAX_AMBI_COEFFS], - ALsizei InChannels, - ALfloat (*restrict OutGains)[MAX_OUTPUT_CHANNELS][FB_Max], - ALsizei OutChannels) -{ - ALsizei i, j, k; - - /* Combine the matrices that do the in->virt and virt->out conversions so - * we get a single in->out conversion. NOTE: the Encoder matrix and output - * are transposed, so the input channels line up with the rows and the - * output channels line up with the columns. - */ - for(i = 0;i < 4;i++) - { - for(j = 0;j < OutChannels;j++) - { - ALfloat hfgain=0.0f, lfgain=0.0f; - for(k = 0;k < InChannels;k++) - { - hfgain += Decoder[k][FB_HighFreq][i]*EncoderT[k][j]; - lfgain += Decoder[k][FB_LowFreq][i]*EncoderT[k][j]; - } - OutGains[i][j][FB_HighFreq] = hfgain; - OutGains[i][j][FB_LowFreq] = lfgain; - } - } } #define MAX_DELAY_LENGTH 128 +#define INVALID_UPSAMPLE_INDEX INT_MAX + /* NOTE: BandSplitter filters are unused with single-band decoding */ typedef struct BFormatDec { ALboolean Enabled[MAX_OUTPUT_CHANNELS]; @@ -250,10 +184,12 @@ typedef struct BFormatDec { } Delay[MAX_OUTPUT_CHANNELS]; struct { - BandSplitter XOver[4]; + ALsizei Index; - ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max]; - } UpSampler; + BandSplitter XOver; + + ALfloat Gains[FB_Max]; + } UpSampler[4]; ALsizei NumChannels; ALboolean DualBand; @@ -327,23 +263,41 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(conf->CoeffScale == ADS_FuMa) coeff_scale = FuMa2N3DScale; + memset(dec->UpSampler, 0, sizeof(dec->UpSampler)); ratio = 400.0f / (ALfloat)srate; for(i = 0;i < 4;i++) - bandsplit_init(&dec->UpSampler.XOver[i], ratio); - memset(dec->UpSampler.Gains, 0, sizeof(dec->UpSampler.Gains)); + bandsplit_init(&dec->UpSampler[i].XOver, ratio); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,Ambi3DEncoderT), - Ambi3DDecoder, COUNTOF(Ambi3DDecoder), - dec->UpSampler.Gains, dec->NumChannels); dec->Periphonic = AL_TRUE; + + dec->UpSampler[0].Index = 0; + dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD : + (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; + dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; + for(i = 1;i < 4;i++) + { + dec->UpSampler[i].Index = i; + dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD : + (dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f; + dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; + } } else { - GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,Ambi2DEncoderT), - Ambi2DDecoder, COUNTOF(Ambi2DDecoder), - dec->UpSampler.Gains, dec->NumChannels); dec->Periphonic = AL_FALSE; + + dec->UpSampler[0].Index = 0; + dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD : + (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f; + dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; + for(i = 1;i < 4;i++) + { + dec->UpSampler[i].Index = (i>2) ? i-1 : ((i==2) ? INVALID_UPSAMPLE_INDEX : i); + dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD : + (dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f; + dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; + } } maxdist = 0.0f; @@ -585,35 +539,53 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo) { - ALsizei i, j; + ALsizei i; - /* This up-sampler is very simplistic. It essentially decodes the first- - * order content to a square channel array (or cube if height is desired), - * then encodes those points onto the higher order soundfield. The decoder - * and encoder matrices have been combined to directly convert each input - * channel to the output, without the need for storing the virtual channel - * array. + /* This up-sampler leverages the differences observed in dual-band second- + * and third-order decoder matrices compared to first-order. For the same + * output channel configuration, the low-frequency matrix has identical + * coefficients in the shared input channels, while the high-frequency + * matrix has extra scalars applied to the W channel and X/Y/Z channels. + * Mixing the first-order content into the higher-order stream with the + * appropriate counter-scales applied to the HF response results in the + * subsequent higher-order decode generating the same response as a first- + * order decode. */ for(i = 0;i < InChannels;i++) { + ALsizei dst_chan = dec->UpSampler[i].Index; + if(dst_chan == INVALID_UPSAMPLE_INDEX) + continue; + /* First, split the first-order components into low and high frequency * bands. */ - bandsplit_process(&dec->UpSampler.XOver[i], + bandsplit_process(&dec->UpSampler[i].XOver, dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq], InSamples[i], SamplesToDo ); /* Now write each band to the output. */ - for(j = 0;j < dec->NumChannels;j++) - MixMatrixRow(OutBuffer[j], dec->UpSampler.Gains[i][j], - SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0, - SamplesToDo - ); + MixMatrixRow(OutBuffer[dst_chan], dec->UpSampler[i].Gains, + SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0, + SamplesToDo + ); } } +static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) +{ + ALsizei i; + for(i = 0;i < numchans;i++) + { + if(chans[i].Index == acn) + return i; + } + return INVALID_UPSAMPLE_INDEX; +} +#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) + typedef struct AmbiUpsampler { alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE]; @@ -635,21 +607,65 @@ void ambiup_free(struct AmbiUpsampler *ambiup) void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { - ALfloat gains[8][MAX_OUTPUT_CHANNELS]; ALfloat ratio; - ALuint i; + size_t i; ratio = 400.0f / (ALfloat)device->Frequency; for(i = 0;i < 4;i++) bandsplit_init(&ambiup->XOver[i], ratio); - for(i = 0;i < COUNTOF(Ambi3DEncoderT);i++) - ComputePanningGains(device->Dry, Ambi3DEncoderT[i], 1.0f, gains[i]); - memset(ambiup->Gains, 0, sizeof(ambiup->Gains)); - GenUpsamplerGains(SAFE_CONST(ALfloatMAX_AMBI_COEFFS*,gains), - Ambi3DDecoder, COUNTOF(Ambi3DDecoder), - ambiup->Gains, device->Dry.NumChannels); + if(device->Dry.CoeffCount > 0) + { + ALfloat encgains[8][MAX_OUTPUT_CHANNELS]; + ALsizei j; + size_t k; + + for(i = 0;i < COUNTOF(Ambi3DPoints);i++) + { + ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; + CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs); + ComputePanningGains(device->Dry, coeffs, 1.0f, encgains[i]); + } + + /* Combine the matrices that do the in->virt and virt->out conversions + * so we get a single in->out conversion. NOTE: the Encoder matrix + * (encgains) and output are transposed, so the input channels line up + * with the rows and the output channels line up with the columns. + */ + for(i = 0;i < 4;i++) + { + for(j = 0;j < device->Dry.NumChannels;j++) + { + ALfloat hfgain=0.0f, lfgain=0.0f; + for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) + { + hfgain += Ambi3DDecoder[k][FB_HighFreq][i]*encgains[k][j]; + lfgain += Ambi3DDecoder[k][FB_LowFreq][i]*encgains[k][j]; + } + ambiup->Gains[i][j][FB_HighFreq] = hfgain; + ambiup->Gains[i][j][FB_LowFreq] = lfgain; + } + } + } + else + { + /* Assumes full 3D/periphonic on the input and output mixes! */ + ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE3D_THIRD : + (device->Dry.NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; + ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE3D_THIRD : + (device->Dry.NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f; + for(i = 0;i < 4;i++) + { + ALsizei index = GetChannelForACN(device->Dry, i); + if(index != INVALID_UPSAMPLE_INDEX) + { + ALfloat scale = device->Dry.Ambi.Map[index].Scale; + ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale); + ambiup->Gains[i][index][FB_LowFreq] = scale; + } + } + } } void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo) diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 3f240e54..7024b003 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -3,6 +3,24 @@ #include "alMain.h" + +/* These are the necessary scales for first-order HF responses to play over + * higher-order 2D (non-periphonic) decoders. + */ +#define W_SCALE2D_SECOND 1.224744871f /* sqrt(1.5) */ +#define XYZ_SCALE2D_SECOND 1.0f +#define W_SCALE2D_THIRD 1.414213562f /* sqrt(2) */ +#define XYZ_SCALE2D_THIRD 1.082392196f + +/* These are the necessary scales for first-order HF responses to play over + * higher-order 3D (periphonic) decoders. + */ +#define W_SCALE3D_SECOND 1.341640787f /* sqrt(1.8) */ +#define XYZ_SCALE3D_SECOND 1.0f +#define W_SCALE3D_THIRD 1.695486018f +#define XYZ_SCALE3D_THIRD 1.136697713f + + struct AmbDecConf; struct BFormatDec; struct AmbiUpsampler; diff --git a/Alc/panning.c b/Alc/panning.c index 32227b04..9b6f9b44 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -39,12 +39,6 @@ extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -#define ZERO_ORDER_SCALE 0.0f -#define FIRST_ORDER_SCALE 1.0f -#define SECOND_ORDER_SCALE (1.0f / 1.22474f) -#define THIRD_ORDER_SCALE (1.0f / 1.30657f) - - static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { 0, /* W */ 3, /* X */ @@ -499,59 +493,50 @@ static void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; ALsizei coeffcount = 0; - ALfloat ambiscale; ALsizei count = 0; ALsizei i, j; - ambiscale = 1.0f; switch(device->FmtChans) { case DevFmtMono: count = COUNTOF(MonoCfg); chanmap = MonoCfg; - ambiscale = ZERO_ORDER_SCALE; coeffcount = 1; break; case DevFmtStereo: count = COUNTOF(StereoCfg); chanmap = StereoCfg; - ambiscale = FIRST_ORDER_SCALE; coeffcount = 4; break; case DevFmtQuad: count = COUNTOF(QuadCfg); chanmap = QuadCfg; - ambiscale = FIRST_ORDER_SCALE; coeffcount = 4; break; case DevFmtX51: count = COUNTOF(X51SideCfg); chanmap = X51SideCfg; - ambiscale = SECOND_ORDER_SCALE; coeffcount = 9; break; case DevFmtX51Rear: count = COUNTOF(X51RearCfg); chanmap = X51RearCfg; - ambiscale = SECOND_ORDER_SCALE; coeffcount = 9; break; case DevFmtX61: count = COUNTOF(X61Cfg); chanmap = X61Cfg; - ambiscale = SECOND_ORDER_SCALE; coeffcount = 9; break; case DevFmtX71: count = COUNTOF(X71Cfg); chanmap = X71Cfg; - ambiscale = THIRD_ORDER_SCALE; coeffcount = 16; break; @@ -603,16 +588,23 @@ static void InitPanning(ALCdevice *device) } else { + ALfloat w_scale, xyz_scale; + SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap, count, &device->Dry.NumChannels); device->Dry.CoeffCount = coeffcount; + w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE2D_THIRD : + (device->Dry.CoeffCount > 4) ? W_SCALE2D_SECOND : 1.0f; + xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE2D_THIRD : + (device->Dry.CoeffCount > 4) ? XYZ_SCALE2D_SECOND : 1.0f; + memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++) + for(i = 0;i < device->Dry.NumChannels;i++) { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; for(j = 1;j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale; + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; } @@ -622,21 +614,40 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = UnitScale; - ALfloat ambiscale = 1.0f; + ALfloat w_scale = 1.0f; + ALfloat xyz_scale = 1.0f; ALsizei i, j; if(conf->FreqBands != 1) ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n", conf->XOverFreq); - if(conf->ChanMask > 0x1ff) - ambiscale = THIRD_ORDER_SCALE; - else if(conf->ChanMask > 0xf) - ambiscale = SECOND_ORDER_SCALE; - else if(conf->ChanMask > 0x1) - ambiscale = FIRST_ORDER_SCALE; + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + { + if(conf->ChanMask > 0x1ff) + { + w_scale = W_SCALE3D_THIRD; + xyz_scale = XYZ_SCALE3D_THIRD; + } + else if(conf->ChanMask > 0xf) + { + w_scale = W_SCALE3D_SECOND; + xyz_scale = XYZ_SCALE3D_SECOND; + } + } else - ambiscale = 0.0f; + { + if(conf->ChanMask > 0x1ff) + { + w_scale = W_SCALE2D_THIRD; + xyz_scale = XYZ_SCALE2D_THIRD; + } + else if(conf->ChanMask > 0xf) + { + w_scale = W_SCALE2D_SECOND; + xyz_scale = XYZ_SCALE2D_SECOND; + } + } if(conf->CoeffScale == ADS_SN3D) coeff_scale = SN3D2N3DScale; @@ -670,11 +681,11 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A (conf->ChanMask > 0xf) ? 9 : 4; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++) + for(i = 0;i < device->Dry.NumChannels;i++) { - device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0]; + device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0] * w_scale; for(j = 1;j < 4;j++) - device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale; + device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; } -- cgit v1.2.3 From f0c8b7f255b17a2fcfcf622a78794cde07f033cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Jan 2017 14:30:14 -0800 Subject: Get the JavaVM handle on Android targets --- Alc/ALc.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/compat.h | 8 ++++++++ 2 files changed, 72 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 80378d91..91ff79af 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1166,6 +1166,70 @@ static void alc_initconfig(void) } #define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) +#ifdef __ANDROID__ +#include + +static JavaVM *gJavaVM; +static pthread_key_t gJVMThreadKey; + +static void CleanupJNIEnv(void* UNUSED(ptr)) +{ + JCALL0(gJavaVM,DetachCurrentThread)(); +} + +void *Android_GetJNIEnv(void) +{ + /* http://developer.android.com/guide/practices/jni.html + * + * All threads are Linux threads, scheduled by the kernel. They're usually + * started from managed code (using Thread.start), but they can also be + * created elsewhere and then attached to the JavaVM. For example, a thread + * started with pthread_create can be attached with the JNI + * AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a + * thread is attached, it has no JNIEnv, and cannot make JNI calls. + * Attaching a natively-created thread causes a java.lang.Thread object to + * be constructed and added to the "main" ThreadGroup, making it visible to + * the debugger. Calling AttachCurrentThread on an already-attached thread + * is a no-op. + */ + JNIEnv *env = pthread_getspecific(gJVMThreadKey); + if(!env) + { + int status = JCALL(gJavaVM,AttachCurrentThread)(&env, NULL); + if(status < 0) + { + ERR("Failed to attach current thread\n"); + return NULL; + } + pthread_setspecific(gJVMThreadKey, env); + } + return env; +} + +/* Automatically called by JNI. */ +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void* UNUSED(reserved)) +{ + void *env; + int err; + + gJavaVM = jvm; + if(JCALL(gJavaVM,GetEnv)(&env, JNI_VERSION_1_4) != JNI_OK) + { + ERR("Failed to get JNIEnv with JNI_VERSION_1_4\n"); + return JNI_ERR; + } + + /* Create gJVMThreadKey so we can keep track of the JNIEnv assigned to each + * thread. The JNIEnv *must* be detached before the thread is destroyed. + */ + if((err=pthread_key_create(&gJVMThreadKey, CleanupJNIEnv)) != 0) + ERR("pthread_key_create failed: %d\n", err); + pthread_setspecific(gJVMThreadKey, env); + return JNI_VERSION_1_4; +} + +#endif + /************************************************ * Library deinitialization diff --git a/Alc/compat.h b/Alc/compat.h index 114fc655..247ed05b 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -46,4 +46,12 @@ void CloseLib(void *handle); void *GetSymbol(void *handle, const char *name); #endif +#ifdef __ANDROID__ +#define JCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS +#define JCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS + +/** Returns a JNIEnv*. */ +void *Android_GetJNIEnv(void); +#endif + #endif /* AL_COMPAT_H */ -- cgit v1.2.3 From 3ba03c5a29bcebb1866f36555957c3c293a99962 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Jan 2017 18:05:34 -0800 Subject: Also log to __android_log_print on Android --- CMakeLists.txt | 7 +++++++ OpenAL32/Include/alMain.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e608146..690ec37a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,13 @@ ELSE() ENDIF() UNSET(OLD_REQUIRED_LIBRARIES) +# Include liblog for Android logging +CHECK_LIBRARY_EXISTS(log __android_log_print "" HAVE_LIBLOG) +IF(HAVE_LIBLOG) + SET(EXTRA_LIBS log ${EXTRA_LIBS}) + SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) +ENDIF() + # Check if we have C99 variable length arrays CHECK_C_SOURCE_COMPILES( "int main(int argc, char *argv[]) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1fb1dcf5..988c7d31 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -914,6 +914,13 @@ void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FOR #define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) #endif +#ifdef __ANDROID__ +#include +#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__) +#else +#define LOG_ANDROID(T, MSG, ...) ((void)0) +#endif + enum LogLevel { NoLog, LogError, @@ -926,21 +933,25 @@ extern enum LogLevel LogLevel; #define TRACEREF(...) do { \ if(LogLevel >= LogRef) \ AL_PRINT("(--)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_VERBOSE, __VA_ARGS__); \ } while(0) #define TRACE(...) do { \ if(LogLevel >= LogTrace) \ AL_PRINT("(II)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ } while(0) #define WARN(...) do { \ if(LogLevel >= LogWarning) \ AL_PRINT("(WW)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ } while(0) #define ERR(...) do { \ if(LogLevel >= LogError) \ AL_PRINT("(EE)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) -- cgit v1.2.3 From 67ffdf7a78ae3e48b1fbdd866ad7c2add7e5b6fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Jan 2017 18:23:29 -0800 Subject: Try to use the system sample rate with Android --- Alc/backends/opensl.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 0796c49a..32f6fa7d 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -22,9 +22,11 @@ #include "config.h" #include +#include #include "alMain.h" #include "alu.h" +#include "compat.h" #include "threads.h" #include @@ -231,16 +233,64 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) SLDataFormat_PCM format_pcm; SLDataSource audioSrc; SLDataSink audioSnk; + ALuint sampleRate; SLInterfaceID id; - SLboolean req; SLresult result; + SLboolean req; + if((Device->Flags&DEVICE_FREQUENCY_REQUEST)) + sampleRate = Device->Frequency; + else + { + JNIEnv *env = Android_GetJNIEnv(); + + /* Get necessary stuff for using java.lang.Integer, + * android.content.Context, and android.media.AudioManager. + */ + jclass int_cls = JCALL(env,FindClass)("java/lang/Integer"); + jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, + "parseInt", "(Ljava/lang/String;)I" + ); + + jclass ctx_cls = (*env)->FindClass(env, "android/content/Context"); + jfieldID ctx_audsvc = (*env)->GetStaticFieldID(env, ctx_cls, + "AUDIO_SERVICE", "Ljava/lang/String;" + ); + jmethodID ctx_getSysSvc = (*env)->GetMethodID(env, ctx_cls, + "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" + ); + + jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); + jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, + "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" + ); + jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, + "getProperty", "(Ljava/lang/String;)Ljava/lang/Object;" + ); + + /* Now make the calls. */ + //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); + jobject audMgr = JCALL(env,CallStaticObjectMethod)(ctx_cls, ctx_getSysSvc, + JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc) + ); + + //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, + JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate) + ); + + //int sampleRate = Integer.parseInt(srateStr); + sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); + + if(!sampleRate) sampleRate = Device->Frequency; + else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); + } - Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency; - Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2; - Device->NumUpdates = 2; - - Device->Frequency = 44100; + if(sampleRate != Device->Frequency) + { + Device->NumUpdates = Device->NumUpdates * sampleRate / Device->Frequency; + Device->Frequency = sampleRate; + } Device->FmtChans = DevFmtStereo; Device->FmtType = DevFmtShort; -- cgit v1.2.3 From 19e96c6fefa3a6e946c5f82ee8311917caeb6545 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jan 2017 01:46:44 -0800 Subject: Round and clamp the scaled update count with opensl --- Alc/backends/opensl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 32f6fa7d..84e73f7b 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -282,13 +282,16 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) //int sampleRate = Integer.parseInt(srateStr); sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); + TRACE("Got system sample rate %uhz\n", sampleRate); if(!sampleRate) sampleRate = Device->Frequency; else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); } if(sampleRate != Device->Frequency) { - Device->NumUpdates = Device->NumUpdates * sampleRate / Device->Frequency; + Device->NumUpdates = (Device->NumUpdates*sampleRate + (Device->Frequency>>1)) / + Device->Frequency; + Device->NumUpdates = maxu(Device->NumUpdates, 2); Device->Frequency = sampleRate; } Device->FmtChans = DevFmtStereo; -- cgit v1.2.3 From 9c019126d4d7450e0dc12f48824fb8c1214ba545 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jan 2017 15:17:11 -0800 Subject: Remove __android_log_print calls for TRACEREF TRACEREFs aren't normally important, and for as often as it happens, the added function calls are wasteful even if they end up doing nothing. --- OpenAL32/Include/alMain.h | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 988c7d31..2ef43ce7 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -933,7 +933,6 @@ extern enum LogLevel LogLevel; #define TRACEREF(...) do { \ if(LogLevel >= LogRef) \ AL_PRINT("(--)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_VERBOSE, __VA_ARGS__); \ } while(0) #define TRACE(...) do { \ -- cgit v1.2.3 From 6b2297b5080ca5ba56759ca2f28206c9af277d42 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jan 2017 15:42:06 -0800 Subject: Add more traces for the Java calls being made --- Alc/backends/opensl.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 84e73f7b..c1065692 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -251,6 +251,7 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls, "parseInt", "(Ljava/lang/String;)I" ); + TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); jclass ctx_cls = (*env)->FindClass(env, "android/content/Context"); jfieldID ctx_audsvc = (*env)->GetStaticFieldID(env, ctx_cls, @@ -259,6 +260,8 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) jmethodID ctx_getSysSvc = (*env)->GetMethodID(env, ctx_cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" ); + TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", + ctx_cls, ctx_audsvc, ctx_getSysSvc); jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager"); jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls, @@ -267,22 +270,34 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, "getProperty", "(Ljava/lang/String;)Ljava/lang/Object;" ); + TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", + audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); + + const char *strchars; + jstring strobj; /* Now make the calls. */ //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - jobject audMgr = JCALL(env,CallStaticObjectMethod)(ctx_cls, ctx_getSysSvc, - JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc) - ); + strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); + jobject audMgr = JCALL(env,CallStaticObjectMethod)(ctx_cls, ctx_getSysSvc, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); + TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, - JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate) - ); + strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate); + jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj); + strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); + TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr); + JCALL(env,ReleaseStringUTFChars)(strobj, strchars); //int sampleRate = Integer.parseInt(srateStr); sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr); - TRACE("Got system sample rate %uhz\n", sampleRate); + strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL); + TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); + JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); + if(!sampleRate) sampleRate = Device->Frequency; else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); } -- cgit v1.2.3 From 3cc88b0aab9914ec6ebc4655d7d3e99fa9730431 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jan 2017 17:15:47 -0800 Subject: Use an all-pass series on each late reverb line This attempts to improve the smoothness of the late reverb decay by passing each line through multiple all-pass filters. Some work is still needed to work better in high-density and not-so-high-diffusion environments. This also removes the decay from the early reflections, since it's no longer continuous feedback. --- Alc/effects/reverb.c | 657 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 396 insertions(+), 261 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 54587f7e..c0b5546f 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -33,6 +33,95 @@ #include "mixer_defs.h" +static const int PrimeTable[1024] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, + 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, + 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, + 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, + 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, + 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, + 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, + 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, + 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, + 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, + 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, + 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, + 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, + 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, + 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, + 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, + 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, + 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, + 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, + 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, + 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, + 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, + 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, + 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, + 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, + 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, + 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, + 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, + 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, + 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, + 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, + 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, + 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, + 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, + 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, + 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, + 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, + 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, + 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, + 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, + 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, + 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, + 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, + 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, + 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, + 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, + 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, + 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, + 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, + 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, + 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, + 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, + 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, + 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, + 8117, 8123, 8147, 8161 +}; + /* This is the maximum number of samples processed for each inner loop * iteration. */ #define MAX_UPDATE_SAMPLES 256 @@ -49,11 +138,10 @@ static void init_mixfunc(void) } -typedef struct DelayLine -{ +typedef struct DelayLine { // The delay lines use sample lengths that are powers of 2 to allow the // use of bit-masking instead of a modulus for wrapping. - ALuint Mask; + ALsizei Mask; ALfloat *Line; } DelayLine; @@ -93,14 +181,13 @@ typedef struct ALreverbState { /* The tap points for the initial delay. First set go to early * reflections, second to late reverb. */ - ALuint EarlyDelayTap[4]; - ALuint LateDelayTap[4]; + ALsizei EarlyDelayTap[4]; + ALsizei LateDelayTap[4]; struct { // Early reflections are done with 4 delay lines. - ALfloat Coeff[4]; DelayLine Delay[4]; - ALuint Offset[4]; + ALsizei Offset[4]; // The gain for each output channel based on 3D panning. ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; @@ -108,37 +195,39 @@ typedef struct ALreverbState { } Early; struct { - // Output gain for late reverb. - ALfloat Gain; - // Attenuation to compensate for the modal density and decay rate of // the late lines. - ALfloat DensityGain; + ALfloat DensityGain; - // The feed-back and feed-forward all-pass coefficient. - ALfloat ApFeedCoeff; - - // Mixing matrix coefficient. - ALfloat MixCoeff; - - // Late reverb has 4 parallel all-pass filters. - struct { - ALfloat Coeff; - DelayLine Delay; - ALuint Offset; - } Ap[4]; - - // In addition to 4 cyclical delay lines. + // In addition to 4 delay lines. ALfloat Coeff[4]; DelayLine Delay[4]; - ALuint Offset[4]; + ALsizei Offset[4]; - // The cyclical delay lines are 1-pole low-pass filtered. + // The delay lines are 1-pole low-pass filtered. struct { ALfloat Sample; ALfloat Coeff; } Lp[4]; + /* Late reverb has 3 all-pass filters in series on each of the 4 lines. + */ + struct { + ALsizei Offsets[3]; + + /* One delay line is used for all 3 all-pass filters. */ + DelayLine Delay; + } Ap[4]; + + // The feed-back and feed-forward all-pass coefficient. + ALfloat ApFeedCoeff; + + // Mixing matrix coefficient. + ALfloat MixCoeff; + + // Output gain for late reverb. + ALfloat Gain; + // The gain for each output channel based on 3D panning. ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; @@ -157,10 +246,9 @@ typedef struct ALreverbState { ALfloat Coeff; ALfloat ApFeedCoeff; - ALfloat ApCoeff; - ALuint Offset; - ALuint ApOffset; + ALsizei Offset; + ALsizei ApOffset; // The echo line is 1-pole low-pass filtered. ALfloat LpCoeff; @@ -171,7 +259,7 @@ typedef struct ALreverbState { } Echo; // EAX only // The current read offset for all delay lines. - ALuint Offset; + ALsizei Offset; /* Temporary storage used when processing. */ alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES]; @@ -224,7 +312,6 @@ static void ALreverbState_Construct(ALreverbState *state) 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; @@ -236,10 +323,11 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.MixCoeff = 0.0f; for(index = 0;index < 4;index++) { - state->Late.Ap[index].Coeff = 0.0f; + ALuint k; + for(k = 0;k < 3;k++) + state->Late.Ap[index].Offsets[k] = 0; state->Late.Ap[index].Delay.Mask = 0; state->Late.Ap[index].Delay.Line = NULL; - state->Late.Ap[index].Offset = 0; state->Late.Coeff[index] = 0.0f; state->Late.Delay[index].Mask = 0; @@ -271,7 +359,6 @@ static void ALreverbState_Construct(ALreverbState *state) } 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; @@ -335,21 +422,16 @@ static const ALfloat EARLY_LINE_LENGTH[4] = 0.0015f, 0.0045f, 0.0135f, 0.0405f }; -// The lengths of the late cyclical delay lines. +/* The lengths of the late delay lines. */ static const ALfloat LATE_LINE_LENGTH[4] = { 0.0211f, 0.0311f, 0.0461f, 0.0680f }; -// The lengths of the late all-pass delay lines. -static const ALfloat ALLPASS_LINE_LENGTH[4] = -{ - 0.0151f, 0.0167f, 0.0183f, 0.0200f, -}; - -// The late cyclical delay lines have a variable length dependent on the -// effect's density parameter (inverted for some reason) and this multiplier. -static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; +/* The late delay lines have a variable length dependent on the effect's + * density parameter (inverted for some reason) and this multiplier. + */ +static const ALfloat LATE_LINE_MULTIPLIER = 3.0f; #if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM) @@ -394,12 +476,85 @@ static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, return samples; } + +static int FindClosestPrime(int desired, ALboolean *used) +{ + ALsizei curidx = 0; + ALsizei count = COUNTOF(PrimeTable)-1; + /* First, a binary search to find the closest prime that's not less than + * the desired value (lower_bound). + */ + while(count > 0) + { + ALsizei step = count>>1; + ALsizei i = curidx+step; + if(!(PrimeTable[i] < desired)) + count = step; + else + { + curidx = i+1; + count -= step+1; + } + } + /* If the next lesser prime is closer to the desired value, use it. */ + if(curidx > 0 && abs(PrimeTable[curidx-1]-desired) < abs(PrimeTable[curidx]-desired)) + curidx--; + +#define GET_BIT(arr, b) (!!(arr[(b)>>4]&(1<<((b)&7)))) +#define SET_BIT(arr, b) ((void)(arr[(b)>>4] |= (1<<((b)&7)))) + if(GET_BIT(used, curidx)) + { + ALsizei off1=0, off2=0; + /* If this prime is already used, find the next unused larger and next + * unused smaller one. + */ + while(off1 < curidx && GET_BIT(used, curidx-off1)) + off1++; + while(off2 < 1024-curidx && GET_BIT(used, curidx+off2)) + off2++; + + /* Select the closest unused prime to the desired value. */ + if(GET_BIT(used, curidx-off1)) + curidx += off2; + else if(GET_BIT(used, curidx+off2)) + curidx -= off1; + else + curidx = (abs(PrimeTable[curidx-off1]-desired) < + abs(PrimeTable[curidx+off2]-desired)) ? (curidx-off1) : (curidx+off2); + } + /* Mark this prime as used. */ + SET_BIT(used, curidx); +#undef SET_BIT +#undef GET_BIT + + return PrimeTable[curidx]; +} + +/* The lengths of the late reverb all-pass filter series are roughly calculated + * as: 15ms / (3**idx), where idx is the filter index of the series. On top of + * that, the filter lengths (in samples) should be prime numbers so they don't + * share any common factors. + * + * To accomplish this, a lookup table is used to search among the first 1024 + * primes, along with a packed bit table to mark used primes, which should be + * enough to handle any reasonable sample rate. + * + * NOTE: The returned length is in *samples*, not seconds! + */ +static ALfloat CalcAllpassLength(ALuint idx, ALuint frequency, ALboolean *used) +{ + ALfloat samples = frequency*0.015f / powf(3.0f, (ALfloat)idx); + + return FindClosestPrime((int)floorf(samples + 0.5f), used); +} + /* Calculates the delay line metrics and allocates the shared sample buffer * for all lines given the sample rate (frequency). If an allocation failure * occurs, it returns AL_FALSE. */ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) { + ALboolean used_primes[COUNTOF(PrimeTable)>>4] = { 0 }; ALuint totalSamples, index; ALfloat length; @@ -447,8 +602,19 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) // The late all-pass lines. for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Late.Ap[index].Delay); + { + ALuint k; + + length = 0.0f; + for(k = 0;k < 3;k++) + length += CalcAllpassLength(k, frequency, used_primes); + /* NOTE: Since 'length' is already the number of samples for the all- + * pass series, pass a sample rate of 1 so the sample length remains + * correct. + */ + totalSamples += CalcLineLength(length, totalSamples, 1, 1, + &State->Late.Ap[index].Delay); + } // The echo all-pass and delay lines. for(index = 0;index < 4;index++) @@ -496,6 +662,7 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) { + ALboolean used_primes[COUNTOF(PrimeTable)>>4] = { 0 }; ALuint frequency = Device->Frequency, index; // Allocate the delay lines. @@ -513,8 +680,21 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev // so their offsets only need to be calculated once. for(index = 0;index < 4;index++) { + ALuint k; + State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * frequency); - State->Late.Ap[index].Offset = fastf2u(ALLPASS_LINE_LENGTH[index] * frequency); + for(k = 0;k < 3;k++) + State->Late.Ap[index].Offsets[k] = (ALuint)CalcAllpassLength( + k, frequency, used_primes + ); + State->Late.Ap[index].Offsets[1] += State->Late.Ap[index].Offsets[0]; + State->Late.Ap[index].Offsets[2] += State->Late.Ap[index].Offsets[1]; + TRACE("Late all-pass %u: %u %u (%+d) %u (%+d)\n", index, + State->Late.Ap[index].Offsets[0], State->Late.Ap[index].Offsets[1], + (State->Late.Ap[index].Offsets[1] - State->Late.Ap[index].Offsets[0]), + State->Late.Ap[index].Offsets[2], + (State->Late.Ap[index].Offsets[2] - State->Late.Ap[index].Offsets[1]) + ); } // The echo all-pass filter line length is static, so its offset only @@ -670,7 +850,7 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat den /* The early reflections and late reverb inputs are decorrelated to provide * time-varying reflections, smooth out the reverb tail, and reduce harsh * echoes. The first tap occurs immediately, while the remaining taps are - * delayed by multiples of a fraction of the smallest cyclical delay time. + * delayed by multiples of a fraction of the smallest delay time. * * offset[index] = (FRACTION (MULTIPLIER^(index-1))) smallest_delay * @@ -693,31 +873,17 @@ static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat den } } -// Update the early reflections mix and line coefficients. -static ALvoid UpdateEarlyLines(ALfloat lateDelay, ALreverbState *State) -{ - ALuint index; - - // Calculate the gain (coefficient) for each early delay line using the - // late delay time. This expands the early reflections to the start of - // the late reverb. - for(index = 0;index < 4;index++) - State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], - lateDelay); -} - // Update the late reverb mix, line lengths, and line coefficients. static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { ALfloat length; - ALuint index; + ALsizei i; /* Calculate the late reverb gain. Since the output is tapped prior to the - * application of the next delay line coefficients, this gain needs to be - * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate - * the late reverb when echo depth is high and diffusion is low, so the - * echo is slightly stronger than the decorrelated echos in the reverb - * tail. + * application of the next delay line coefficients, the output needs to be + * attenuated by the 'x' mixing matrix coefficient. Also attenuate the + * late reverb when echo depth is high and diffusion is low, so the echo is + * slightly stronger than the decorrelated echos in the reverb tail. */ State->Late.Gain = xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); @@ -732,41 +898,31 @@ static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; length *= 1.0f + (density * LATE_LINE_MULTIPLIER); - /* To account for each channel being a discrete input, also multiply by - * sqrt(num_channels). - */ - State->Late.DensityGain = 2.0f * CalcDensityGain( + State->Late.DensityGain = CalcDensityGain( CalcDecayCoeff(length, decayTime) ); // Calculate the all-pass feed-back and feed-forward coefficient. - State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); + State->Late.ApFeedCoeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - for(index = 0;index < 4;index++) + for(i = 0;i < 4;i++) { - // Calculate the gain (coefficient) for each all-pass line. - State->Late.Ap[index].Coeff = CalcDecayCoeff( - ALLPASS_LINE_LENGTH[index], decayTime - ); + // Calculate the length (in seconds) of each delay line. + length = LATE_LINE_LENGTH[i] * (1.0f + (density*LATE_LINE_MULTIPLIER)); - // Calculate the length (in seconds) of each cyclical delay line. - length = LATE_LINE_LENGTH[index] * - (1.0f + (density * LATE_LINE_MULTIPLIER)); + // Calculate the delay offset for each delay line. + State->Late.Offset[i] = fastf2u(length * frequency); - // Calculate the delay offset for each cyclical delay line. - State->Late.Offset[index] = fastf2u(length * frequency); - - // Calculate the gain (coefficient) for each cyclical line. - State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); + // Calculate the gain (coefficient) for each line. + State->Late.Coeff[i] = CalcDecayCoeff(length, decayTime); // Calculate the damping coefficient for each low-pass filter. - State->Late.Lp[index].Coeff = CalcDampingCoeff( - hfRatio, length, decayTime, State->Late.Coeff[index], cw + State->Late.Lp[i].Coeff = CalcDampingCoeff( + hfRatio, length, decayTime, State->Late.Coeff[i], cw ); - // Attenuate the cyclical line coefficients by the mixing coefficient - // (x). - State->Late.Coeff[index] *= xMix; + // Attenuate the line coefficients by the mixing coefficient (x). + State->Late.Coeff[i] *= xMix; } } @@ -785,10 +941,7 @@ static ALvoid UpdateEchoLine(ALfloat echoTime, ALfloat decayTime, ALfloat diffus State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); // Calculate the echo all-pass feed coefficient. - State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); - - // Calculate the echo all-pass attenuation coefficient. - State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); + State->Echo.ApFeedCoeff = sqrtf(0.5f) * powf(diffusion, 2.0f); // Calculate the damping coefficient for each low-pass filter. State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, @@ -883,17 +1036,13 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection }}; /* Converts late reverb A-Format to B-Format (transposed). */ static const aluMatrixf LateA2B = {{ - { 0.8660254038f, -0.8660254038f, 0.8660254038f, 0.8660254038f }, - { 0.8660254038f, -0.8660254038f, -0.8660254038f, -0.8660254038f }, - { 0.8660254038f, 0.8660254038f, 0.8660254038f, -0.8660254038f }, - { 0.8660254038f, 0.8660254038f, -0.8660254038f, 0.8660254038f } -/* { 0.8660254038f, 1.2247448714f, 0.0f, 0.8660254038f }, + { 0.8660254038f, 1.2247448714f, 0.0f, 0.8660254038f }, { 0.8660254038f, 0.0f, -1.2247448714f, -0.8660254038f }, { 0.8660254038f, 0.0f, 1.2247448714f, -0.8660254038f }, - { 0.8660254038f, -1.2247448714f, 0.0f, 0.8660254038f }*/ + { 0.8660254038f, -1.2247448714f, 0.0f, 0.8660254038f } }}; aluMatrixf transform, rot; - ALuint i; + ALsizei i; STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; @@ -931,7 +1080,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device ALfloat lfscale, hfscale, hfRatio; ALfloat gain, gainlf, gainhf; ALfloat cw, x, y; - ALuint i; + ALsizei i; if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) State->IsEax = AL_TRUE; @@ -949,17 +1098,17 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); for(i = 1;i < 4;i++) { - State->Filter[i].Lp.a1 = State->Filter[0].Lp.a1; - State->Filter[i].Lp.a2 = State->Filter[0].Lp.a2; State->Filter[i].Lp.b0 = State->Filter[0].Lp.b0; State->Filter[i].Lp.b1 = State->Filter[0].Lp.b1; State->Filter[i].Lp.b2 = State->Filter[0].Lp.b2; + State->Filter[i].Lp.a1 = State->Filter[0].Lp.a1; + State->Filter[i].Lp.a2 = State->Filter[0].Lp.a2; - State->Filter[i].Hp.a1 = State->Filter[0].Hp.a1; - State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; State->Filter[i].Hp.b0 = State->Filter[0].Hp.b0; State->Filter[i].Hp.b1 = State->Filter[0].Hp.b1; State->Filter[i].Hp.b2 = State->Filter[0].Hp.b2; + State->Filter[i].Hp.a1 = State->Filter[0].Hp.a1; + State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; } // Update the modulator line. @@ -970,9 +1119,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, props->Reverb.Density, frequency, State); - // Update the early lines. - UpdateEarlyLines(props->Reverb.LateReverbDelay, State); - // Get the mixing matrix coefficients (x and y). CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); // Then divide x into y to simplify the matrix calculation. @@ -1010,26 +1156,26 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device **************************************/ // Basic delay line input/output routines. -static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) +static inline ALfloat DelayLineOut(DelayLine *Delay, ALsizei offset) { return Delay->Line[offset&Delay->Mask]; } -static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) +static inline ALvoid DelayLineIn(DelayLine *Delay, ALsizei offset, ALfloat in) { Delay->Line[offset&Delay->Mask] = in; } -static inline ALfloat DelayLineInOut(DelayLine *Delay, ALuint offset, ALuint outoffset, ALfloat in) +static inline ALfloat DelayLineInOut(DelayLine *Delay, ALsizei offset, ALsizei outoffset, ALfloat in) { Delay->Line[offset&Delay->Mask] = in; return Delay->Line[(offset-outoffset)&Delay->Mask]; } -static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, ALuint todo) +static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, ALsizei todo) { ALfloat sinus, range; - ALuint index, i; + ALsizei index, i; index = State->Mod.Index; range = State->Mod.Filter; @@ -1059,11 +1205,11 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, // Given some input samples, this function produces modulation for the late // reverb. -static void EAXModulation(DelayLine *ModDelay, ALuint offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, ALuint todo) +static void EAXModulation(DelayLine *ModDelay, ALsizei offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, ALsizei todo) { ALfloat frac, fdelay; ALfloat out0, out1; - ALuint delay, i; + ALsizei delay, i; for(i = 0;i < todo;i++) { @@ -1090,25 +1236,24 @@ static void EAXModulation(DelayLine *ModDelay, ALuint offset, const ALfloat *res /* Given some input samples from the main delay line, this function produces * four-channel outputs for the early reflections. */ -static ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +static ALvoid EarlyReflection(ALreverbState *State, ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { + ALsizei offset = State->Offset; ALfloat d[4], v, f[4]; - ALuint i; + ALsizei i; for(i = 0;i < todo;i++) { - ALuint offset = State->Offset+i; - /* Obtain the first reflection samples from the main delay line. */ f[0] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[0])*4 + 0); f[1] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[1])*4 + 1); f[2] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[2])*4 + 2); f[3] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[3])*4 + 3); - /* The following uses a lossless scattering junction from waveguide - * theory. It actually amounts to a householder mixing matrix, which - * will produce a maximally diffuse response, and means this can - * probably be considered a simple feed-back delay network (FDN). + /* The following is a Householder matrix that was derived from a + * lossless scattering junction from waveguide theory. In this case, + * it's maximally diffuse scattering is used without feedback. + * * N * --- * \ @@ -1118,181 +1263,172 @@ static ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restr */ v = (f[0] + f[1] + f[2] + f[3]) * 0.5f; - /* Calculate the feed values for the early delay lines. */ + /* Calculate the values to pass through the delay lines. */ d[0] = v - f[0]; d[1] = v - f[1]; d[2] = v - f[2]; d[3] = v - f[3]; + /* Store the post-junction results in the main delay line, helping + * compensate for the late reverb starting with a low echo density. + */ + DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[0])*4 + 0, d[0]); + DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[1])*4 + 1, d[1]); + DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[2])*4 + 2, d[2]); + DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[3])*4 + 3, d[3]); + /* Feed the early delay lines, and load the delayed results. */ - d[0] = DelayLineInOut(&State->Early.Delay[0], offset, State->Early.Offset[0], d[0]); - d[1] = DelayLineInOut(&State->Early.Delay[1], offset, State->Early.Offset[1], d[1]); - d[2] = DelayLineInOut(&State->Early.Delay[2], offset, State->Early.Offset[2], d[2]); - d[3] = DelayLineInOut(&State->Early.Delay[3], offset, State->Early.Offset[3], d[3]); + f[0] += DelayLineInOut(&State->Early.Delay[0], offset, State->Early.Offset[0], d[0]); + f[1] += DelayLineInOut(&State->Early.Delay[1], offset, State->Early.Offset[1], d[1]); + f[2] += DelayLineInOut(&State->Early.Delay[2], offset, State->Early.Offset[2], d[2]); + f[3] += DelayLineInOut(&State->Early.Delay[3], offset, State->Early.Offset[3], d[3]); + offset++; /* Output the initial reflection taps and the results of the delayed - * and decayed junction for all four channels. + * junction for all four channels. */ - out[0][i] = f[0] + d[0]*State->Early.Coeff[0]; - out[1][i] = f[1] + d[1]*State->Early.Coeff[1]; - out[2][i] = f[2] + d[2]*State->Early.Coeff[2]; - out[3][i] = f[3] + d[3]*State->Early.Coeff[3]; + out[0][i] = f[0]; + out[1][i] = f[1]; + out[2][i] = f[2]; + out[3][i] = f[3]; } } // 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, ALsizei outOffset, ALsizei inOffset, ALfloat in, ALfloat feedCoeff) { ALfloat out, feed; out = DelayLineOut(Delay, outOffset); feed = feedCoeff * in; - DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); + DelayLineIn(Delay, inOffset, in + feedCoeff*(out - feed)); - // The time-based attenuation is only applied to the delay output to - // keep it from affecting the feed-back path (which is already controlled - // by the all-pass feed coefficient). - return (coeff * out) - feed; + return out - feed; } -// All-pass input/output routine for late reverb. -static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in) +// All-pass series input/output routine for late reverb. +static inline ALfloat LateAllPassInOut(ALreverbState *State, ALsizei offset, ALsizei index, ALfloat sample) { - return AllpassInOut(&State->Late.Ap[index].Delay, - offset - State->Late.Ap[index].Offset, - offset, in, State->Late.ApFeedCoeff, - State->Late.Ap[index].Coeff); + ALsizei inOffset; + ALsizei i; + + inOffset = offset; + for(i = 0;i < 3;i++) + { + ALuint outOffset = offset - State->Late.Ap[index].Offsets[i]; + sample = AllpassInOut(&State->Late.Ap[index].Delay, + outOffset, inOffset, sample, State->Late.ApFeedCoeff + ); + inOffset = outOffset; + } + + return sample; } // Low-pass filter input/output routine for late reverb. -static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in) +static inline ALfloat LateLowPassInOut(ALreverbState *State, ALsizei index, ALfloat in) { in = lerp(in, State->Late.Lp[index].Sample, State->Late.Lp[index].Coeff); State->Late.Lp[index].Sample = in; return in; } -// Given four decorrelated input samples, this function produces four-channel -// output for the late reverb. -static ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +/* Given decorrelated input samples from the main delay line, this function + * produces four-channel output for the late reverb. + */ +static ALvoid LateReverb(ALreverbState *State, ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat d[4], f[4]; - ALuint offset; - ALuint base, i; + ALsizei offset; + ALsizei i, j; offset = State->Offset; - for(base = 0;base < todo;) + for(i = 0;i < todo;i++) { - ALfloat tmp[MAX_UPDATE_SAMPLES/4][4]; - ALuint tmp_todo = minu(todo, MAX_UPDATE_SAMPLES/4); - - for(i = 0;i < tmp_todo;i++) - { - /* Obtain four decorrelated input samples. */ - f[0] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[0])*4 + 0) * State->Late.DensityGain; - f[1] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[1])*4 + 1) * State->Late.DensityGain; - f[2] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[2])*4 + 2) * State->Late.DensityGain; - f[3] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[3])*4 + 3) * State->Late.DensityGain; - - /* Add the decayed results of the cyclical delay lines, then pass - * the results through the low-pass filters. - */ - f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; - f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; - f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; - f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; - - /* This is where the feed-back cycles from line 0 to 3 to 1 to 2 - * and back to 0. - */ - d[0] = LateLowPassInOut(State, 2, f[2]); - d[1] = LateLowPassInOut(State, 3, f[3]); - d[2] = LateLowPassInOut(State, 1, f[1]); - d[3] = LateLowPassInOut(State, 0, f[0]); - - /* To help increase diffusion, run each line through an all-pass - * filter. When there is no diffusion, the shortest all-pass filter - * will feed the shortest delay line. - */ - d[0] = LateAllPassInOut(State, offset, 0, d[0]); - d[1] = LateAllPassInOut(State, offset, 1, d[1]); - d[2] = LateAllPassInOut(State, offset, 2, d[2]); - d[3] = LateAllPassInOut(State, offset, 3, d[3]); - - /* Late reverb is done with a modified feed-back delay network (FDN) - * topology. Four input lines are each fed through their own all-pass - * filter and then into the mixing matrix. The four outputs of the - * mixing matrix are then cycled back to the inputs. Each output feeds - * a different input to form a circlular feed cycle. - * - * The mixing matrix used is a 4D skew-symmetric rotation matrix - * derived using a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y - * with differing signs, and d is the coefficient x. The matrix is - * thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * To reduce the number of multiplies, the x coefficient is applied - * with the cyclical delay line coefficients. Thus only the y - * coefficient is applied when mixing, and is modified to be: y / x. - */ - f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); - f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); - f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); - f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); - - /* Re-feed the cyclical delay lines. */ - DelayLineIn(&State->Late.Delay[0], offset, f[0]); - DelayLineIn(&State->Late.Delay[1], offset, f[1]); - DelayLineIn(&State->Late.Delay[2], offset, f[2]); - DelayLineIn(&State->Late.Delay[3], offset, f[3]); - offset++; - - /* Output the results of the matrix for all four channels, - * attenuated by the late reverb gain (which is attenuated by the - * 'x' mix coefficient). - */ - tmp[i][0] = State->Late.Gain * f[0]; - tmp[i][1] = State->Late.Gain * f[1]; - tmp[i][2] = State->Late.Gain * f[2]; - tmp[i][3] = State->Late.Gain * f[3]; - } - - /* Deinterlace to output */ - for(i = 0;i < tmp_todo;i++) out[0][base+i] = tmp[i][0]; - for(i = 0;i < tmp_todo;i++) out[1][base+i] = tmp[i][1]; - for(i = 0;i < tmp_todo;i++) out[2][base+i] = tmp[i][2]; - for(i = 0;i < tmp_todo;i++) out[3][base+i] = tmp[i][3]; + /* Obtain four decorrelated input samples. */ + for(j = 0;j < 4;j++) + f[j] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[j])*4 + j) * + State->Late.DensityGain; + + /* Add the decayed results of the delay lines. */ + for(j = 0;j < 4;j++) + f[j] += DelayLineOut(&State->Late.Delay[j], offset-State->Late.Offset[j]) * + State->Late.Coeff[j]; + + /* Apply a low-pass filter to simulate surface absorption. */ + for(j = 0;j < 4;j++) + f[j] = LateLowPassInOut(State, 0, f[j]); + + /* To help increase diffusion, run each line through three all-pass + * filters. This is where the feedback cycles from line 0 to 3 to 1 to + * 2 and back to 0. + */ + d[0] = LateAllPassInOut(State, offset, 2, f[2]); + d[1] = LateAllPassInOut(State, offset, 3, f[3]); + d[2] = LateAllPassInOut(State, offset, 1, f[1]); + d[3] = LateAllPassInOut(State, offset, 0, f[0]); + + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filters and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix + * derived using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is + * thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied + * with the delay line coefficients. Thus only the y coefficient + * is applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + + /* Re-feed the delay lines. */ + for(j = 0;j < 4;j++) + DelayLineIn(&State->Late.Delay[j], offset, f[j]); + offset++; - base += tmp_todo; + /* Output the results of the matrix for all four channels, attenuated + * by the late reverb gain (which is attenuated by the 'x' mix + * coefficient). + */ + for(j = 0;j < 4;j++) + out[j][i] = f[j] * State->Late.Gain; } } -// Given an input sample, this function mixes echo into the four-channel late -// reverb. -static ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +/* This function reads from the main delay line's late reverb tap, and mixes a + * continuous echo feedback into the four-channel late reverb output. + */ +static ALvoid EAXEcho(ALreverbState *State, ALsizei todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALfloat feed; - ALuint offset; - ALuint c, i; + ALsizei offset; + ALsizei c, i; for(c = 0;c < 4;c++) { offset = State->Offset; for(i = 0;i < todo;i++) { - // Get the latest attenuated echo sample for output. + // Get the attenuated echo feedback sample for output. feed = DelayLineOut(&State->Echo.Delay[c].Feedback, offset-State->Echo.Offset) * State->Echo.Coeff; @@ -1308,8 +1444,7 @@ static ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late // Then the echo all-pass filter. feed = AllpassInOut(&State->Echo.Delay[c].Ap, offset-State->Echo.ApOffset, - offset, feed, State->Echo.ApFeedCoeff, - State->Echo.ApCoeff); + offset, feed, State->Echo.ApFeedCoeff); // Feed the delay with the mixed and filtered sample. DelayLineIn(&State->Echo.Delay[c].Feedback, offset, feed); @@ -1320,9 +1455,9 @@ static ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static ALvoid VerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALvoid VerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALuint i, c; + ALsizei i, c; for(c = 0;c < 4;c++) { @@ -1346,9 +1481,9 @@ static ALvoid VerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict inp // Perform the EAX reverb pass on a given input sample, resulting in four- // channel output. -static ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALvoid EAXVerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { - ALuint i, c; + ALsizei i, c; /* Perform any modulation on the input (use the early and late buffers as * temp storage). @@ -1398,9 +1533,9 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); + ALsizei todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - /* Convert B-Foramt to A-Format for processing. */ + /* Convert B-Format to A-Format for processing. */ memset(afmt, 0, sizeof(*afmt)*4); for(c = 0;c < 4;c++) MixRowSamples(afmt[c], B2A.m[c], @@ -1443,7 +1578,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - ALuint todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); + ALsizei todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); memset(afmt, 0, 4*MAX_UPDATE_SAMPLES*sizeof(float)); for(c = 0;c < 4;c++) -- cgit v1.2.3 From 55a2474d7e5ad39d4dc1c07082314bb26a528335 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Jan 2017 13:06:40 -0800 Subject: Fix late reverb low-pass filtering --- Alc/effects/reverb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c0b5546f..456b25dc 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1357,7 +1357,7 @@ static ALvoid LateReverb(ALreverbState *State, ALsizei todo, ALfloat (*restrict /* Apply a low-pass filter to simulate surface absorption. */ for(j = 0;j < 4;j++) - f[j] = LateLowPassInOut(State, 0, f[j]); + f[j] = LateLowPassInOut(State, j, f[j]); /* To help increase diffusion, run each line through three all-pass * filters. This is where the feedback cycles from line 0 to 3 to 1 to -- cgit v1.2.3 From 071b83ba523b0bae6f86482190677b4e52fb6082 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Jan 2017 16:42:02 -0800 Subject: Replace more ALuint with ALsizei --- Alc/bformatdec.c | 20 ++++++++++---------- Alc/bformatdec.h | 2 +- Alc/panning.c | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 86300f7b..fc0dee47 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -233,9 +233,9 @@ int bformatdec_getOrder(const struct BFormatDec *dec) return 0; } -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags) +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags) { - static const ALuint map2DTo3D[MAX_AMBI2D_COEFFS] = { + static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; @@ -312,7 +312,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { for(i = 0;i < conf->NumSpeakers;i++) { - ALuint chan = chanmap[i]; + ALsizei chan = chanmap[i]; ALfloat delay; /* Distance compensation only delays in steps of the sample rate. @@ -341,15 +341,15 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount dec->DualBand = AL_FALSE; for(i = 0;i < conf->NumSpeakers;i++) { - ALuint chan = chanmap[i]; + ALsizei chan = chanmap[i]; ALfloat gain; - ALuint j, k; + ALsizei j, k; if(!dec->Periphonic) { for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { - ALuint l = map2DTo3D[j]; + ALsizei l = map2DTo3D[j]; if(j == 0) gain = conf->HFOrderGain[0]; else if(j == 1) gain = conf->HFOrderGain[1]; else if(j == 3) gain = conf->HFOrderGain[2]; @@ -385,15 +385,15 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount ratio = powf(10.0f, conf->XOverRatio / 40.0f); for(i = 0;i < conf->NumSpeakers;i++) { - ALuint chan = chanmap[i]; + ALsizei chan = chanmap[i]; ALfloat gain; - ALuint j, k; + ALsizei j, k; if(!dec->Periphonic) { for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { - ALuint l = map2DTo3D[j]; + ALsizei l = map2DTo3D[j]; if(j == 0) gain = conf->HFOrderGain[0] * ratio; else if(j == 1) gain = conf->HFOrderGain[1] * ratio; else if(j == 3) gain = conf->HFOrderGain[2] * ratio; @@ -405,7 +405,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount } for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { - ALuint l = map2DTo3D[j]; + ALsizei l = map2DTo3D[j]; if(j == 0) gain = conf->LFOrderGain[0] / ratio; else if(j == 1) gain = conf->LFOrderGain[1] / ratio; else if(j == 3) gain = conf->LFOrderGain[2] / ratio; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 7024b003..06c14ec3 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -32,7 +32,7 @@ enum BFormatDecFlags { struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); -void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags); +void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags); /* Decodes the ambisonic input to the given output channels. */ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); diff --git a/Alc/panning.c b/Alc/panning.c index 9b6f9b44..98da032e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -360,7 +360,7 @@ static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeff *outcount = i; } -static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS]) +static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { ALsizei i; @@ -610,7 +610,7 @@ static void InitPanning(ALCdevice *device) } } -static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS]) +static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; const ALfloat *coeff_scale = UnitScale; @@ -690,7 +690,7 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A device->FOAOut.CoeffCount = 4; } -static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS]) +static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { const char *devname; int decflags = 0; @@ -879,7 +879,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->FmtChans != DevFmtStereo) { - ALuint speakermap[MAX_OUTPUT_CHANNELS]; + ALsizei speakermap[MAX_OUTPUT_CHANNELS]; const char *devname, *layout = NULL; AmbDecConf conf, *pconf = NULL; -- cgit v1.2.3 From 2c1791752aebea9f2cf83df155db607eaeeb2046 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 2 Feb 2017 06:14:01 -0800 Subject: Android's AudioManager.getProperty(String) returns a String --- Alc/backends/opensl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index c1065692..51fe11f6 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -268,7 +268,7 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;" ); jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls, - "getProperty", "(Ljava/lang/String;)Ljava/lang/Object;" + "getProperty", "(Ljava/lang/String;)Ljava/lang/String;" ); TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n", audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty); -- cgit v1.2.3 From 428cde5dc26191871111e1edbea85ade952898aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Feb 2017 09:41:21 -0800 Subject: Call getSystemService as a non-static function --- Alc/backends/opensl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 51fe11f6..1e4bcb06 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -253,11 +253,11 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) ); TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint); - jclass ctx_cls = (*env)->FindClass(env, "android/content/Context"); - jfieldID ctx_audsvc = (*env)->GetStaticFieldID(env, ctx_cls, + jclass ctx_cls = JCALL(env,FindClass)("android/content/Context"); + jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls, "AUDIO_SERVICE", "Ljava/lang/String;" ); - jmethodID ctx_getSysSvc = (*env)->GetMethodID(env, ctx_cls, + jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;" ); TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n", @@ -279,7 +279,7 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) /* Now make the calls. */ //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallStaticObjectMethod)(ctx_cls, ctx_getSysSvc, strobj); + jobject audMgr = JCALL(env,CallObjectMethod)(ctx_cls, ctx_getSysSvc, strobj); strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); JCALL(env,ReleaseStringUTFChars)(strobj, strchars); -- cgit v1.2.3 From af362c2d05097fce816b5c5d911d6650eb6bef37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 Feb 2017 14:25:17 -0800 Subject: Fix for NULL JNIEnv Which can happen with native-only apps --- Alc/ALc.c | 6 ++++++ Alc/backends/opensl.c | 8 +++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 91ff79af..39e29f9f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1179,6 +1179,12 @@ static void CleanupJNIEnv(void* UNUSED(ptr)) void *Android_GetJNIEnv(void) { + if(!gJavaVM) + { + WARN("gJavaVM is NULL!\n"); + return NULL; + } + /* http://developer.android.com/guide/practices/jni.html * * All threads are Linux threads, scheduled by the kernel. They're usually diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 1e4bcb06..08530d95 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -237,13 +237,11 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) SLInterfaceID id; SLresult result; SLboolean req; + JNIEnv *env; - if((Device->Flags&DEVICE_FREQUENCY_REQUEST)) - sampleRate = Device->Frequency; - else + sampleRate = Device->Frequency; + if(!(Device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL) { - JNIEnv *env = Android_GetJNIEnv(); - /* Get necessary stuff for using java.lang.Integer, * android.content.Context, and android.media.AudioManager. */ -- cgit v1.2.3 From 9f10ae466c089388db1bd9ff236eec50ed98b157 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Feb 2017 06:25:11 -0800 Subject: Convert the OpenSL backend to the new backend API This also removes the buffer queue callback's call to aluMixData, which could potentially block on a mutex. --- Alc/ALc.c | 2 +- Alc/backends/base.h | 1 + Alc/backends/opensl.c | 608 +++++++++++++++++++++++++++++++++++--------------- 3 files changed, 434 insertions(+), 177 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 39e29f9f..94e19267 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -99,7 +99,7 @@ static struct BackendInfo BackendList[] = { { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_OPENSL - { "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs }, + { "opensl", ALCopenslBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif { "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 94177405..4f398047 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -145,6 +145,7 @@ ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCportBackendFactory_getFactory(void); +ALCbackendFactory *ALCopenslBackendFactory_getFactory(void); ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 08530d95..878519bd 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -29,33 +29,17 @@ #include "compat.h" #include "threads.h" +#include "backends/base.h" + #include #include +#include /* Helper macros */ #define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS #define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS -typedef struct { - /* engine interfaces */ - SLObjectItf engineObject; - SLEngineItf engine; - - /* output mix interfaces */ - SLObjectItf outputMix; - - /* buffer queue player interfaces */ - SLObjectItf bufferQueueObject; - - void *buffer; - ALuint bufferSize; - ALuint curBuffer; - - ALuint frameSize; -} osl_data; - - static const ALCchar opensl_device[] = "OpenSL"; @@ -89,6 +73,26 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) return 0; } +#ifdef SL_DATAFORMAT_PCM_EX +static SLuint32 GetTypeRepresentation(enum DevFmtType type) +{ + switch(type) + { + case DevFmtUByte: + case DevFmtUShort: + case DevFmtUInt: + return SL_PCM_REPRESENTATION_UNSIGNED_INT; + case DevFmtByte: + case DevFmtShort: + case DevFmtInt: + return SL_PCM_REPRESENTATION_SIGNED_INT; + case DevFmtFloat: + return SL_PCM_REPRESENTATION_FLOAT; + } + return 0; +} +#endif + static const char *res_str(SLresult result) { switch(result) @@ -128,120 +132,315 @@ static const char *res_str(SLresult result) ERR("%s: %s\n", (s), res_str((x))); \ } while(0) + +typedef struct ALCopenslPlayback { + DERIVE_FROM_TYPE(ALCbackend); + + /* engine interfaces */ + SLObjectItf mEngineObj; + SLEngineItf mEngine; + + /* output mix interfaces */ + SLObjectItf mOutputMix; + + /* buffer queue player interfaces */ + SLObjectItf mBufferQueueObj; + + ll_ringbuffer_t *mRing; + alcnd_t mCond; + + ALsizei mFrameSize; + + ATOMIC(ALboolean) mKillNow; + althrd_t mThread; +} ALCopenslPlayback; + +static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context); +static int ALCopenslPlayback_mixerProc(void *arg); + +static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); +static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); +static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); +static void ALCopenslPlayback_close(ALCopenslPlayback *self); +static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); +static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); +static void ALCopenslPlayback_stop(ALCopenslPlayback *self); +static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self); +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback); + + +static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCopenslPlayback, ALCbackend, self); + + self->mEngineObj = NULL; + self->mEngine = NULL; + self->mOutputMix = NULL; + self->mBufferQueueObj = NULL; + + self->mRing = NULL; + alcnd_init(&self->mCond); + + self->mFrameSize = 0; + + ATOMIC_INIT(&self->mKillNow, AL_FALSE); +} + +static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) +{ + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + if(self->mOutputMix != NULL) + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + alcnd_destroy(&self->mCond); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + /* this callback handler is called every time a buffer finishes playing */ -static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context) +static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) { - ALCdevice *Device = context; - osl_data *data = Device->ExtraData; - ALvoid *buf; + ALCopenslPlayback *self = context; + + /* A note on the ringbuffer usage: The buffer queue seems to hold on to the + * pointer passed to the Enqueue method, rather than copying the audio. + * Consequently, the ringbuffer contains the audio that is currently queued + * and waiting to play. This process() callback is called when a buffer is + * finished, so we simply move the read pointer up to indicate the space is + * available for writing again, and wake up the mixer thread to mix and + * queue more audio. + */ + ll_ringbuffer_read_advance(self->mRing, 1); + + alcnd_signal(&self->mCond); +} + + +static int ALCopenslPlayback_mixerProc(void *arg) +{ + ALCopenslPlayback *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + SLAndroidSimpleBufferQueueItf bufferQueue; + ll_ringbuffer_data_t data[2]; + SLPlayItf player; SLresult result; + size_t padding; - buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize; - aluMixData(Device, buf, data->bufferSize/data->frameSize); + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); - result = VCALL(bq,Enqueue)(buf, data->bufferSize); - PRINTERR(result, "bq->Enqueue"); + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_BUFFERQUEUE"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); + } + if(SL_RESULT_SUCCESS != result) + { + ALCopenslPlayback_lock(self); + aluHandleDisconnect(device); + ALCopenslPlayback_unlock(self); + return 1; + } + + /* NOTE: The ringbuffer will be larger than the desired buffer metrics. + * Calculate the amount of extra space so we know how much to keep unused. + */ + padding = ll_ringbuffer_write_space(self->mRing) - device->NumUpdates; + + ALCopenslPlayback_lock(self); + while(ATOMIC_LOAD_SEQ(&self->mKillNow) == AL_FALSE && device->Connected) + { + size_t todo, len0, len1; + + if(ll_ringbuffer_write_space(self->mRing) <= padding) + { + SLuint32 state = 0; + + result = VCALL(player,GetPlayState)(&state); + PRINTERR(result, "player->GetPlayState"); + if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING) + { + result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); + PRINTERR(result, "player->SetPlayState"); + } + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(device); + break; + } + + /* NOTE: Unfortunately, there is an unavoidable race condition + * here. It's possible for the process() method to run, updating + * the read pointer and signaling the condition variable, in + * between checking the write size and waiting for the condition + * variable here. This will cause alcnd_wait to wait until the + * *next* process() invocation signals the condition variable + * again. + * + * However, this should only happen if the mixer is running behind + * anyway (as ideally we'll be asleep in alcnd_wait by the time the + * process() method is invoked), so this behavior is not completely + * unwarranted. It's unfortunate since it'll be wasting time + * sleeping that could be used to catch up, but there's no way + * around it without blocking in the process() method. + */ + if(ll_ringbuffer_write_space(self->mRing) <= padding) + { + alcnd_wait(&self->mCond, &STATIC_CAST(ALCbackend,self)->mMutex); + continue; + } + } + + ll_ringbuffer_get_write_vector(self->mRing, data); + todo = data[0].len+data[1].len - padding; + + len0 = minu(todo, data[0].len); + len1 = minu(todo-len0, data[1].len); + + aluMixData(device, data[0].buf, len0*device->UpdateSize); + for(size_t i = 0;i < len0;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS == result) + ll_ringbuffer_write_advance(self->mRing, 1); + + data[0].buf += device->UpdateSize*self->mFrameSize; + } + + if(len1 > 0) + { + aluMixData(device, data[1].buf, len1*device->UpdateSize); + for(size_t i = 0;i < len1;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[1].buf, device->UpdateSize*self->mFrameSize); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS == result) + ll_ringbuffer_write_advance(self->mRing, 1); + + data[1].buf += device->UpdateSize*self->mFrameSize; + } + } + } + ALCopenslPlayback_unlock(self); - data->curBuffer = (data->curBuffer+1) % Device->NumUpdates; + return 0; } -static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName) +static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name) { - osl_data *data = NULL; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLresult result; - if(!deviceName) - deviceName = opensl_device; - else if(strcmp(deviceName, opensl_device) != 0) + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) return ALC_INVALID_VALUE; - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - // create engine - result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL); + result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); PRINTERR(result, "slCreateEngine"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "engine->Realize"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine); + result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); PRINTERR(result, "engine->GetInterface"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL); + result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL); PRINTERR(result, "engine->CreateOutputMix"); } if(SL_RESULT_SUCCESS == result) { - result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE); + result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "outputMix->Realize"); } if(SL_RESULT_SUCCESS != result) { - if(data->outputMix != NULL) - VCALL0(data->outputMix,Destroy)(); - data->outputMix = NULL; + if(self->mOutputMix != NULL) + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; - if(data->engineObject != NULL) - VCALL0(data->engineObject,Destroy)(); - data->engineObject = NULL; - data->engine = NULL; + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; - free(data); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&Device->DeviceName, deviceName); - Device->ExtraData = data; + al_string_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } - -static void opensl_close_playback(ALCdevice *Device) +static void ALCopenslPlayback_close(ALCopenslPlayback *self) { - osl_data *data = Device->ExtraData; - - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; - - VCALL0(data->outputMix,Destroy)(); - data->outputMix = NULL; + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; - VCALL0(data->engineObject,Destroy)(); - data->engineObject = NULL; - data->engine = NULL; + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; - free(data); - Device->ExtraData = NULL; + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; } -static ALCboolean opensl_reset_playback(ALCdevice *Device) +static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) { - osl_data *data = Device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataLocator_OutputMix loc_outmix; - SLDataFormat_PCM format_pcm; SLDataSource audioSrc; SLDataSink audioSnk; ALuint sampleRate; - SLInterfaceID id; + SLInterfaceID ids[2]; + SLboolean reqs[2]; SLresult result; - SLboolean req; JNIEnv *env; - sampleRate = Device->Frequency; - if(!(Device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL) + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + sampleRate = device->Frequency; + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL) { + /* FIXME: Disabled until I figure out how to get the Context needed for + * the getSystemService call. + */ +#if 0 /* Get necessary stuff for using java.lang.Integer, * android.content.Context, and android.media.AudioManager. */ @@ -296,64 +495,99 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars); JCALL(env,ReleaseStringUTFChars)(srateStr, strchars); - if(!sampleRate) sampleRate = Device->Frequency; + if(!sampleRate) sampleRate = device->Frequency; else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); +#endif } - if(sampleRate != Device->Frequency) + if(sampleRate != device->Frequency) { - Device->NumUpdates = (Device->NumUpdates*sampleRate + (Device->Frequency>>1)) / - Device->Frequency; - Device->NumUpdates = maxu(Device->NumUpdates, 2); - Device->Frequency = sampleRate; + device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) / + device->Frequency; + device->NumUpdates = maxu(device->NumUpdates, 2); + device->Frequency = sampleRate; } - Device->FmtChans = DevFmtStereo; - Device->FmtType = DevFmtShort; - SetDefaultWFXChannelOrder(Device); + device->FmtChans = DevFmtStereo; + device->FmtType = DevFmtShort; + SetDefaultWFXChannelOrder(device); + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - req = SL_BOOLEAN_TRUE; loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = Device->NumUpdates; - + loc_bufq.numBuffers = device->NumUpdates; + +#ifdef SL_DATAFORMAT_PCM_EX + SLDataFormat_PCM_EX format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM_EX; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans); + format_pcm.sampleRate = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(device->FmtType); +#else + SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans); - format_pcm.samplesPerSec = Device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans); + format_pcm.samplesPerSec = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(Device->FmtChans); + format_pcm.channelMask = GetChannelMask(device->FmtChans); format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN; +#endif audioSrc.pLocator = &loc_bufq; audioSrc.pFormat = &format_pcm; loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = data->outputMix; + loc_outmix.outputMix = self->mOutputMix; audioSnk.pLocator = &loc_outmix; audioSnk.pFormat = NULL; - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; + ids[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + reqs[0] = SL_BOOLEAN_TRUE; + ids[1] = SL_IID_ANDROIDCONFIGURATION; + reqs[1] = SL_BOOLEAN_FALSE; - result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req); + result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj, + &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs + ); PRINTERR(result, "engine->CreateAudioPlayer"); if(SL_RESULT_SUCCESS == result) { - result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE); + /* Set the stream type to "media" (games, music, etc), if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLint32 streamType = SL_ANDROID_STREAM_MEDIA; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, + &streamType, sizeof(streamType) + ); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "bufferQueue->Realize"); } if(SL_RESULT_SUCCESS != result) { - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; return ALC_FALSE; } @@ -361,64 +595,35 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device) return ALC_TRUE; } -static ALCboolean opensl_start_playback(ALCdevice *Device) +static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) { - osl_data *data = Device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; SLresult result; - ALuint i; - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); - data->bufferSize = Device->UpdateSize * data->frameSize; - data->buffer = calloc(Device->NumUpdates, data->bufferSize); - if(!data->buffer) - { - result = SL_RESULT_MEMORY_FAILURE; - PRINTERR(result, "calloc"); - } - } - /* enqueue the first buffer to kick off the callbacks */ - for(i = 0;i < Device->NumUpdates;i++) - { - if(SL_RESULT_SUCCESS == result) - { - ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize; - result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize); - PRINTERR(result, "bufferQueue->Enqueue"); - } - } - data->curBuffer = 0; - if(SL_RESULT_SUCCESS == 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_PLAYING); - PRINTERR(result, "player->SetPlayState"); - } + ll_ringbuffer_free(self->mRing); + /* NOTE: Add an extra update since one period's worth of audio in the ring + * buffer will always be left unfilled because one element of the ring + * buffer will not be writeable, and we only write in period-sized chunks. + */ + self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, + self->mFrameSize*device->UpdateSize); + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS != result) - { - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; + return ALC_FALSE; - free(data->buffer); - data->buffer = NULL; - data->bufferSize = 0; + result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self); + PRINTERR(result, "bufferQueue->RegisterCallback"); + if(SL_RESULT_SUCCESS != result) + return ALC_FALSE; + ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE); + if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success) + { + ERR("Failed to start mixer thread\n"); return ALC_FALSE; } @@ -426,14 +631,27 @@ static ALCboolean opensl_start_playback(ALCdevice *Device) } -static void opensl_stop_playback(ALCdevice *Device) +static void ALCopenslPlayback_stop(ALCopenslPlayback *self) { - osl_data *data = Device->ExtraData; - SLPlayItf player; SLAndroidSimpleBufferQueueItf bufferQueue; + SLPlayItf player; SLresult result; - - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player); + int res; + + if(ATOMIC_EXCHANGE_SEQ(ALboolean, &self->mKillNow, AL_TRUE)) + return; + + /* Lock the backend to ensure we don't flag the mixer to die and signal the + * mixer to wake up in between it checking the flag and going to sleep and + * wait for a wakeup (potentially leading to it never waking back up to see + * the flag). + */ + ALCopenslPlayback_lock(self); + ALCopenslPlayback_unlock(self); + alcnd_signal(&self->mCond); + althrd_join(self->mThread, &res); + + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -441,7 +659,8 @@ static void opensl_stop_playback(ALCdevice *Device) PRINTERR(result, "player->SetPlayState"); } - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); PRINTERR(result, "bufferQueue->GetInterface"); if(SL_RESULT_SUCCESS == result) { @@ -449,6 +668,11 @@ static void opensl_stop_playback(ALCdevice *Device) PRINTERR(result, "bufferQueue->Clear"); } if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) { SLAndroidSimpleBufferQueueState state; do { @@ -458,45 +682,77 @@ static void opensl_stop_playback(ALCdevice *Device) PRINTERR(result, "bufferQueue->GetState"); } - free(data->buffer); - data->buffer = NULL; - data->bufferSize = 0; + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; } +static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ClockLatency ret; + + ALCopenslPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ll_ringbuffer_read_space(self->mRing) * DEVICE_CLOCK_RES / + device->Frequency; + ALCopenslPlayback_unlock(self); -static const BackendFuncs opensl_funcs = { - opensl_open_playback, - opensl_close_playback, - opensl_reset_playback, - opensl_start_playback, - opensl_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL -}; + return ret; +} -ALCboolean alc_opensl_init(BackendFuncs *func_list) +typedef struct ALCopenslBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCopenslBackendFactory; +#define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self)) { - *func_list = opensl_funcs; return ALC_TRUE; } -void alc_opensl_deinit(void) +static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self)) +{ +} + +static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; } -void alc_opensl_probe(enum DevProbe type) +static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { case ALL_DEVICE_PROBE: AppendAllDevicesList(opensl_device); break; + case CAPTURE_DEVICE_PROBE: break; } } + +static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCopenslPlayback *backend; + NEW_OBJ(backend, ALCopenslPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory); + + +ALCbackendFactory *ALCopenslBackendFactory_getFactory(void) +{ + static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} -- cgit v1.2.3 From c771b82a39bcbb29b2ab97b3e592ee96a190e7cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Feb 2017 10:29:31 -0800 Subject: Use the correct IID for the opensl buffer queue --- Alc/backends/opensl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 878519bd..a667dc70 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -249,8 +249,9 @@ static int ALCopenslPlayback_mixerProc(void *arg) SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface SL_IID_BUFFERQUEUE"); + result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE"); if(SL_RESULT_SUCCESS == result) { result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); -- cgit v1.2.3 From 317d135b96bc1d2a095a9e249588182883540093 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Feb 2017 11:19:41 -0800 Subject: Clear trailing whitespace from the cpu features string --- Alc/helpers.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Alc/helpers.c b/Alc/helpers.c index ef0c8e88..eb00acb8 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -242,11 +242,16 @@ void FillCPUCaps(ALuint capfilter) char buf[256]; while(fgets(buf, sizeof(buf), file) != NULL) { + size_t len; char *str; if(strncmp(buf, "Features\t:", 10) != 0) continue; + len = strlen(buf); + while(len > 0 && isspace(buf[len-1])) + buf[--len] = 0; + TRACE("Got features string:%s\n", buf+10); str = buf; -- cgit v1.2.3 From 7cc8ba99f094119d176538325c827cad63140801 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Feb 2017 18:33:12 -0800 Subject: Properly capitalize NEON --- Alc/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index eb00acb8..eac3811d 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -277,7 +277,7 @@ void FillCPUCaps(ALuint capfilter) ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""), ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), - ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""), + ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""), ((!capfilter) ? " -none-" : "") ); CPUCapFlags = caps & capfilter; -- cgit v1.2.3 From 5bd63ff03d324f772875611325ee10c8a8df1c3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Feb 2017 19:32:49 -0800 Subject: Remove a couple context lock wrapper functions --- Alc/ALc.c | 3 --- OpenAL32/Include/alMain.h | 6 ------ OpenAL32/alSource.c | 34 +++++++++++++++++----------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 94e19267..fcc6d649 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1496,9 +1496,6 @@ static ALCboolean IsValidALCChannels(ALCenum channels) * Miscellaneous ALC helpers ************************************************/ -extern inline void LockContext(ALCcontext *context); -extern inline void UnlockContext(ALCcontext *context); - void ALCdevice_Lock(ALCdevice *device) { V0(device->Backend,lock)(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2ef43ce7..2573c836 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -822,12 +822,6 @@ void ALCdevice_Unlock(ALCdevice *device); void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type); void ALCcontext_ProcessUpdates(ALCcontext *context); -inline void LockContext(ALCcontext *context) -{ ALCdevice_Lock(context->Device); } - -inline void UnlockContext(ALCcontext *context) -{ ALCdevice_Unlock(context->Device); } - enum { DeferOff = AL_FALSE, DeferAll, diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e3d3cf1b..c60cd790 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -527,16 +527,16 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { - LockContext(Context); + ALCdevice_Lock(Context->Device); WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { WriteUnlock(&Source->queue_lock); - UnlockContext(Context); + ALCdevice_Unlock(Context->Device); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } WriteUnlock(&Source->queue_lock); - UnlockContext(Context); + ALCdevice_Unlock(Context->Device); } return AL_TRUE; @@ -728,16 +728,16 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { - LockContext(Context); + ALCdevice_Lock(Context->Device); WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { WriteUnlock(&Source->queue_lock); - UnlockContext(Context); + ALCdevice_Unlock(Context->Device); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } WriteUnlock(&Source->queue_lock); - UnlockContext(Context); + ALCdevice_Unlock(Context->Device); } return AL_TRUE; @@ -1606,10 +1606,10 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) continue; FreeThunkEntry(Source->id); - LockContext(context); + ALCdevice_Lock(context->Device); voice = GetSourceVoice(Source, context); if(voice) voice->Source = NULL; - UnlockContext(context); + ALCdevice_Unlock(context->Device); DeinitSource(Source); @@ -2303,7 +2303,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - LockContext(context); + ALCdevice_Lock(context->Device); while(n > context->MaxVoices-context->VoiceCount) { ALvoice *temp = NULL; @@ -2314,7 +2314,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) temp = al_malloc(16, newcount * sizeof(context->Voices[0])); if(!temp) { - UnlockContext(context); + ALCdevice_Unlock(context->Device); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0])); @@ -2341,7 +2341,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SetSourceState(source, context, AL_PLAYING); } } - UnlockContext(context); + ALCdevice_Unlock(context->Device); done: UnlockSourcesRead(context); @@ -2370,7 +2370,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - LockContext(context); + ALCdevice_Lock(context->Device); if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) { for(i = 0;i < n;i++) @@ -2387,7 +2387,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SetSourceState(source, context, AL_PAUSED); } } - UnlockContext(context); + ALCdevice_Unlock(context->Device); done: UnlockSourcesRead(context); @@ -2416,14 +2416,14 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - LockContext(context); + ALCdevice_Lock(context->Device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); source->new_state = AL_NONE; SetSourceState(source, context, AL_STOPPED); } - UnlockContext(context); + ALCdevice_Unlock(context->Device); done: UnlockSourcesRead(context); @@ -2452,14 +2452,14 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - LockContext(context); + ALCdevice_Lock(context->Device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); source->new_state = AL_NONE; SetSourceState(source, context, AL_INITIAL); } - UnlockContext(context); + ALCdevice_Unlock(context->Device); done: UnlockSourcesRead(context); -- cgit v1.2.3 From e92229f8395979591a14a980543d92aa4e7489c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 10 Feb 2017 06:20:16 -0800 Subject: Fix more uses of unsigned sizes and offsets --- Alc/ALu.c | 10 +++++----- Alc/bs2b.c | 8 ++++---- OpenAL32/Include/bs2b.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 67f61f07..29097c2a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1369,9 +1369,9 @@ static inline ALubyte aluF2UB(ALfloat val) #define DECL_TEMPLATE(T, func) \ static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - ALuint SamplesToDo, ALuint numchans) \ + ALsizei SamplesToDo, ALsizei numchans) \ { \ - ALuint i, j; \ + ALsizei i, j; \ for(j = 0;j < numchans;j++) \ { \ const ALfloat *in = InBuffer[j]; \ @@ -1394,7 +1394,7 @@ DECL_TEMPLATE(ALbyte, aluF2B) void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { - ALuint SamplesToDo; + ALsizei SamplesToDo; ALvoice *voice, *voice_end; ALeffectslot *slot; ALsource *source; @@ -1406,7 +1406,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { - SamplesToDo = minu(size, BUFFERSIZE); + SamplesToDo = mini(size, BUFFERSIZE); for(c = 0;c < device->Dry.NumChannels;c++) memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); if(device->Dry.Buffer != device->RealOut.Buffer) @@ -1559,7 +1559,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(buffer) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; - ALuint OutChannels = device->RealOut.NumChannels; + ALsizei OutChannels = device->RealOut.NumChannels; #define WRITE(T, a, b, c, d) do { \ Write_##T((a), (b), (c), (d)); \ diff --git a/Alc/bs2b.c b/Alc/bs2b.c index ddc2e2f2..e235e547 100644 --- a/Alc/bs2b.c +++ b/Alc/bs2b.c @@ -129,16 +129,16 @@ void bs2b_clear(struct bs2b *bs2b) memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); } /* bs2b_clear */ -void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo) +void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo) { float lsamples[128][2]; float rsamples[128][2]; - unsigned int base; + int base; for(base = 0;base < SamplesToDo;) { - unsigned int todo = minu(128, SamplesToDo-base); - unsigned int i; + int todo = mini(128, SamplesToDo-base); + int i; /* Process left input */ lsamples[0][0] = bs2b->a0_lo*Left[0] + diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h index bfe5c274..e845d906 100644 --- a/OpenAL32/Include/bs2b.h +++ b/OpenAL32/Include/bs2b.h @@ -85,7 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b); /* Clear buffer */ void bs2b_clear(struct bs2b *bs2b); -void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo); +void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo); #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3 From 6b030999cbde7cbd59752031ed696b7f9dd51969 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 11 Feb 2017 12:56:13 -0800 Subject: Don't require SDL_sound for alffplay Also explicitly link with libz for alffplay, since static ffmpeg libs need it. --- CMakeLists.txt | 107 +++++++++++++++++++++++++++---------------------- cmake/FindFFmpeg.cmake | 6 +++ 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 690ec37a..5de93610 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1438,54 +1438,62 @@ IF(ALSOFT_TESTS) ENDIF() IF(ALSOFT_EXAMPLES) - IF(SDL2_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 COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET ex-common APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - ADD_EXECUTABLE(alstream examples/alstream.c) - TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) - SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - ADD_EXECUTABLE(alreverb examples/alreverb.c) - TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) - SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - ADD_EXECUTABLE(allatency examples/allatency.c) - TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) - SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - ADD_EXECUTABLE(alloopback examples/alloopback.c) - TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + IF(SDL2_FOUND) + IF(SDL_SOUND_FOUND) + ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c + examples/common/sdl_sound.c) + SET_PROPERTY(TARGET ex-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET ex-common APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} + ) + + ADD_EXECUTABLE(alstream examples/alstream.c) + TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) + SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET alstream APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} + ) + + ADD_EXECUTABLE(alreverb examples/alreverb.c) + TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) + SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET alreverb APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} + ) + + ADD_EXECUTABLE(allatency examples/allatency.c) + TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) + SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET allatency APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} + ) + + ADD_EXECUTABLE(alloopback examples/alloopback.c) + TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} + common ${LIBNAME}) + SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET alloopback APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} + ) + + ADD_EXECUTABLE(alhrtf examples/alhrtf.c) + TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} common ${LIBNAME}) - SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - ADD_EXECUTABLE(alhrtf examples/alhrtf.c) - TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) - SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${SDL_SOUND_INCLUDE_DIR}) - - IF(ALSOFT_INSTALL) - INSTALL(TARGETS alstream alreverb allatency alloopback alhrtf - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET_PROPERTY(TARGET alhrtf APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) + + IF(ALSOFT_INSTALL) + INSTALL(TARGETS alstream alreverb allatency alloopback alhrtf + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + ENDIF() ENDIF() SET(FFVER_OK FALSE) @@ -1514,10 +1522,11 @@ IF(ALSOFT_EXAMPLES) ENDIF() IF(FFVER_OK AND NOT MSVC) ADD_EXECUTABLE(alffplay examples/alffplay.c) - TARGET_LINK_LIBRARIES(alffplay common ex-common ${SDL2_LIBRARY} ${LIBNAME} ${FFMPEG_LIBRARIES}) + TARGET_LINK_LIBRARIES(alffplay common ${SDL2_LIBRARY} ${LIBNAME} ${FFMPEG_LIBRARIES}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} - ${FFMPEG_INCLUDE_DIRS}) + SET_PROPERTY(TARGET alffplay APPEND PROPERTY + INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS} + ) IF(ALSOFT_INSTALL) INSTALL(TARGETS alffplay diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 96cbb6ed..c489c2c3 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -142,6 +142,12 @@ foreach(_component ${FFmpeg_FIND_COMPONENTS}) endif() endforeach() +# Add libz if it exists (needed for static ffmpeg builds) +find_library(_FFmpeg_HAVE_LIBZ NAMES z) +if(_FFmpeg_HAVE_LIBZ) + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${_FFmpeg_HAVE_LIBZ}) +endif() + # Build the include path and library list with duplicates removed. if(FFMPEG_INCLUDE_DIRS) list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) -- cgit v1.2.3 From 427f484e01eb09581dc5d3d0fb3f961c23916599 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Feb 2017 08:37:42 -0800 Subject: Print separate messages for building sdl_sound and ffmpeg examples --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5de93610..86c335be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1494,6 +1494,8 @@ IF(ALSOFT_EXAMPLES) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() + + MESSAGE(STATUS "Building SDL_sound example programs") ENDIF() SET(FFVER_OK FALSE) @@ -1535,9 +1537,7 @@ IF(ALSOFT_EXAMPLES) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ENDIF() - MESSAGE(STATUS "Building SDL and FFmpeg example programs") - ELSE() - MESSAGE(STATUS "Building SDL example programs") + MESSAGE(STATUS "Building SDL+FFmpeg example programs") ENDIF() MESSAGE(STATUS "") ENDIF() -- cgit v1.2.3 From 27695e2b24dea23d0db451fb0f9ae1c1af6f416e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Feb 2017 21:03:30 -0800 Subject: Add NEON-enhanced resamplers --- Alc/mixer.c | 16 ++++ Alc/mixer_defs.h | 22 ++++- Alc/mixer_neon.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+), 4 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 0ee1edd6..5442954e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -113,6 +113,10 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) case PointResampler: return Resample_point32_C; case LinearResampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_lerp32_Neon; +#endif #ifdef HAVE_SSE4_1 if((CPUCapFlags&CPU_CAP_SSE4_1)) return Resample_lerp32_SSE41; @@ -123,6 +127,10 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) #endif return Resample_lerp32_C; case FIR4Resampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_fir4_32_Neon; +#endif #ifdef HAVE_SSE4_1 if((CPUCapFlags&CPU_CAP_SSE4_1)) return Resample_fir4_32_SSE41; @@ -133,6 +141,10 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) #endif return Resample_fir4_32_C; case FIR8Resampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_fir8_32_Neon; +#endif #ifdef HAVE_SSE4_1 if((CPUCapFlags&CPU_CAP_SSE4_1)) return Resample_fir8_32_SSE41; @@ -143,6 +155,10 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) #endif return Resample_fir8_32_C; case BSincResampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_bsinc32_Neon; +#endif #ifdef HAVE_SSE if((CPUCapFlags&CPU_CAP_SSE)) return Resample_bsinc32_SSE; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 64da7680..4bafc839 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -67,10 +67,6 @@ inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restric } } -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen); - const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); @@ -92,6 +88,10 @@ const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *re ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen); + /* Neon mixers */ void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, @@ -108,4 +108,18 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); +/* Neon resamplers */ +const ALfloat *Resample_lerp32_Neon(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); +const ALfloat *Resample_fir4_32_Neon(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); +const ALfloat *Resample_fir8_32_Neon(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); +const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen); + #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 0fbcea67..75ad14eb 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -7,6 +7,266 @@ #include "alMain.h" #include "alu.h" #include "hrtf.h" +#include "mixer_defs.h" + + +#ifdef __GNUC__ +#define ASSUME_ALIGNED(ptr, ...) __builtin_assume_aligned((ptr), __VA_ARGS__) +#else +#define ASSUME_ALIGNED(ptr, ...) (ptr) +#endif + +const ALfloat *Resample_lerp32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); + const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); + alignas(16) ALint pos_[4]; + alignas(16) ALuint frac_[4]; + int32x4_t pos4; + uint32x4_t frac4; + ALsizei i; + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + + frac4 = vld1q_u32(frac_); + pos4 = vld1q_s32(pos_); + + for(i = 0;numsamples-i > 3;i += 4) + { + const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]}; + const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]}; + + /* val1 + (val2-val1)*mu */ + const float32x4_t r0 = vsubq_f32(val2, val1); + const float32x4_t mu = vmulq_f32(vcvtq_f32_u32(frac4), fracOne4); + const float32x4_t out = vmlaq_f32(val1, mu, r0); + + vst1q_f32(&dst[i], out); + + frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); + pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); + frac4 = vandq_u32(frac4, fracMask4); + + vst1q_s32(pos_, pos4); + } + + if(i < numsamples) + { + /* NOTE: These four elements represent the position *after* the last + * four samples, so the lowest element is the next position to + * resample. + */ + ALint pos = pos_[0]; + frac = vgetq_lane_u32(frac4, 0); + do { + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(++i < numsamples); + } + return dst; +} + +const ALfloat *Resample_fir4_32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); + alignas(16) ALint pos_[4]; + alignas(16) ALuint frac_[4]; + int32x4_t pos4; + uint32x4_t frac4; + ALsizei i; + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + + frac4 = vld1q_u32(frac_); + pos4 = vld1q_s32(pos_); + + --src; + for(i = 0;numsamples-i > 3;i += 4) + { + const float32x4_t val0 = vld1q_f32(&src[pos_[0]]); + const float32x4_t val1 = vld1q_f32(&src[pos_[1]]); + const float32x4_t val2 = vld1q_f32(&src[pos_[2]]); + const float32x4_t val3 = vld1q_f32(&src[pos_[3]]); + float32x4_t k0 = vld1q_f32(ResampleCoeffs.FIR4[frac_[0]]); + float32x4_t k1 = vld1q_f32(ResampleCoeffs.FIR4[frac_[1]]); + float32x4_t k2 = vld1q_f32(ResampleCoeffs.FIR4[frac_[2]]); + float32x4_t k3 = vld1q_f32(ResampleCoeffs.FIR4[frac_[3]]); + float32x4_t out; + + k0 = vmulq_f32(k0, val0); + k1 = vmulq_f32(k1, val1); + k2 = vmulq_f32(k2, val2); + k3 = vmulq_f32(k3, val3); + k0 = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), + vpadd_f32(vget_low_f32(k1), vget_high_f32(k1))); + k2 = vcombine_f32(vpadd_f32(vget_low_f32(k2), vget_high_f32(k2)), + vpadd_f32(vget_low_f32(k3), vget_high_f32(k3))); + out = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), + vpadd_f32(vget_low_f32(k2), vget_high_f32(k2))); + + vst1q_f32(&dst[i], out); + + frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); + pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); + frac4 = vandq_u32(frac4, fracMask4); + + vst1q_s32(pos_, pos4); + vst1q_u32(frac_, frac4); + } + + if(i < numsamples) + { + /* NOTE: These four elements represent the position *after* the last + * four samples, so the lowest element is the next position to + * resample. + */ + ALint pos = pos_[0]; + frac = frac_[0]; + do { + dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(++i < numsamples); + } + return dst; +} + +const ALfloat *Resample_fir8_32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); + alignas(16) ALint pos_[4]; + alignas(16) ALuint frac_[4]; + int32x4_t pos4; + uint32x4_t frac4; + ALsizei i, j; + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + + frac4 = vld1q_u32(frac_); + pos4 = vld1q_s32(pos_); + + src -= 3; + for(i = 0;numsamples-i > 3;i += 4) + { + float32x4_t out[2]; + for(j = 0;j < 8;j+=4) + { + const float32x4_t val0 = vld1q_f32(&src[pos_[0]+j]); + const float32x4_t val1 = vld1q_f32(&src[pos_[1]+j]); + const float32x4_t val2 = vld1q_f32(&src[pos_[2]+j]); + const float32x4_t val3 = vld1q_f32(&src[pos_[3]+j]); + float32x4_t k0 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[0]][j]); + float32x4_t k1 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[1]][j]); + float32x4_t k2 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[2]][j]); + float32x4_t k3 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[3]][j]); + + k0 = vmulq_f32(k0, val0); + k1 = vmulq_f32(k1, val1); + k2 = vmulq_f32(k2, val2); + k3 = vmulq_f32(k3, val3); + k0 = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), + vpadd_f32(vget_low_f32(k1), vget_high_f32(k1))); + k2 = vcombine_f32(vpadd_f32(vget_low_f32(k2), vget_high_f32(k2)), + vpadd_f32(vget_low_f32(k3), vget_high_f32(k3))); + out[j>>2] = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), + vpadd_f32(vget_low_f32(k2), vget_high_f32(k2))); + } + + out[0] = vaddq_f32(out[0], out[1]); + vst1q_f32(&dst[i], out[0]); + + frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); + pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); + frac4 = vandq_u32(frac4, fracMask4); + + vst1q_s32(pos_, pos4); + vst1q_u32(frac_, frac4); + } + + if(i < numsamples) + { + /* NOTE: These four elements represent the position *after* the last + * four samples, so the lowest element is the next position to + * resample. + */ + ALint pos = pos_[0]; + frac = frac_[0]; + do { + dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3], + src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(++i < numsamples); + } + return dst; +} + +const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *restrict src, + ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen) +{ + const float32x4_t sf4 = vdupq_n_f32(state->sf); + const ALsizei m = state->m; + const ALfloat *fil, *scd, *phd, *spd; + ALsizei pi, i, j; + float32x4_t r4; + ALfloat pf; + + src += state->l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<coeffs[pi].filter, 16); + scd = ASSUME_ALIGNED(state->coeffs[pi].scDelta, 16); + phd = ASSUME_ALIGNED(state->coeffs[pi].phDelta, 16); + spd = ASSUME_ALIGNED(state->coeffs[pi].spDelta, 16); + + // Apply the scale and phase interpolated filter. + r4 = vdupq_n_f32(0.0f); + { + const float32x4_t pf4 = vdupq_n_f32(pf); + for(j = 0;j < m;j+=4) + { + float32x4_t f4 = vmlaq_f32(vld1q_f32(&fil[j]), sf4, vld1q_f32(&scd[j])); + f4 = vmlaq_f32(f4, + pf4, vmlaq_f32(vld1q_f32(&phd[j]), + sf4, vld1q_f32(&spd[j]) + ) + ); + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); + } + } + r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), + vrev64_f32(vget_low_f32(r4)))); + dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], -- cgit v1.2.3 From 65f9b2792c50ae730a9f16680f931a9884e2b02c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Feb 2017 21:35:08 -0800 Subject: Clean up the bsinc mixer a bit --- Alc/mixer_c.c | 8 ++++---- Alc/mixer_neon.c | 4 ++-- Alc/mixer_sse.c | 42 ++++++++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 15c603ca..1284371b 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -62,10 +62,10 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri const ALfloat *fil, *scd, *phd, *spd; const ALfloat sf = state->sf; const ALsizei m = state->m; - const ALint l = state->l; - ALsizei j_s, j_f, pi, i; + ALsizei j_f, pi, i; ALfloat pf, r; + src += state->l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. @@ -81,9 +81,9 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri // Apply the scale and phase interpolated filter. r = 0.0f; - for(j_f = 0,j_s = l;j_f < m;j_f++,j_s++) + for(j_f = 0;j_f < m;j_f++) r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * - src[j_s]; + src[j_f]; dst[i] = r; frac += increment; diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 75ad14eb..2875b321 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -248,8 +248,8 @@ const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *res const float32x4_t pf4 = vdupq_n_f32(pf); for(j = 0;j < m;j+=4) { - float32x4_t f4 = vmlaq_f32(vld1q_f32(&fil[j]), sf4, vld1q_f32(&scd[j])); - f4 = vmlaq_f32(f4, + const float32x4_t f4 = vmlaq_f32(vmlaq_f32(vld1q_f32(&fil[j]), + sf4, vld1q_f32(&scd[j])), pf4, vmlaq_f32(vld1q_f32(&phd[j]), sf4, vld1q_f32(&spd[j]) ) diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 96228b47..25daf00b 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -12,18 +12,24 @@ #include "mixer_defs.h" +#ifdef __GNUC__ +#define ASSUME_ALIGNED(ptr, ...) __builtin_assume_aligned((ptr), __VA_ARGS__) +#else +#define ASSUME_ALIGNED(ptr, ...) (ptr) +#endif + const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { const __m128 sf4 = _mm_set1_ps(state->sf); const ALsizei m = state->m; - const ALint l = state->l; const ALfloat *fil, *scd, *phd, *spd; - ALsizei j_s, pi, j_f, i; + ALsizei pi, i, j; ALfloat pf; __m128 r4; + src += state->l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. @@ -32,32 +38,28 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest pf = (frac & ((1<coeffs[pi].filter; - scd = state->coeffs[pi].scDelta; - phd = state->coeffs[pi].phDelta; - spd = state->coeffs[pi].spDelta; + fil = ASSUME_ALIGNED(state->coeffs[pi].filter, 16); + scd = ASSUME_ALIGNED(state->coeffs[pi].scDelta, 16); + phd = ASSUME_ALIGNED(state->coeffs[pi].phDelta, 16); + spd = ASSUME_ALIGNED(state->coeffs[pi].spDelta, 16); // Apply the scale and phase interpolated filter. r4 = _mm_setzero_ps(); { const __m128 pf4 = _mm_set1_ps(pf); - for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4) +#define LD4(x) _mm_load_ps(x) +#define ULD4(x) _mm_loadu_ps(x) +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + for(j = 0;j < m;j+=4) { - const __m128 f4 = _mm_add_ps( - _mm_add_ps( - _mm_load_ps(&fil[j_f]), - _mm_mul_ps(sf4, _mm_load_ps(&scd[j_f])) - ), - _mm_mul_ps( - pf4, - _mm_add_ps( - _mm_load_ps(&phd[j_f]), - _mm_mul_ps(sf4, _mm_load_ps(&spd[j_f])) - ) - ) + const __m128 f4 = MLA4(MLA4(LD4(&fil[j]), sf4, LD4(&scd[j])), + pf4, MLA4(LD4(&phd[j]), sf4, LD4(&spd[j])) ); - r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s]))); + r4 = MLA4(r4, f4, ULD4(&src[j])); } +#undef MLA4 +#undef ULD4 +#undef LD4 } r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); -- cgit v1.2.3 From 841d0bb893e19dbe6f95bd80a3ac50997f9e8f0d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 13 Feb 2017 07:36:49 -0800 Subject: Porperly check for and use __builtin_assume_aligned --- Alc/mixer_neon.c | 19 +++++++++++++------ Alc/mixer_sse.c | 13 +++++++------ CMakeLists.txt | 13 +++++++++++++ config.h.in | 3 +++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 2875b321..533817ff 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -10,12 +10,6 @@ #include "mixer_defs.h" -#ifdef __GNUC__ -#define ASSUME_ALIGNED(ptr, ...) __builtin_assume_aligned((ptr), __VA_ARGS__) -#else -#define ASSUME_ALIGNED(ptr, ...) (ptr) -#endif - const ALfloat *Resample_lerp32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) @@ -248,12 +242,14 @@ const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *res const float32x4_t pf4 = vdupq_n_f32(pf); for(j = 0;j < m;j+=4) { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const float32x4_t f4 = vmlaq_f32(vmlaq_f32(vld1q_f32(&fil[j]), sf4, vld1q_f32(&scd[j])), pf4, vmlaq_f32(vld1q_f32(&phd[j]), sf4, vld1q_f32(&spd[j]) ) ); + /* r += f*src */ r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); } } @@ -283,6 +279,9 @@ static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2] leftright2 = vset_lane_f32(right, leftright2, 1); leftright4 = vcombine_f32(leftright2, leftright2); } + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); + CoeffStep = ASSUME_ALIGNED(CoeffStep, 16); for(c = 0;c < IrSize;c += 2) { const ALsizei o0 = (Offset+c)&HRIR_MASK; @@ -314,6 +313,8 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], leftright2 = vset_lane_f32(right, leftright2, 1); leftright4 = vcombine_f32(leftright2, leftright2); } + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); for(c = 0;c < IrSize;c += 2) { const ALsizei o0 = (Offset+c)&HRIR_MASK; @@ -343,6 +344,9 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe float32x4_t gain4; ALsizei c; + data = ASSUME_ALIGNED(data, 16); + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) @@ -412,6 +416,9 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restr float32x4_t gain4; ALsizei c; + data = ASSUME_ALIGNED(data, 16); + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); + for(c = 0;c < InChans;c++) { ALsizei pos = 0; diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 25daf00b..8aeb8211 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -12,12 +12,6 @@ #include "mixer_defs.h" -#ifdef __GNUC__ -#define ASSUME_ALIGNED(ptr, ...) __builtin_assume_aligned((ptr), __VA_ARGS__) -#else -#define ASSUME_ALIGNED(ptr, ...) (ptr) -#endif - const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) @@ -52,9 +46,11 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) for(j = 0;j < m;j+=4) { + /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const __m128 f4 = MLA4(MLA4(LD4(&fil[j]), sf4, LD4(&scd[j])), pf4, MLA4(LD4(&phd[j]), sf4, LD4(&spd[j])) ); + /* r += f*src */ r4 = MLA4(r4, f4, ULD4(&src[j])); } #undef MLA4 @@ -84,6 +80,9 @@ static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2] __m128 vals = _mm_setzero_ps(); ALsizei i; + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); + CoeffStep = ASSUME_ALIGNED(CoeffStep, 16); if((Offset&1)) { const ALsizei o0 = Offset&HRIR_MASK; @@ -145,6 +144,8 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], __m128 coeffs; ALsizei i; + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); if((Offset&1)) { const ALsizei o0 = Offset&HRIR_MASK; diff --git a/CMakeLists.txt b/CMakeLists.txt index 86c335be..7149351a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,6 +411,19 @@ ELSE() SET(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS}") ENDIF() +CHECK_C_SOURCE_COMPILES(" +int main() +{ + float *ptr; + ptr = __builtin_assume_aligned(ptr, 16); + return 0; +}" HAVE___BUILTIN_ASSUME_ALIGNED) +IF(HAVE___BUILTIN_ASSUME_ALIGNED) + SET(ASSUME_ALIGNED_DECL "__builtin_assume_aligned(x, y)") +ELSE() + SET(ASSUME_ALIGNED_DECL "x") +ENDIF() + SET(SSE_SWITCH "") SET(SSE2_SWITCH "") SET(SSE3_SWITCH "") diff --git a/config.h.in b/config.h.in index 4f22e5c8..d46c69ac 100644 --- a/config.h.in +++ b/config.h.in @@ -5,6 +5,9 @@ /* Define any available alignment declaration */ #define ALIGN(x) ${ALIGN_DECL} +/* Define a built-in call indicating an aligned data pointer */ +#define ASSUME_ALIGNED(x, y) ${ASSUME_ALIGNED_DECL} + /* Explicit hidden visibility attribute */ #define HIDDEN_DECL ${HIDDEN_DECL} -- cgit v1.2.3 From 0324712540f88d18f1fa8f18f7a72da06af00d75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 13 Feb 2017 11:29:32 -0800 Subject: Put BsincState in a generic union --- Alc/ALu.c | 4 ++-- Alc/mixer.c | 2 +- Alc/mixer_c.c | 20 ++++++++++---------- Alc/mixer_defs.h | 34 +++++++++++++++++----------------- Alc/mixer_neon.c | 38 +++++++++++++++++++------------------- Alc/mixer_sse.c | 16 ++++++++-------- Alc/mixer_sse2.c | 6 +++--- Alc/mixer_sse3.c | 12 ++++++------ Alc/mixer_sse41.c | 18 +++++++++--------- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 6 +++++- 11 files changed, 81 insertions(+), 77 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 29097c2a..42f229a2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -433,7 +433,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); - BsincPrepare(voice->Step, &voice->SincState); + BsincPrepare(voice->Step, &voice->ResampleState.bsinc); /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); @@ -1115,7 +1115,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); - BsincPrepare(voice->Step, &voice->SincState); + BsincPrepare(voice->Step, &voice->ResampleState.bsinc); if(Device->Render_Mode == HrtfRender) { diff --git a/Alc/mixer.c b/Alc/mixer.c index 5442954e..592d51d4 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -564,7 +564,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp ); /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample(&voice->SincState, + ResampledData = Resample(&voice->ResampleState, &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment, Device->ResampledData, DstBufferSize ); diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 1284371b..323f1363 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -18,7 +18,7 @@ static inline ALfloat fir8_32(const ALfloat *restrict vals, ALuint frac) { return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); } -const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), +const ALfloat *Resample_copy32_C(const InterpState* UNUSED(state), const ALfloat *restrict src, ALuint UNUSED(frac), ALint UNUSED(increment), ALfloat *restrict dst, ALsizei numsamples) { @@ -32,7 +32,7 @@ const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), } #define DECL_TEMPLATE(Sampler) \ -const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \ +const ALfloat *Resample_##Sampler##_C(const InterpState* UNUSED(state), \ const ALfloat *restrict src, ALuint frac, ALint increment, \ ALfloat *restrict dst, ALsizei numsamples) \ { \ @@ -55,17 +55,17 @@ DECL_TEMPLATE(fir8_32) #undef DECL_TEMPLATE -const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { const ALfloat *fil, *scd, *phd, *spd; - const ALfloat sf = state->sf; - const ALsizei m = state->m; + const ALfloat sf = state->bsinc.sf; + const ALsizei m = state->bsinc.m; ALsizei j_f, pi, i; ALfloat pf, r; - src += state->l; + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. @@ -74,10 +74,10 @@ const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restri pf = (frac & ((1<coeffs[pi].filter; - scd = state->coeffs[pi].scDelta; - phd = state->coeffs[pi].phDelta; - spd = state->coeffs[pi].spDelta; + fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16); + scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16); + phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16); + spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16); // Apply the scale and phase interpolated filter. r = 0.0f; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 4bafc839..60735c9f 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -12,12 +12,12 @@ struct MixHrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_copy32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_point32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_lerp32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_fir4_32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_fir8_32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); /* C mixers */ @@ -67,28 +67,28 @@ inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restric } } -const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_lerp32_SSE2(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_lerp32_SSE41(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir4_32_SSE3(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir4_32_SSE41(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir8_32_SSE3(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir8_32_SSE41(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); @@ -109,16 +109,16 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, ALsizei InPos, ALsizei BufferSize); /* Neon resamplers */ -const ALfloat *Resample_lerp32_Neon(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_lerp32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir4_32_Neon(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir4_32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir8_32_Neon(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_fir8_32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 533817ff..543ff0f3 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -10,9 +10,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); @@ -66,9 +66,9 @@ const ALfloat *Resample_lerp32_Neon(const BsincState* UNUSED(state), const ALflo return dst; } -const ALfloat *Resample_fir4_32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); @@ -136,9 +136,9 @@ const ALfloat *Resample_fir4_32_Neon(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_fir8_32_Neon(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir8_32_Neon(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); @@ -211,18 +211,18 @@ const ALfloat *Resample_fir8_32_Neon(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen) +const ALfloat *Resample_bsinc32_Neon(const InterpState *state, + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei dstlen) { - const float32x4_t sf4 = vdupq_n_f32(state->sf); - const ALsizei m = state->m; + const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); + const ALsizei m = state->bsinc.m; const ALfloat *fil, *scd, *phd, *spd; ALsizei pi, i, j; float32x4_t r4; ALfloat pf; - src += state->l; + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. @@ -231,10 +231,10 @@ const ALfloat *Resample_bsinc32_Neon(const BsincState *state, const ALfloat *res pf = (frac & ((1<coeffs[pi].filter, 16); - scd = ASSUME_ALIGNED(state->coeffs[pi].scDelta, 16); - phd = ASSUME_ALIGNED(state->coeffs[pi].phDelta, 16); - spd = ASSUME_ALIGNED(state->coeffs[pi].spDelta, 16); + fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16); + scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16); + phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16); + spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16); // Apply the scale and phase interpolated filter. r4 = vdupq_n_f32(0.0f); diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 8aeb8211..7870a6d8 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -12,18 +12,18 @@ #include "mixer_defs.h" -const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, +const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { - const __m128 sf4 = _mm_set1_ps(state->sf); - const ALsizei m = state->m; + const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); + const ALsizei m = state->bsinc.m; const ALfloat *fil, *scd, *phd, *spd; ALsizei pi, i, j; ALfloat pf; __m128 r4; - src += state->l; + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. @@ -32,10 +32,10 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest pf = (frac & ((1<coeffs[pi].filter, 16); - scd = ASSUME_ALIGNED(state->coeffs[pi].scDelta, 16); - phd = ASSUME_ALIGNED(state->coeffs[pi].phDelta, 16); - spd = ASSUME_ALIGNED(state->coeffs[pi].spDelta, 16); + fil = ASSUME_ALIGNED(state->bsinc.coeffs[pi].filter, 16); + scd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].scDelta, 16); + phd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].phDelta, 16); + spd = ASSUME_ALIGNED(state->bsinc.coeffs[pi].spDelta, 16); // Apply the scale and phase interpolated filter. r4 = _mm_setzero_ps(); diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index 5cf4c8a0..a1e8507e 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -27,9 +27,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_lerp32_SSE2(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 34121d71..3b444158 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -31,9 +31,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); @@ -96,9 +96,9 @@ const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir8_32_SSE3(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index a531ca77..7ae5bec7 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -28,9 +28,9 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_lerp32_SSE41(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); @@ -85,9 +85,9 @@ const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfl return dst; } -const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); @@ -153,9 +153,9 @@ const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALf return dst; } -const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples) +const ALfloat *Resample_fir8_32_SSE41(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALuint frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 4f04efe2..3111a48a 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -92,7 +92,7 @@ typedef struct ALvoice { alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; - BsincState SincState; + InterpState ResampleState; struct { ALfloat (*Buffer)[BUFFERSIZE]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 642fb944..c3c7a20c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -62,6 +62,10 @@ typedef struct BsincState { } coeffs[BSINC_PHASE_COUNT]; } BsincState; +typedef union InterpState { + BsincState bsinc; +} InterpState; + typedef union aluVector { alignas(16) ALfloat v[4]; @@ -148,7 +152,7 @@ typedef struct SendParams { } SendParams; -typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, +typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen ); -- cgit v1.2.3 From 0d19a209014582f1e77ab3b927dfb1af6c307d66 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 13 Feb 2017 21:18:18 -0800 Subject: Make the source state atomic Since it's modified by the mixer when playback is ended, a plain struct member isn't safe. --- Alc/ALc.c | 3 +-- Alc/ALu.c | 10 ++++++---- Alc/mixer.c | 2 +- OpenAL32/Include/alSource.h | 9 ++++++++- OpenAL32/alSource.c | 46 ++++++++++++++++++++------------------------- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fcc6d649..69e37540 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1697,8 +1697,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) ALsource *Source = context->SourceMap.values[pos]; ALenum new_state; - if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - Source->OffsetType != AL_NONE) + if(Source->OffsetType != AL_NONE && IsPlayingOrPaused(Source)) { WriteLock(&Source->queue_lock); ApplyOffset(Source); diff --git a/Alc/ALu.c b/Alc/ALu.c index 42f229a2..31dd6271 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1326,7 +1326,7 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) for(;voice != voice_end;++voice) { if(!(source=voice->Source)) continue; - if(source->state != AL_PLAYING && source->state != AL_PAUSED) + if(!IsPlayingOrPaused(source)) voice->Source = NULL; else CalcSourceParams(voice, ctx, force); @@ -1449,7 +1449,8 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALboolean IsVoiceInit = (voice->Step > 0); source = voice->Source; - if(source && source->state == AL_PLAYING && IsVoiceInit) + if(IsVoiceInit && source && + ATOMIC_LOAD(&source->state, almemory_order_relaxed) == AL_PLAYING) MixSource(voice, source, device, SamplesToDo); } @@ -1614,12 +1615,13 @@ void aluHandleDisconnect(ALCdevice *device) voice_end = voice + Context->VoiceCount; while(voice != voice_end) { + ALenum playing = AL_PLAYING; ALsource *source = voice->Source; voice->Source = NULL; - if(source && source->state == AL_PLAYING) + if(source && + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &source->state, &playing, AL_STOPPED)) { - source->state = AL_STOPPED; ATOMIC_STORE(&source->current_buffer, NULL, almemory_order_relaxed); ATOMIC_STORE(&source->position, 0, almemory_order_relaxed); ATOMIC_STORE(&source->position_fraction, 0, almemory_order_release); diff --git a/Alc/mixer.c b/Alc/mixer.c index 592d51d4..179c028e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -711,7 +711,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp voice->Moving = AL_TRUE; /* Update source info */ - Source->state = State; + ATOMIC_STORE(&Source->state, State, almemory_order_relaxed); ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed); ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed); ATOMIC_STORE(&Source->position_fraction, DataPosFrac, almemory_order_release); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 3111a48a..b9479905 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -175,7 +175,7 @@ typedef struct ALsource { ALint SourceType; /** Source state (initial, playing, paused, or stopped) */ - ALenum state; + ATOMIC(ALenum) state; ALenum new_state; /** Source Buffer Queue info. */ @@ -224,6 +224,13 @@ void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source); +inline ALboolean IsPlayingOrPaused(ALsource *source) +{ + ALenum state = ATOMIC_LOAD_SEQ(&source->state); + return state == AL_PLAYING || state == AL_PAUSED; +} + + ALvoid ReleaseALSources(ALCcontext *Context); #ifdef __cplusplus diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c60cd790..edcb49cd 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -46,6 +46,7 @@ extern inline void LockSourcesWrite(ALCcontext *context); extern inline void UnlockSourcesWrite(ALCcontext *context); extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); +extern inline ALboolean IsPlayingOrPaused(ALsource *source); static void InitSourceParams(ALsource *Source); static void DeinitSource(ALsource *source); @@ -524,7 +525,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + if(IsPlayingOrPaused(Source) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { ALCdevice_Lock(Context->Device); @@ -671,7 +672,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } WriteLock(&Source->queue_lock); - if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL)) + if(IsPlayingOrPaused(Source)) { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -725,7 +726,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + if(IsPlayingOrPaused(Source) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { ALCdevice_Lock(Context->Device); @@ -843,8 +844,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } UnlockFiltersRead(device); - if(slot != Source->Send[values[1]].Slot && - (Source->state == AL_PLAYING || Source->state == AL_PAUSED)) + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); @@ -1227,7 +1227,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_SOURCE_STATE: - *values = Source->state; + *values = ATOMIC_LOAD_SEQ(&Source->state); return AL_TRUE; case AL_BYTE_LENGTH_SOFT: @@ -2767,7 +2767,7 @@ static void InitSourceParams(ALsource *Source) Source->Offset = 0.0; Source->OffsetType = AL_NONE; Source->SourceType = AL_UNDETERMINED; - Source->state = AL_INITIAL; + ATOMIC_INIT(&Source->state, AL_INITIAL); Source->new_state = AL_NONE; ATOMIC_INIT(&Source->queue, NULL); @@ -2926,9 +2926,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = &context->Voices[pos]; ALsource *source = voice->Source; - if(source != NULL && (source->state == AL_PLAYING || - source->state == AL_PAUSED) && - source->NeedsUpdate) + if(source != NULL && source->NeedsUpdate && IsPlayingOrPaused(source)) { source->NeedsUpdate = AL_FALSE; UpdateSourceProps(source, num_sends); @@ -2963,19 +2961,15 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) BufferList = BufferList->next; } - if(Source->state != AL_PAUSED) + if(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel) == AL_PAUSED) + discontinuity = AL_FALSE; + else { - Source->state = AL_PLAYING; ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); discontinuity = AL_TRUE; } - else - { - Source->state = AL_PLAYING; - discontinuity = AL_FALSE; - } // Check if an Offset has been set if(Source->OffsetType != AL_NONE) @@ -3041,15 +3035,15 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } else if(state == AL_PAUSED) { - if(Source->state == AL_PLAYING) - Source->state = AL_PAUSED; + ALenum playing = AL_PLAYING; + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED); } else if(state == AL_STOPPED) { do_stop: - if(Source->state != AL_INITIAL) + if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) { - Source->state = AL_STOPPED; + ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); ATOMIC_STORE_SEQ(&Source->current_buffer, NULL); } Source->OffsetType = AL_NONE; @@ -3057,9 +3051,9 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } else if(state == AL_INITIAL) { - if(Source->state != AL_INITIAL) + if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) { - Source->state = AL_INITIAL; + ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue), almemory_order_relaxed); ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); @@ -3085,7 +3079,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint ALuint refcount; ReadLock(&Source->queue_lock); - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + if(!IsPlayingOrPaused(Source)) { ReadUnlock(&Source->queue_lock); do { @@ -3135,7 +3129,7 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 ALuint refcount; ReadLock(&Source->queue_lock); - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + if(!IsPlayingOrPaused(Source)) { ReadUnlock(&Source->queue_lock); do { @@ -3200,7 +3194,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ALuint refcount; ReadLock(&Source->queue_lock); - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + if(!IsPlayingOrPaused(Source)) { ReadUnlock(&Source->queue_lock); return 0.0; -- cgit v1.2.3 From 69dd57096183c4e381cc3f5c0a8ac4e33048b346 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 13 Feb 2017 21:30:20 -0800 Subject: Fix build with non-C11 atomics --- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index b9479905..d45e5d9c 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -224,7 +224,7 @@ void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source); -inline ALboolean IsPlayingOrPaused(ALsource *source) +inline ALboolean IsPlayingOrPaused(const ALsource *source) { ALenum state = ATOMIC_LOAD_SEQ(&source->state); return state == AL_PLAYING || state == AL_PAUSED; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index edcb49cd..036b7542 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -46,7 +46,7 @@ extern inline void LockSourcesWrite(ALCcontext *context); extern inline void UnlockSourcesWrite(ALCcontext *context); extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); -extern inline ALboolean IsPlayingOrPaused(ALsource *source); +extern inline ALboolean IsPlayingOrPaused(const ALsource *source); static void InitSourceParams(ALsource *Source); static void DeinitSource(ALsource *source); @@ -141,7 +141,7 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) { - return (source->state == AL_PLAYING || source->state == AL_PAUSED) && + return IsPlayingOrPaused(source) && !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); } -- cgit v1.2.3 From 5a50c46c22e7e6c5f119613584d826bc7b7b4a61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 14 Feb 2017 19:59:39 -0800 Subject: Make ALsourceProps' Send array dynamically sized ALsourceProps' Send[] array is placed at the end of the struct, and given an indeterminate size. Extra space is allocated at the end of each struct given the number of auxiliary sends set for the device. --- Alc/ALc.c | 99 ++++++++++++++++++++++++++++++++++++++++----- Alc/ALu.c | 22 +++++----- Alc/helpers.c | 1 + OpenAL32/Include/alMain.h | 9 +++++ OpenAL32/Include/alSource.h | 8 ++-- OpenAL32/alSource.c | 21 +++------- 6 files changed, 121 insertions(+), 39 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 69e37540..1028321e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1769,6 +1769,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCcontext *context; enum HrtfRequestMode hrtf_appreq = Hrtf_Default; enum HrtfRequestMode hrtf_userreq = Hrtf_Default; + ALsizei old_sends = device->NumAuxSends; enum DevFmtChannels oldChans; enum DevFmtType oldType; ALCuint oldFreq; @@ -2183,7 +2184,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALsizei pos; - ReadLock(&context->PropLock); + WriteLock(&context->PropLock); LockUIntMapRead(&context->EffectSlotMap); for(pos = 0;pos < context->EffectSlotMap.size;pos++) { @@ -2208,8 +2209,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(pos = 0;pos < context->SourceMap.size;pos++) { ALsource *source = context->SourceMap.values[pos]; - ALuint s = device->NumAuxSends; - while(s < MAX_SENDS) + struct ALsourceProps *props; + ALsizei s; + + for(s = device->NumAuxSends;s < MAX_SENDS;s++) { if(source->Send[s].Slot) DecrementRef(&source->Send[s].Slot->ref); @@ -2219,14 +2222,32 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) source->Send[s].HFReference = LOWPASSFREQREF; source->Send[s].GainLF = 1.0f; source->Send[s].LFReference = HIGHPASSFREQREF; - s++; } + source->NeedsUpdate = AL_TRUE; + + /* Clear any pre-existing source property structs, in case the + * number of auxiliary sends changed. Playing (or paused) sources + * will have updates specified. + */ + props = ATOMIC_EXCHANGE_SEQ(struct ALsourceProps*, &source->Update, NULL); + al_free(props); + + props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->FreeList, NULL, + almemory_order_relaxed); + while(props) + { + struct ALsourceProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + al_free(props); + props = next; + } } + AllocateVoices(context, context->MaxVoices, old_sends); UnlockUIntMapRead(&context->SourceMap); UpdateListenerProps(context); - ReadUnlock(&context->PropLock); + UpdateAllSourceProps(context); + WriteUnlock(&context->PropLock); context = context->next; } @@ -2595,6 +2616,65 @@ ALCcontext *GetContextRef(void) } +void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) +{ + ALCdevice *device = context->Device; + ALsizei num_sends = device->NumAuxSends; + struct ALsourceProps *props; + size_t sizeof_props; + ALvoice *voices; + ALsizei v = 0; + size_t size; + + if(num_voices == context->MaxVoices && num_sends == old_sends) + return; + + /* Allocate the voices, and the voices' stored source property set + * (including the dynamically-sized Send[] array) in one chunk. + */ + sizeof_props = RoundUp(offsetof(struct ALsourceProps, Send[num_sends]), 16); + size = sizeof(*voices) + sizeof_props; + + voices = al_calloc(16, size * num_voices); + props = (struct ALsourceProps*)(voices + num_voices); + + if(context->Voices) + { + ALsizei v_count = mini(context->VoiceCount, num_voices); + for(;v < v_count;v++) + { + ALsizei s_count = mini(old_sends, num_sends); + ALsizei i; + + /* Copy the old voice data and source property set to the new + * storage. + */ + voices[v] = context->Voices[v]; + *props = *(context->Voices[v].Props); + for(i = 0;i < s_count;i++) + props->Send[i] = context->Voices[v].Props->Send[i]; + + /* Set this voice's property set pointer and increment 'props' to + * the next property storage space. + */ + voices[v].Props = props; + props = (struct ALsourceProps*)((char*)props + sizeof_props); + } + } + /* Finish setting the voices' property set pointers. */ + for(;v < num_voices;v++) + { + voices[v].Props = props; + props = (struct ALsourceProps*)((char*)props + sizeof_props); + } + + al_free(context->Voices); + context->Voices = voices; + context->MaxVoices = num_voices; + context->VoiceCount = mini(context->VoiceCount, num_voices); +} + + /************************************************ * Standard ALC functions ************************************************/ @@ -3267,11 +3347,13 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin InitRef(&ALContext->ref, 1); ALContext->Listener = (ALlistener*)ALContext->_listener_mem; + ALContext->Device = device; ATOMIC_INIT(&ALContext->ActiveAuxSlotList, NULL); + ALContext->Voices = NULL; + ALContext->MaxVoices = 0; ALContext->VoiceCount = 0; - ALContext->MaxVoices = 256; - ALContext->Voices = al_calloc(16, ALContext->MaxVoices * sizeof(ALContext->Voices[0])); + AllocateVoices(ALContext, 256, device->NumAuxSends); } if(!ALContext || !ALContext->Voices) { @@ -3312,8 +3394,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin return NULL; } - ALContext->Device = device; - ALCdevice_IncRef(device); + ALCdevice_IncRef(ALContext->Device); InitContext(ALContext); if(ConfigValueFloat(al_string_get_cstr(device->DeviceName), NULL, "volume-adjust", &valf)) diff --git a/Alc/ALu.c b/Alc/ALu.c index 31dd6271..3cb02f84 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -807,14 +807,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro ALint NumSends; ALint i; - DryGainHF = 1.0f; - DryGainLF = 1.0f; - for(i = 0;i < MAX_SENDS;i++) - { - WetGainHF[i] = 1.0f; - WetGainLF[i] = 1.0f; - } - /* Get context/device properties */ DopplerFactor = Listener->Params.DopplerFactor; SpeedOfSound = Listener->Params.SpeedOfSound; @@ -989,8 +981,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Source Gain + Attenuation */ DryGain = SourceVolume * Attenuation; + DryGainHF = 1.0f; + DryGainLF = 1.0f; for(i = 0;i < NumSends;i++) + { WetGain[i] = SourceVolume * RoomAttenuation[i]; + WetGainHF[i] = 1.0f; + WetGainLF[i] = 1.0f; + } /* Distance-based air absorption */ if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) @@ -1284,7 +1282,9 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc if(props) { - voice->Props = *props; + memcpy(voice->Props, props, + offsetof(struct ALsourceProps, Send[context->Device->NumAuxSends]) + ); ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props); } @@ -1296,9 +1296,9 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc if((buffer=BufferListItem->buffer) != NULL) { if(buffer->FmtChannels == FmtMono) - CalcAttnSourceParams(voice, &voice->Props, buffer, context); + CalcAttnSourceParams(voice, voice->Props, buffer, context); else - CalcNonAttnSourceParams(voice, &voice->Props, buffer, context); + CalcNonAttnSourceParams(voice, voice->Props, buffer, context); break; } BufferListItem = BufferListItem->next; diff --git a/Alc/helpers.c b/Alc/helpers.c index eac3811d..1ce567b2 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -112,6 +112,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x extern inline ALuint NextPowerOf2(ALuint value); +extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); extern inline ALuint fastf2u(ALfloat f); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2573c836..947a16ba 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -356,6 +356,13 @@ inline ALuint NextPowerOf2(ALuint value) return value+1; } +/** Round up a value to the next multiple. */ +inline size_t RoundUp(size_t value, size_t r) +{ + value += r-1; + return value - (value%r); +} + /* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero * mode. */ inline ALint fastf2i(ALfloat f) @@ -813,6 +820,8 @@ ALCcontext *GetContextRef(void); void ALCcontext_IncRef(ALCcontext *context); void ALCcontext_DecRef(ALCcontext *context); +void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); + void AppendAllDevicesList(const ALCchar *name); void AppendCaptureDeviceList(const ALCchar *name); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index d45e5d9c..cc9dd763 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -23,6 +23,8 @@ typedef struct ALbufferlistitem { struct ALsourceProps { + ATOMIC(struct ALsourceProps*) next; + ATOMIC(ALfloat) Pitch; ATOMIC(ALfloat) Gain; ATOMIC(ALfloat) OuterGain; @@ -69,14 +71,12 @@ struct ALsourceProps { ATOMIC(ALfloat) HFReference; ATOMIC(ALfloat) GainLF; ATOMIC(ALfloat) LFReference; - } Send[MAX_SENDS]; - - ATOMIC(struct ALsourceProps*) next; + } Send[]; }; typedef struct ALvoice { - struct ALsourceProps Props; + struct ALsourceProps *Props; struct ALsource *Source; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 036b7542..56d2b415 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2306,23 +2306,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ALCdevice_Lock(context->Device); while(n > context->MaxVoices-context->VoiceCount) { - ALvoice *temp = NULL; - ALsizei newcount; - - newcount = context->MaxVoices << 1; - if(newcount > 0) - temp = al_malloc(16, newcount * sizeof(context->Voices[0])); - if(!temp) + ALsizei newcount = context->MaxVoices << 1; + if(context->MaxVoices >= newcount) { ALCdevice_Unlock(context->Device); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } - memcpy(temp, context->Voices, context->MaxVoices * sizeof(temp[0])); - memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0])); - - al_free(context->Voices); - context->Voices = temp; - context->MaxVoices = newcount; + AllocateVoices(context, newcount, context->Device->NumAuxSends); } if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) @@ -2757,6 +2747,7 @@ static void InitSourceParams(ALsource *Source) Source->Direct.LFReference = HIGHPASSFREQREF; for(i = 0;i < MAX_SENDS;i++) { + Source->Send[i].Slot = NULL; Source->Send[i].Gain = 1.0f; Source->Send[i].GainHF = 1.0f; Source->Send[i].HFReference = LOWPASSFREQREF; @@ -2819,7 +2810,7 @@ static void DeinitSource(ALsource *source) BufferList = next; } - for(i = 0;i < MAX_SENDS;++i) + for(i = 0;i < MAX_SENDS;i++) { if(source->Send[i].Slot) DecrementRef(&source->Send[i].Slot->ref); @@ -2835,7 +2826,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) /* Get an unused property container, or allocate a new one as needed. */ props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); if(!props) - props = al_calloc(16, sizeof(*props)); + props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends])); else { struct ALsourceProps *next; -- cgit v1.2.3 From 909193a345469529ec98b8b01379738facee861d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 15 Feb 2017 17:40:26 -0800 Subject: Reorganize ALvoice members This places the Send[] array at the end of the struct, making it easier to handle dynamically. --- Alc/ALu.c | 168 +++++++++++++++++++++++--------------------- Alc/mixer.c | 15 ++-- OpenAL32/Include/alSource.h | 13 ++-- OpenAL32/alSource.c | 6 +- 4 files changed, 104 insertions(+), 98 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3cb02f84..d5065199 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -407,8 +407,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * StereoMap[0].angle = -ATOMIC_LOAD(&props->StereoPan[0], almemory_order_relaxed); StereoMap[1].angle = -ATOMIC_LOAD(&props->StereoPan[1], almemory_order_relaxed); - voice->DirectOut.Buffer = Device->Dry.Buffer; - voice->DirectOut.Channels = Device->Dry.NumChannels; + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); @@ -417,13 +417,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) { SendSlots[i] = NULL; - voice->SendOut[i].Buffer = NULL; - voice->SendOut[i].Channels = 0; + voice->Send[i].Buffer = NULL; + voice->Send[i].Channels = 0; } else { - voice->SendOut[i].Buffer = SendSlots[i]->WetBuffer; - voice->SendOut[i].Channels = SendSlots[i]->NumChannels; + voice->Send[i].Buffer = SendSlots[i]->WetBuffer; + voice->Send[i].Channels = SendSlots[i]->NumChannels; } } @@ -534,11 +534,11 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale ); - voice->DirectOut.Buffer = Device->FOAOut.Buffer; - voice->DirectOut.Channels = Device->FOAOut.NumChannels; + voice->Direct.Buffer = Device->FOAOut.Buffer; + voice->Direct.Channels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, - voice->Chan[c].Direct.Gains.Target); + voice->Direct.Params[c].Gains.Target); for(i = 0;i < NumSends;i++) { @@ -547,7 +547,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(c = 0;c < num_channels;c++) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } else @@ -555,8 +555,9 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(c = 0;c < num_channels;c++) { const ALeffectslot *Slot = SendSlots[i]; - ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], - WetGain[i], voice->Chan[c].Send[i].Gains.Target); + ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, + matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target + ); } } } @@ -570,15 +571,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(DirectChannels) { /* Skip the virtual channels and write inputs to the real output. */ - voice->DirectOut.Buffer = Device->RealOut.Buffer; - voice->DirectOut.Channels = Device->RealOut.NumChannels; + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Chan[c].Direct.Gains.Target[j] = 0.0f; + voice->Direct.Params[c].Gains.Target[j] = 0.0f; if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Chan[c].Direct.Gains.Target[idx] = DryGain; + voice->Direct.Params[c].Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal panning since they mix to B-Format, which can't @@ -592,13 +593,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Chan[c].Send[i].Gains.Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); } } } @@ -610,25 +612,25 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Full HRTF rendering. Skip the virtual channels and render each * input channel to the real outputs. */ - voice->DirectOut.Buffer = Device->RealOut.Buffer; - voice->DirectOut.Channels = Device->RealOut.NumChannels; + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; for(c = 0;c < num_channels;c++) { if(chans[c].channel == LFE) { /* Skip LFE */ - voice->Chan[c].Direct.Hrtf.Target.Delay[0] = 0; - voice->Chan[c].Direct.Hrtf.Target.Delay[1] = 0; + voice->Direct.Params[c].Hrtf.Target.Delay[0] = 0; + voice->Direct.Params[c].Hrtf.Target.Delay[1] = 0; for(i = 0;i < HRIR_LENGTH;i++) { - voice->Chan[c].Direct.Hrtf.Target.Coeffs[i][0] = 0.0f; - voice->Chan[c].Direct.Hrtf.Target.Coeffs[i][1] = 0.0f; + voice->Direct.Params[c].Hrtf.Target.Coeffs[i][0] = 0.0f; + voice->Direct.Params[c].Hrtf.Target.Coeffs[i][1] = 0.0f; } for(i = 0;i < NumSends;i++) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } continue; @@ -637,8 +639,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Get the static HRIR coefficients and delays for this channel. */ GetHrtfCoeffs(Device->Hrtf.Handle, chans[c].elevation, chans[c].angle, 0.0f, DryGain, - voice->Chan[c].Direct.Hrtf.Target.Coeffs, - voice->Chan[c].Direct.Hrtf.Target.Delay + voice->Direct.Params[c].Hrtf.Target.Coeffs, + voice->Direct.Params[c].Hrtf.Target.Delay ); /* Normal panning for auxiliary sends. */ @@ -649,13 +651,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(!SendSlots[i]) { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Chan[c].Send[i].Gains.Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); } } } @@ -671,19 +674,19 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(chans[c].channel == LFE) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Chan[c].Direct.Gains.Target[j] = 0.0f; + voice->Direct.Params[c].Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx; if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Chan[c].Direct.Gains.Target[idx] = DryGain; + voice->Direct.Params[c].Gains.Target[idx] = DryGain; } for(i = 0;i < NumSends;i++) { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Direct.Params[c].Gains.Target[j] = 0.0f; } continue; } @@ -693,10 +696,10 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f; - voice->Chan[c].Direct.Gains.Target[0] = coeffs[0] * DryGain; - voice->Chan[c].Direct.Gains.Target[1] = (1.0f-coeffs[0]) * DryGain; + voice->Direct.Params[c].Gains.Target[0] = coeffs[0] * DryGain; + voice->Direct.Params[c].Gains.Target[1] = (1.0f-coeffs[0]) * DryGain; for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) - voice->Chan[c].Direct.Gains.Target[j] = 0.0f; + voice->Direct.Params[c].Gains.Target[j] = 0.0f; CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); } @@ -704,7 +707,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, DryGain, - voice->Chan[c].Direct.Gains.Target); + voice->Direct.Params[c].Gains.Target); } for(i = 0;i < NumSends;i++) @@ -713,13 +716,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[c].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Chan[c].Send[i].Gains.Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); } } } @@ -737,15 +741,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * DryGainLF = maxf(DryGainLF, 0.0001f); for(c = 0;c < num_channels;c++) { - voice->Chan[c].Direct.FilterType = AF_None; - if(DryGainHF != 1.0f) voice->Chan[c].Direct.FilterType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Chan[c].Direct.FilterType |= AF_HighPass; + voice->Direct.Params[c].FilterType = AF_None; + if(DryGainHF != 1.0f) voice->Direct.Params[c].FilterType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Chan[c].Direct.LowPass, ALfilterType_HighShelf, + &voice->Direct.Params[c].LowPass, ALfilterType_HighShelf, DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Chan[c].Direct.HighPass, ALfilterType_LowShelf, + &voice->Direct.Params[c].HighPass, ALfilterType_LowShelf, DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } @@ -760,15 +764,15 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); for(c = 0;c < num_channels;c++) { - voice->Chan[c].Send[i].FilterType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Chan[c].Send[i].FilterType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Chan[c].Send[i].FilterType |= AF_HighPass; + voice->Send[i].Params[c].FilterType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Chan[c].Send[i].LowPass, ALfilterType_HighShelf, + &voice->Send[i].Params[c].LowPass, ALfilterType_HighShelf, WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Chan[c].Send[i].HighPass, ALfilterType_LowShelf, + &voice->Send[i].Params[c].HighPass, ALfilterType_LowShelf, WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } @@ -846,8 +850,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro WetGainHFAuto = ATOMIC_LOAD(&props->WetGainHFAuto, almemory_order_relaxed); RoomRolloffBase = ATOMIC_LOAD(&props->RoomRolloffFactor, almemory_order_relaxed); - voice->DirectOut.Buffer = Device->Dry.Buffer; - voice->DirectOut.Channels = Device->Dry.NumChannels; + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); @@ -879,13 +883,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(!SendSlots[i]) { - voice->SendOut[i].Buffer = NULL; - voice->SendOut[i].Channels = 0; + voice->Send[i].Buffer = NULL; + voice->Send[i].Channels = 0; } else { - voice->SendOut[i].Buffer = SendSlots[i]->WetBuffer; - voice->SendOut[i].Channels = SendSlots[i]->NumChannels; + voice->Send[i].Buffer = SendSlots[i]->WetBuffer; + voice->Send[i].Channels = SendSlots[i]->NumChannels; } } @@ -1126,8 +1130,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat spread = 0.0f; - voice->DirectOut.Buffer = Device->RealOut.Buffer; - voice->DirectOut.Channels = Device->RealOut.NumChannels; + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; if(Distance > FLT_EPSILON) { @@ -1149,8 +1153,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Get the HRIR coefficients and delays. */ GetHrtfCoeffs(Device->Hrtf.Handle, ev, az, spread, DryGain, - voice->Chan[0].Direct.Hrtf.Target.Coeffs, - voice->Chan[0].Direct.Hrtf.Target.Delay); + voice->Direct.Params[0].Hrtf.Target.Coeffs, + voice->Direct.Params[0].Hrtf.Target.Delay); CalcDirectionCoeffs(dir, spread, coeffs); @@ -1160,13 +1164,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[0].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Chan[0].Send[i].Gains.Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target + ); } } @@ -1197,10 +1202,10 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f)); x = clampf(x, -0.5f, 0.5f) + 0.5f; - voice->Chan[0].Direct.Gains.Target[0] = x * DryGain; - voice->Chan[0].Direct.Gains.Target[1] = (1.0f-x) * DryGain; + voice->Direct.Params[0].Gains.Target[0] = x * DryGain; + voice->Direct.Params[0].Gains.Target[1] = (1.0f-x) * DryGain; for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) - voice->Chan[0].Direct.Gains.Target[i] = 0.0f; + voice->Direct.Params[0].Gains.Target[i] = 0.0f; CalcDirectionCoeffs(dir, spread, coeffs); } @@ -1208,7 +1213,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { CalcDirectionCoeffs(dir, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, DryGain, - voice->Chan[0].Direct.Gains.Target); + voice->Direct.Params[0].Gains.Target); } for(i = 0;i < NumSends;i++) @@ -1217,13 +1222,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Chan[0].Send[i].Gains.Target[j] = 0.0f; + voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } else { const ALeffectslot *Slot = SendSlots[i]; - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, - WetGain[i], voice->Chan[0].Send[i].Gains.Target); + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target + ); } } @@ -1237,15 +1243,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Frequency; DryGainHF = maxf(DryGainHF, 0.0001f); DryGainLF = maxf(DryGainLF, 0.0001f); - voice->Chan[0].Direct.FilterType = AF_None; - if(DryGainHF != 1.0f) voice->Chan[0].Direct.FilterType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Chan[0].Direct.FilterType |= AF_HighPass; + voice->Direct.Params[0].FilterType = AF_None; + if(DryGainHF != 1.0f) voice->Direct.Params[0].FilterType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Chan[0].Direct.LowPass, ALfilterType_HighShelf, + &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Chan[0].Direct.HighPass, ALfilterType_LowShelf, + &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } @@ -1257,15 +1263,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); - voice->Chan[0].Send[i].FilterType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Chan[0].Send[i].FilterType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Chan[0].Send[i].FilterType |= AF_HighPass; + voice->Send[i].Params[0].FilterType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( - &voice->Chan[0].Send[i].LowPass, ALfilterType_HighShelf, + &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Chan[0].Send[i].HighPass, ALfilterType_LowShelf, + &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } diff --git a/Alc/mixer.c b/Alc/mixer.c index 179c028e..d5cf30cc 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -569,7 +569,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp Device->ResampledData, DstBufferSize ); { - DirectParams *parms = &voice->Chan[chan].Direct; + DirectParams *parms = &voice->Direct.Params[chan]; const ALfloat *samples; samples = DoFilters( @@ -581,8 +581,9 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp if(!Counter) memcpy(parms->Gains.Current, parms->Gains.Target, sizeof(parms->Gains.Current)); - MixSamples(samples, voice->DirectOut.Channels, voice->DirectOut.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize + MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize ); } else @@ -626,7 +627,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp assert(lidx != -1 && ridx != -1); MixHrtfSamples( - voice->DirectOut.Buffer[lidx], voice->DirectOut.Buffer[ridx], + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, &parms->Hrtf.State, DstBufferSize ); @@ -635,10 +636,10 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp for(send = 0;send < Device->NumAuxSends;send++) { - SendParams *parms = &voice->Chan[chan].Send[send]; + SendParams *parms = &voice->Send[send].Params[chan]; const ALfloat *samples; - if(!voice->SendOut[send].Buffer) + if(!voice->Send[send].Buffer) continue; samples = DoFilters( @@ -649,7 +650,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp if(!Counter) memcpy(parms->Gains.Current, parms->Gains.Target, sizeof(parms->Gains.Current)); - MixSamples(samples, voice->SendOut[send].Channels, voice->SendOut[send].Buffer, + MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index cc9dd763..c63aef70 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -95,19 +95,18 @@ typedef struct ALvoice { InterpState ResampleState; struct { + DirectParams Params[MAX_INPUT_CHANNELS]; + ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; - } DirectOut; + } Direct; struct { + SendParams Params[MAX_INPUT_CHANNELS]; + ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; - } SendOut[MAX_SENDS]; - - struct { - DirectParams Direct; - SendParams Send[MAX_SENDS]; - } Chan[MAX_INPUT_CHANNELS]; + } Send[MAX_SENDS]; } ALvoice; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 56d2b415..395bc8c2 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3013,11 +3013,11 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALsizei j; for(j = 0;j < HRTF_HISTORY_LENGTH;j++) - voice->Chan[i].Direct.Hrtf.State.History[j] = 0.0f; + voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f; for(j = 0;j < HRIR_LENGTH;j++) { - voice->Chan[i].Direct.Hrtf.State.Values[j][0] = 0.0f; - voice->Chan[i].Direct.Hrtf.State.Values[j][1] = 0.0f; + voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f; + voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f; } } -- cgit v1.2.3 From d8c42918f46e2439c81c4d4562df8fa7ad2e01fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 18 Feb 2017 15:58:15 -0800 Subject: Use select() to wait for audio with OSS and Solaris --- Alc/backends/oss.c | 146 +++++++++++++++++++++++++++++-------------------- Alc/backends/solaris.c | 76 ++++++++++++++++--------- 2 files changed, 137 insertions(+), 85 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 2da096f6..8934181b 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -269,42 +269,64 @@ static int ALCplaybackOSS_mixerProc(void *ptr) { ALCplaybackOSS *self = (ALCplaybackOSS*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALint frameSize; + struct timeval timeout; + ALubyte *write_ptr; + ALint frame_size; + ALint to_write; ssize_t wrote; + fd_set wfds; + int sret; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + ALCplaybackOSS_lock(self); while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) { - ALint len = self->data_size; - ALubyte *WritePtr = self->mix_data; + FD_ZERO(&wfds); + FD_SET(self->fd, &wfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + ALCplaybackOSS_unlock(self); + sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); + ALCplaybackOSS_lock(self); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } - aluMixData(device, WritePtr, len/frameSize); - while(len > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) + write_ptr = self->mix_data; + to_write = self->data_size; + aluMixData(device, write_ptr, to_write/frame_size); + while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) { - wrote = write(self->fd, WritePtr, len); + wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) { - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - { - ERR("write failed: %s\n", strerror(errno)); - ALCplaybackOSS_lock(self); - aluHandleDisconnect(device); - ALCplaybackOSS_unlock(self); - break; - } - - al_nssleep(1000000); - continue; + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; } - len -= wrote; - WritePtr += wrote; + to_write -= wrote; + write_ptr += wrote; } } + ALCplaybackOSS_unlock(self); return 0; } @@ -492,7 +514,6 @@ typedef struct ALCcaptureOSS { int fd; ll_ringbuffer_t *ring; - ATOMIC(ALenum) doCapture; ATOMIC(ALenum) killNow; althrd_t thread; @@ -520,41 +541,55 @@ static int ALCcaptureOSS_recordProc(void *ptr) { ALCcaptureOSS *self = (ALCcaptureOSS*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - int frameSize; + struct timeval timeout; + int frame_size; + fd_set rfds; ssize_t amt; + int sret; SetRTPriority(); althrd_setname(althrd_current(), RECORD_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); while(!ATOMIC_LOAD_SEQ(&self->killNow)) { ll_ringbuffer_data_t vec[2]; - amt = 0; - if(ATOMIC_LOAD_SEQ(&self->doCapture)) + FD_ZERO(&rfds); + FD_SET(self->fd, &rfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + sret = select(self->fd+1, &rfds, NULL, NULL, &timeout); + if(sret < 0) { - ll_ringbuffer_get_write_vector(self->ring, vec); - if(vec[0].len > 0) - { - amt = read(self->fd, vec[0].buf, vec[0].len*frameSize); - if(amt < 0) - { - ERR("read failed: %s\n", strerror(errno)); - ALCcaptureOSS_lock(self); - aluHandleDisconnect(device); - ALCcaptureOSS_unlock(self); - break; - } - ll_ringbuffer_write_advance(self->ring, amt/frameSize); - } + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; } - if(amt == 0) + else if(sret == 0) { - al_nssleep(1000000); + WARN("select timeout\n"); continue; } + + ll_ringbuffer_get_write_vector(self->ring, vec); + if(vec[0].len > 0) + { + amt = read(self->fd, vec[0].buf, vec[0].len*frame_size); + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + ALCcaptureOSS_lock(self); + aluHandleDisconnect(device); + ALCcaptureOSS_unlock(self); + break; + } + ll_ringbuffer_write_advance(self->ring, amt/frame_size); + } } return 0; @@ -566,7 +601,6 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); - ATOMIC_INIT(&self->doCapture, AL_FALSE); ATOMIC_INIT(&self->killNow, AL_FALSE); } @@ -690,15 +724,6 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) - { - ll_ringbuffer_free(self->ring); - self->ring = NULL; - close(self->fd); - self->fd = -1; - return ALC_OUT_OF_MEMORY; - } - al_string_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; @@ -706,11 +731,6 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) static void ALCcaptureOSS_close(ALCcaptureOSS *self) { - int res; - - ATOMIC_STORE_SEQ(&self->killNow, AL_TRUE); - althrd_join(self->thread, &res); - close(self->fd); self->fd = -1; @@ -720,13 +740,23 @@ static void ALCcaptureOSS_close(ALCcaptureOSS *self) static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { - ATOMIC_STORE_SEQ(&self->doCapture, AL_TRUE); + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); + if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success) + return ALC_FALSE; return ALC_TRUE; } static void ALCcaptureOSS_stop(ALCcaptureOSS *self) { - ATOMIC_STORE_SEQ(&self->doCapture, AL_FALSE); + int res; + + if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE)) + return; + + althrd_join(self->thread, &res); + + if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0) + ERR("Error resetting device: %s\n", strerror(errno)); } static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples) diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 792f717a..c70e0b46 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -50,7 +50,7 @@ typedef struct ALCsolarisBackend { ALubyte *mix_data; int data_size; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCsolarisBackend; @@ -84,6 +84,7 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); self->fd = -1; + ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) @@ -103,43 +104,65 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) static int ALCsolarisBackend_mixerProc(void *ptr) { ALCsolarisBackend *self = ptr; - ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice; - ALint frameSize; - int wrote; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timeval timeout; + ALubyte *write_ptr; + ALint frame_size; + ALint to_write; + ssize_t wrote; + fd_set wfds; + int sret; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - while(!self->killNow && Device->Connected) + ALCsolarisBackend_lock(self); + while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) { - ALint len = self->data_size; - ALubyte *WritePtr = self->mix_data; + FD_ZERO(&wfds); + FD_SET(self->fd, &wfds); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + ALCsolarisBackend_unlock(self); + sret = select(self->fd+1, NULL, &wfds, NULL, &timeout); + ALCsolarisBackend_lock(self); + if(sret < 0) + { + if(errno == EINTR) + continue; + ERR("select failed: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; + } + else if(sret == 0) + { + WARN("select timeout\n"); + continue; + } - aluMixData(Device, WritePtr, len/frameSize); - while(len > 0 && !self->killNow) + write_ptr = self->mix_data; + to_write = self->data_size; + aluMixData(device, write_ptr, to_write/frame_size); + while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow)) { - wrote = write(self->fd, WritePtr, len); + wrote = write(self->fd, write_ptr, to_write); if(wrote < 0) { - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - { - ERR("write failed: %s\n", strerror(errno)); - ALCsolarisBackend_lock(self); - aluHandleDisconnect(Device); - ALCsolarisBackend_unlock(self); - break; - } - - al_nssleep(1000000); - continue; + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; + ERR("write failed: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; } - len -= wrote; - WritePtr += wrote; + to_write -= wrote; + write_ptr += wrote; } } + ALCsolarisBackend_unlock(self); return 0; } @@ -250,7 +273,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) { - self->killNow = 0; + ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) return ALC_FALSE; return ALC_TRUE; @@ -260,10 +283,9 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE_SEQ(int, &self->killNow, AL_TRUE)) return; - self->killNow = 1; althrd_join(self->thread, &res); if(ioctl(self->fd, AUDIO_DRAIN) < 0) -- cgit v1.2.3 From 2448f88e70f6207ad5743f0a55eaa5de7cbce737 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 18 Feb 2017 16:55:48 -0800 Subject: Return some device latency by default A device will never have 0 latency. OpenAL Soft itself uses a sample buffer length of UpdateSize*NumUpdates, and during playback will have about (NumUpdates-1) periods filled, more or less. Without a more accurate measurement from the playback system, this is better than reporting 0. --- Alc/backends/base.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Alc/backends/base.c b/Alc/backends/base.c index ff808f53..e4305653 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -4,6 +4,7 @@ #include #include "alMain.h" +#include "alu.h" #include "backends/base.h" @@ -45,8 +46,12 @@ ClockLatency ALCbackend_getClockLatency(ALCbackend *self) almtx_lock(&self->mMutex); ret.ClockTime = GetDeviceClockTime(device); - // TODO: Perhaps should be NumUpdates-1 worth of UpdateSize? - ret.Latency = 0; + /* NOTE: The device will generally have about all but one periods filled at + * any given time during playback. Without a more accurate measurement from + * the output, this is an okay approximation. + */ + ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency * + maxu(device->NumUpdates-1, 1); almtx_unlock(&self->mMutex); return ret; -- cgit v1.2.3 From 247f56249ade334f8f7ef9eda9c380af0278562f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 18 Feb 2017 17:32:07 -0800 Subject: Always lock the device backend before calling aluMixData --- Alc/ALc.c | 4 +++ Alc/ALu.c | 2 -- Alc/backends/coreaudio.c | 2 ++ Alc/backends/dsound.c | 2 ++ Alc/backends/mmdevapi.c | 4 +-- Alc/backends/null.c | 2 ++ Alc/backends/portaudio.c | 2 ++ Alc/backends/qsa.c | 89 +++++++++++++++++++++++------------------------- Alc/backends/sndio.c | 2 ++ Alc/backends/wave.c | 2 ++ Alc/backends/winmm.c | 2 ++ 11 files changed, 63 insertions(+), 50 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1028321e..17b2727d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -4182,7 +4182,11 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL else if(samples < 0 || (samples > 0 && buffer == NULL)) alcSetError(device, ALC_INVALID_VALUE); else + { + V0(device->Backend,lock)(); aluMixData(device, buffer, samples); + V0(device->Backend,unlock)(); + } if(device) ALCdevice_DecRef(device); } diff --git a/Alc/ALu.c b/Alc/ALu.c index d5065199..9dcef6ff 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1423,7 +1423,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); IncrementRef(&device->MixCount); - V0(device->Backend,lock)(); if((slot=device->DefaultSlot) != NULL) { @@ -1488,7 +1487,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->SamplesDone += SamplesToDo; device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; device->SamplesDone %= device->Frequency; - V0(device->Backend,unlock)(); IncrementRef(&device->MixCount); if(device->Hrtf.Handle) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 24aeabd4..eb93f9ea 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -89,8 +89,10 @@ static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioAction ALCdevice *device = (ALCdevice*)inRefCon; ca_data *data = (ca_data*)device->ExtraData; + ALCdevice_Lock(device); aluMixData(device, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / data->frameSize); + ALCdevice_Unlock(device); return noErr; } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index bb38d516..084d1125 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -299,8 +299,10 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) if(SUCCEEDED(err)) { // If we have an active context, mix data directly into output buffer otherwise fill with silence + ALCdevice_Lock(device); aluMixData(device, WritePtr1, WriteCnt1/FrameSize); aluMixData(device, WritePtr2, WriteCnt2/FrameSize); + ALCdevice_Unlock(device); // Unlock output buffer only when successfully locked IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 92089416..6ff9d931 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -629,10 +629,10 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer); if(SUCCEEDED(hr)) { - V0(device->Backend,lock)(); + ALCmmdevPlayback_lock(self); aluMixData(device, buffer, len); self->Padding = written + len; - V0(device->Backend,unlock)(); + ALCmmdevPlayback_unlock(self); hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); } if(FAILED(hr)) diff --git a/Alc/backends/null.c b/Alc/backends/null.c index 5b153cd9..41636538 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -109,7 +109,9 @@ static int ALCnullBackend_mixerProc(void *ptr) al_nssleep(restTime); else while(avail-done >= device->UpdateSize) { + ALCnullBackend_lock(self); aluMixData(device, NULL, device->UpdateSize); + ALCnullBackend_unlock(self); done += device->UpdateSize; } } diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 1dbca941..129b0606 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -177,7 +177,9 @@ static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void * { ALCportPlayback *self = userData; + ALCportPlayback_lock(self); aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer); + ALCportPlayback_unlock(self); return 0; } diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index b7923517..dabe5ee9 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -33,6 +33,8 @@ #include "alu.h" #include "threads.h" +#include "backends/base.h" + typedef struct { snd_pcm_t* pcmHandle; @@ -161,13 +163,13 @@ FORCE_ALIGN static int qsa_proc_playback(void* 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; + char* write_ptr; + fd_set wfds; + ALint len; + int sret; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); @@ -177,59 +179,53 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr) param.sched_priority=param.sched_curpriority+1; SchedSet(0, 0, SCHED_NOCHANGE, ¶m); - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + const ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - while (!data->killNow) + V0(device->Backend,lock)(); + while(!data->killNow) { - ALint len=data->size; - write_ptr=data->buffer; - - avail=len/frame_size; - aluMixData(device, write_ptr, avail); + FD_ZERO(&wfds); + FD_SET(data->audio_fd, &wfds); + timeout.tv_sec=2; + timeout.tv_usec=0; - while (len>0 && !data->killNow) + /* Select also works like time slice to OS */ + V0(device->Backend,unlock)(); + sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout); + V0(device->Backend,lock)(); + if(sret == -1) { - 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); + ERR("select error: %s\n", strerror(errno)); + aluHandleDisconnect(device); + break; + } + if(sret == 0) + { + ERR("select timeout\n"); + continue; + } - if (wrote<=0) + len = data->size; + write_ptr = data->buffer; + aluMixData(device, write_ptr, len/frame_size); + while(len>0 && !data->killNow) + { + int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); + if(wrote <= 0) { - if ((errno==EAGAIN) || (errno==EWOULDBLOCK)) - { + if(errno==EAGAIN || errno==EWOULDBLOCK) continue; - } - memset(&status, 0, sizeof (status)); - status.channel=SND_PCM_CHANNEL_PLAYBACK; + 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(status.status == SND_PCM_STATUS_UNDERRUN || + status.status == SND_PCM_STATUS_READY) { - if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0) + if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) { aluHandleDisconnect(device); break; @@ -238,11 +234,12 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr) } else { - write_ptr+=wrote; - len-=wrote; + write_ptr += wrote; + len -= wrote; } } } + V0(device->Backend,unlock)(); return 0; } diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index af519794..00d7c654 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -105,7 +105,9 @@ static int ALCsndioBackend_mixerProc(void *ptr) ALsizei len = self->data_size; ALubyte *WritePtr = self->mix_data; + ALCsndioBackend_lock(self); aluMixData(device, WritePtr, len/frameSize); + ALCsndioBackend_unlock(self); while(len > 0 && !self->killNow) { wrote = sio_write(self->sndHandle, WritePtr, len); diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 9bf5a727..ac0ffd80 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -157,7 +157,9 @@ static int ALCwaveBackend_mixerProc(void *ptr) al_nssleep(restTime); else while(avail-done >= device->UpdateSize) { + ALCwaveBackend_lock(self); aluMixData(device, self->mBuffer, device->UpdateSize); + ALCwaveBackend_unlock(self); done += device->UpdateSize; if(!IS_LITTLE_ENDIAN) diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 9d8f8e9d..2b6db4ad 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -232,8 +232,10 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) } WaveHdr = ((WAVEHDR*)msg.lParam); + ALCwinmmPlayback_lock(self); aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / self->Format.nBlockAlign); + ALCwinmmPlayback_unlock(self); // Send buffer back to play more data waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); -- cgit v1.2.3 From d45dd9c668b2f4331492600d8ff99dc20c068664 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Feb 2017 14:36:06 -0800 Subject: Remove the sinc8 resampler option Perf shows less than 1 percent CPU difference from the higher quality bsinc resampler, but uses almost twice as much memory (a 128KB lookup table). --- Alc/mixer.c | 59 +++++++-------------------- Alc/mixer_c.c | 3 -- Alc/mixer_defs.h | 11 ----- Alc/mixer_neon.c | 83 ++------------------------------------ Alc/mixer_sse3.c | 75 ++-------------------------------- Alc/mixer_sse41.c | 81 ++----------------------------------- OpenAL32/Include/alu.h | 14 +------ utils/alsoft-config/mainwindow.cpp | 8 ++-- utils/alsoft-config/mainwindow.ui | 14 +++---- 9 files changed, 39 insertions(+), 309 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index d5cf30cc..a48b0e29 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -43,22 +43,21 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, extern inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); -alignas(16) union ResamplerCoeffs ResampleCoeffs; +alignas(16) ALfloat ResampleCoeffs_FIR4[FRACTIONONE][4]; enum Resampler { PointResampler, LinearResampler, FIR4Resampler, - FIR8Resampler, BSincResampler, ResamplerDefault = LinearResampler }; -/* FIR8 requires 3 extra samples before the current position, and 4 after. */ -static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!"); -static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!"); +/* BSinc requires up to 11 extra samples before the current position, and 12 after. */ +static_assert(MAX_PRE_SAMPLES >= 11, "MAX_PRE_SAMPLES must be at least 11!"); +static_assert(MAX_POST_SAMPLES >= 12, "MAX_POST_SAMPLES must be at least 12!"); static MixerFunc MixSamples = Mix_C; @@ -140,20 +139,6 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) return Resample_fir4_32_SSE3; #endif return Resample_fir4_32_C; - case FIR8Resampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_fir8_32_Neon; -#endif -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_fir8_32_SSE41; -#endif -#ifdef HAVE_SSE3 - if((CPUCapFlags&CPU_CAP_SSE3)) - return Resample_fir8_32_SSE3; -#endif - return Resample_fir8_32_C; case BSincResampler: #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -264,13 +249,11 @@ void aluInitMixer(void) resampler = LinearResampler; else if(strcasecmp(str, "sinc4") == 0) resampler = FIR4Resampler; - else if(strcasecmp(str, "sinc8") == 0) - resampler = FIR8Resampler; else if(strcasecmp(str, "bsinc") == 0) resampler = BSincResampler; - else if(strcasecmp(str, "cubic") == 0) + else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 0) { - WARN("Resampler option \"cubic\" is deprecated, using sinc4\n"); + WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str); resampler = FIR4Resampler; } else @@ -284,28 +267,14 @@ void aluInitMixer(void) } } - if(resampler == FIR8Resampler) - for(i = 0;i < FRACTIONONE;i++) - { - ALdouble mu = (ALdouble)i / FRACTIONONE; - ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0); - ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0); - ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0); - ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0); - ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0); - ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0); - ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0); - ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0); - } - else if(resampler == FIR4Resampler) - for(i = 0;i < FRACTIONONE;i++) - { - ALdouble mu = (ALdouble)i / FRACTIONONE; - ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0); - ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0); - ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0); - ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0); - } + for(i = 0;i < FRACTIONONE;i++) + { + ALdouble mu = (ALdouble)i / FRACTIONONE; + ResampleCoeffs_FIR4[i][0] = SincKaiser(2.0, mu - -1.0); + ResampleCoeffs_FIR4[i][1] = SincKaiser(2.0, mu - 0.0); + ResampleCoeffs_FIR4[i][2] = SincKaiser(2.0, mu - 1.0); + ResampleCoeffs_FIR4[i][3] = SincKaiser(2.0, mu - 2.0); + } MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 323f1363..a3d79a46 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -14,8 +14,6 @@ static inline ALfloat lerp32(const ALfloat *restrict vals, ALuint frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } static inline ALfloat fir4_32(const ALfloat *restrict vals, ALuint frac) { return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); } -static inline ALfloat fir8_32(const ALfloat *restrict vals, ALuint frac) -{ return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); } const ALfloat *Resample_copy32_C(const InterpState* UNUSED(state), @@ -51,7 +49,6 @@ const ALfloat *Resample_##Sampler##_C(const InterpState* UNUSED(state), \ DECL_TEMPLATE(point32) DECL_TEMPLATE(lerp32) DECL_TEMPLATE(fir4_32) -DECL_TEMPLATE(fir8_32) #undef DECL_TEMPLATE diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index 60735c9f..b76c9aee 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -16,7 +16,6 @@ const ALfloat *Resample_copy32_C(const InterpState *state, const ALfloat *restri const ALfloat *Resample_point32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); const ALfloat *Resample_lerp32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); const ALfloat *Resample_fir4_32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_fir8_32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); @@ -81,13 +80,6 @@ const ALfloat *Resample_fir4_32_SSE41(const InterpState *state, const ALfloat *r ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir8_32_SSE3(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); -const ALfloat *Resample_fir8_32_SSE41(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); - const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); @@ -115,9 +107,6 @@ const ALfloat *Resample_lerp32_Neon(const InterpState *state, const ALfloat *res const ALfloat *Resample_fir4_32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); -const ALfloat *Resample_fir8_32_Neon(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 543ff0f3..727c5c55 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -90,10 +90,10 @@ const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), const float32x4_t val1 = vld1q_f32(&src[pos_[1]]); const float32x4_t val2 = vld1q_f32(&src[pos_[2]]); const float32x4_t val3 = vld1q_f32(&src[pos_[3]]); - float32x4_t k0 = vld1q_f32(ResampleCoeffs.FIR4[frac_[0]]); - float32x4_t k1 = vld1q_f32(ResampleCoeffs.FIR4[frac_[1]]); - float32x4_t k2 = vld1q_f32(ResampleCoeffs.FIR4[frac_[2]]); - float32x4_t k3 = vld1q_f32(ResampleCoeffs.FIR4[frac_[3]]); + float32x4_t k0 = vld1q_f32(ResampleCoeffs_FIR4[frac_[0]]); + float32x4_t k1 = vld1q_f32(ResampleCoeffs_FIR4[frac_[1]]); + float32x4_t k2 = vld1q_f32(ResampleCoeffs_FIR4[frac_[2]]); + float32x4_t k3 = vld1q_f32(ResampleCoeffs_FIR4[frac_[3]]); float32x4_t out; k0 = vmulq_f32(k0, val0); @@ -136,81 +136,6 @@ const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), return dst; } -const ALfloat *Resample_fir8_32_Neon(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const int32x4_t increment4 = vdupq_n_s32(increment*4); - const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); - alignas(16) ALint pos_[4]; - alignas(16) ALuint frac_[4]; - int32x4_t pos4; - uint32x4_t frac4; - ALsizei i, j; - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - - frac4 = vld1q_u32(frac_); - pos4 = vld1q_s32(pos_); - - src -= 3; - for(i = 0;numsamples-i > 3;i += 4) - { - float32x4_t out[2]; - for(j = 0;j < 8;j+=4) - { - const float32x4_t val0 = vld1q_f32(&src[pos_[0]+j]); - const float32x4_t val1 = vld1q_f32(&src[pos_[1]+j]); - const float32x4_t val2 = vld1q_f32(&src[pos_[2]+j]); - const float32x4_t val3 = vld1q_f32(&src[pos_[3]+j]); - float32x4_t k0 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[0]][j]); - float32x4_t k1 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[1]][j]); - float32x4_t k2 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[2]][j]); - float32x4_t k3 = vld1q_f32(&ResampleCoeffs.FIR4[frac_[3]][j]); - - k0 = vmulq_f32(k0, val0); - k1 = vmulq_f32(k1, val1); - k2 = vmulq_f32(k2, val2); - k3 = vmulq_f32(k3, val3); - k0 = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), - vpadd_f32(vget_low_f32(k1), vget_high_f32(k1))); - k2 = vcombine_f32(vpadd_f32(vget_low_f32(k2), vget_high_f32(k2)), - vpadd_f32(vget_low_f32(k3), vget_high_f32(k3))); - out[j>>2] = vcombine_f32(vpadd_f32(vget_low_f32(k0), vget_high_f32(k0)), - vpadd_f32(vget_low_f32(k2), vget_high_f32(k2))); - } - - out[0] = vaddq_f32(out[0], out[1]); - vst1q_f32(&dst[i], out[0]); - - frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); - pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); - frac4 = vandq_u32(frac4, fracMask4); - - vst1q_s32(pos_, pos4); - vst1q_u32(frac_, frac4); - } - - if(i < numsamples) - { - /* NOTE: These four elements represent the position *after* the last - * four samples, so the lowest element is the next position to - * resample. - */ - ALint pos = pos_[0]; - frac = frac_[0]; - do { - dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3], - src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } while(++i < numsamples); - } - return dst; -} - const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 3b444158..861cfc38 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -55,10 +55,10 @@ const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state), const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]); + __m128 k0 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[0]]); + __m128 k1 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[1]]); + __m128 k2 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[2]]); + __m128 k3 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); @@ -95,70 +95,3 @@ const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state), } return dst; } - -const ALfloat *Resample_fir8_32_SSE3(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const __m128i increment4 = _mm_set1_epi32(increment*4); - const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; - __m128i frac4, pos4; - ALsizei i, j; - ALint pos; - - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); - - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - src -= 3; - for(i = 0;numsamples-i > 3;i += 4) - { - __m128 out[2]; - for(j = 0;j < 8;j+=4) - { - const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]); - const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]); - const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]); - const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]); - __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]); - __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]); - __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]); - __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]); - - k0 = _mm_mul_ps(k0, val0); - k1 = _mm_mul_ps(k1, val1); - k2 = _mm_mul_ps(k2, val2); - k3 = _mm_mul_ps(k3, val3); - k0 = _mm_hadd_ps(k0, k1); - k2 = _mm_hadd_ps(k2, k3); - out[j>>2] = _mm_hadd_ps(k0, k2); - } - - out[0] = _mm_add_ps(out[0], out[1]); - _mm_store_ps(&dst[i], out[0]); - - frac4 = _mm_add_epi32(frac4, increment4); - pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); - frac4 = _mm_and_si128(frac4, fracMask4); - - _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4)); - _mm_store_ps(frac_.f, _mm_castsi128_ps(frac4)); - } - - pos = pos_.i[0]; - frac = frac_.i[0]; - - for(;i < numsamples;i++) - { - dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3], - src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index 7ae5bec7..61be4cae 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -109,10 +109,10 @@ const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state), const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]); + __m128 k0 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[0]]); + __m128 k1 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[1]]); + __m128 k2 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[2]]); + __m128 k3 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); @@ -152,76 +152,3 @@ const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state), } return dst; } - -const ALfloat *Resample_fir8_32_SSE41(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const __m128i increment4 = _mm_set1_epi32(increment*4); - const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; - __m128i frac4, pos4; - ALsizei i, j; - ALint pos; - - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); - - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - src -= 3; - for(i = 0;numsamples-i > 3;i += 4) - { - __m128 out[2]; - for(j = 0;j < 8;j+=4) - { - const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]); - const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]); - const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]); - const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]); - __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]); - __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]); - __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]); - __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]); - - k0 = _mm_mul_ps(k0, val0); - k1 = _mm_mul_ps(k1, val1); - k2 = _mm_mul_ps(k2, val2); - k3 = _mm_mul_ps(k3, val3); - k0 = _mm_hadd_ps(k0, k1); - k2 = _mm_hadd_ps(k2, k3); - out[j>>2] = _mm_hadd_ps(k0, k2); - } - - out[0] = _mm_add_ps(out[0], out[1]); - _mm_store_ps(&dst[i], out[0]); - - frac4 = _mm_add_epi32(frac4, increment4); - pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); - frac4 = _mm_and_si128(frac4, fracMask4); - - pos_.i[0] = _mm_extract_epi32(pos4, 0); - pos_.i[1] = _mm_extract_epi32(pos4, 1); - pos_.i[2] = _mm_extract_epi32(pos4, 2); - pos_.i[3] = _mm_extract_epi32(pos4, 3); - frac_.i[0] = _mm_extract_epi32(frac4, 0); - frac_.i[1] = _mm_extract_epi32(frac4, 1); - frac_.i[2] = _mm_extract_epi32(frac4, 2); - frac_.i[3] = _mm_extract_epi32(frac4, 3); - } - - pos = pos_.i[0]; - frac = frac_.i[0]; - - for(;i < numsamples;i++) - { - dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3], - src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c3c7a20c..c9f8760e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -229,11 +229,7 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) { return minu64(max, maxu64(min, val)); } -union ResamplerCoeffs { - ALfloat FIR4[FRACTIONONE][4]; - ALfloat FIR8[FRACTIONONE][8]; -}; -extern alignas(16) union ResamplerCoeffs ResampleCoeffs; +extern alignas(16) ALfloat ResampleCoeffs_FIR4[FRACTIONONE][4]; extern alignas(16) const ALfloat bsincTab[18840]; @@ -244,15 +240,9 @@ inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) } inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac) { - const ALfloat *k = ResampleCoeffs.FIR4[frac]; + const ALfloat *k = ResampleCoeffs_FIR4[frac]; return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3; } -inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac) -{ - const ALfloat *k = ResampleCoeffs.FIR8[frac]; - return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 + - k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7; -} enum HrtfRequestMode { diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4ae89f09..89e4c30a 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -101,7 +101,6 @@ static const struct NameValuePair { { "Linear", "linear" }, { "Default (Linear)", "" }, { "4-Point Sinc", "sinc4" }, - { "8-Point Sinc", "sinc8" }, { "Band-limited Sinc", "bsinc" }, { "", "" } @@ -598,9 +597,10 @@ void MainWindow::loadConfig(const QString &fname) QString resampler = settings.value("resampler").toString().trimmed(); ui->resamplerSlider->setValue(0); - /* The "cubic" resampler is no longer supported. It's been replaced by - * "sinc4". */ - if(resampler == "cubic") + /* The "cubic" and "sinc8" resamplers are no longer supported. Use "sinc4" + * as a fallback. + */ + if(resampler == "cubic" || resampler == "sinc8") resampler = "sinc4"; for(int i = 0;resamplerList[i].name[0];i++) { diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 0356d491..06f12546 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -7,13 +7,13 @@ 0 0 564 - 454 + 460 564 - 454 + 460 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 96 - 22 + 91 + 29 @@ -2075,8 +2075,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 131 - 22 + 123 + 29 @@ -2245,7 +2245,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 19 + 27 -- cgit v1.2.3 From 9da152a9c8b9f3a6f019c77e0324772344fc9156 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Feb 2017 17:45:27 -0800 Subject: Don't use periphonic FOA when the HOA decoder is not periphonic --- Alc/ALc.c | 50 +++++++++++++++++++++++++++++--------------------- Alc/ALu.c | 7 +++---- Alc/bformatdec.c | 22 +++++++++------------- Alc/bformatdec.h | 1 + Alc/panning.c | 16 +++++++++++++--- 5 files changed, 55 insertions(+), 41 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 17b2727d..d200733b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2118,16 +2118,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); /* Allocate extra channels for any post-filter output. */ - size = device->Dry.NumChannels * sizeof(device->Dry.Buffer[0]); - if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2)) - size += (ChannelsFromDevFmt(device->FmtChans)+4) * sizeof(device->Dry.Buffer[0]); - else if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) + size = device->Dry.NumChannels; + if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) { - size += ChannelsFromDevFmt(device->FmtChans) * sizeof(device->Dry.Buffer[0]); - if(device->AmbiUp) size += 4 * sizeof(device->Dry.Buffer[0]); + size += ChannelsFromDevFmt(device->FmtChans); + size += bformatdec_isPeriphonic(device->AmbiDecoder) ? 4 : 3; } - else if(device->AmbiUp) - size += 4 * sizeof(device->Dry.Buffer[0]); + else + { + if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) + size += ChannelsFromDevFmt(device->FmtChans); + if(device->AmbiUp) + size += 4; + } + size *= sizeof(device->Dry.Buffer[0]); + TRACE("Allocating "SZFMT" channels, "SZFMT" bytes\n", size/sizeof(device->Dry.Buffer[0]), size); device->Dry.Buffer = al_calloc(16, size); if(!device->Dry.Buffer) @@ -2136,30 +2141,33 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) - { - device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); - } - else - { - device->RealOut.Buffer = device->Dry.Buffer; - device->RealOut.NumChannels = device->Dry.NumChannels; - } - if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || device->AmbiUp) { /* Higher-order rendering requires upsampling first-order content, so * make sure to mix it separately. */ - device->FOAOut.Buffer = device->RealOut.Buffer + device->RealOut.NumChannels; - device->FOAOut.NumChannels = 4; + device->FOAOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; + if((device->AmbiDecoder && bformatdec_isPeriphonic(device->AmbiDecoder)) || device->AmbiUp) + device->FOAOut.NumChannels = 4; + else + device->FOAOut.NumChannels = 3; } else { device->FOAOut.Buffer = device->Dry.Buffer; device->FOAOut.NumChannels = device->Dry.NumChannels; } + + if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) + { + device->RealOut.Buffer = device->FOAOut.Buffer + device->FOAOut.NumChannels; + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + } + else + { + device->RealOut.Buffer = device->Dry.Buffer; + device->RealOut.NumChannels = device->Dry.NumChannels; + } TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, device->FOAOut.NumChannels, device->RealOut.NumChannels); diff --git a/Alc/ALu.c b/Alc/ALu.c index 9dcef6ff..2476622b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -81,7 +81,6 @@ extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac); -extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac); extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); @@ -1415,12 +1414,12 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) SamplesToDo = mini(size, BUFFERSIZE); for(c = 0;c < device->Dry.NumChannels;c++) memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); - if(device->Dry.Buffer != device->RealOut.Buffer) - for(c = 0;c < device->RealOut.NumChannels;c++) - memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); if(device->Dry.Buffer != device->FOAOut.Buffer) for(c = 0;c < device->FOAOut.NumChannels;c++) memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Dry.Buffer != device->RealOut.Buffer) + for(c = 0;c < device->RealOut.NumChannels;c++) + memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat)); IncrementRef(&device->MixCount); diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index fc0dee47..549cd42c 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -184,10 +184,7 @@ typedef struct BFormatDec { } Delay[MAX_OUTPUT_CHANNELS]; struct { - ALsizei Index; - BandSplitter XOver; - ALfloat Gains[FB_Max]; } UpSampler[4]; @@ -233,6 +230,11 @@ int bformatdec_getOrder(const struct BFormatDec *dec) return 0; } +int bformatdec_isPeriphonic(const struct BFormatDec *dec) +{ + return dec->Periphonic; +} + void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags) { static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { @@ -271,13 +273,11 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { dec->Periphonic = AL_TRUE; - dec->UpSampler[0].Index = 0; dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD : (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; for(i = 1;i < 4;i++) { - dec->UpSampler[i].Index = i; dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD : (dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f; dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; @@ -287,17 +287,17 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { dec->Periphonic = AL_FALSE; - dec->UpSampler[0].Index = 0; dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD : (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f; dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; - for(i = 1;i < 4;i++) + for(i = 1;i < 3;i++) { - dec->UpSampler[i].Index = (i>2) ? i-1 : ((i==2) ? INVALID_UPSAMPLE_INDEX : i); dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD : (dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f; dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; } + dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f; + dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f; } maxdist = 0.0f; @@ -553,10 +553,6 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B */ for(i = 0;i < InChannels;i++) { - ALsizei dst_chan = dec->UpSampler[i].Index; - if(dst_chan == INVALID_UPSAMPLE_INDEX) - continue; - /* First, split the first-order components into low and high frequency * bands. */ @@ -566,7 +562,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B ); /* Now write each band to the output. */ - MixMatrixRow(OutBuffer[dst_chan], dec->UpSampler[i].Gains, + MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains, SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0, SamplesToDo ); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 06c14ec3..5f6e230d 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -32,6 +32,7 @@ enum BFormatDecFlags { struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); +int bformatdec_isPeriphonic(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags); /* Decodes the ambisonic input to the given output channels. */ diff --git a/Alc/panning.c b/Alc/panning.c index 98da032e..eb2ec0c8 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -742,10 +742,20 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz else { memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); - for(i = 0;i < 4;i++) + if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) + for(i = 0;i < 4;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = i; + } + else { - device->FOAOut.Ambi.Map[i].Scale = 1.0f; - device->FOAOut.Ambi.Map[i].Index = i; + static const int map[3] = { 0, 1, 3 }; + for(i = 0;i < 3;i++) + { + device->FOAOut.Ambi.Map[i].Scale = 1.0f; + device->FOAOut.Ambi.Map[i].Index = map[i]; + } } device->FOAOut.CoeffCount = 0; } -- cgit v1.2.3 From 3761336e6cf49a7cd5075424b3c8c4a1f5e5b226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Feb 2017 22:47:59 -0800 Subject: Apply distance compensation when writing to the output --- Alc/ALu.c | 51 ++++++++++++++------ Alc/bformatdec.c | 115 +++++----------------------------------------- Alc/bformatdec.h | 2 +- Alc/panning.c | 48 +++++++++++++++++-- OpenAL32/Include/alMain.h | 12 +++++ 5 files changed, 106 insertions(+), 122 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 2476622b..1fca0ed0 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1373,15 +1373,39 @@ static inline ALubyte aluF2UB(ALfloat val) { return aluF2B(val)+128; } #define DECL_TEMPLATE(T, func) \ -static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - ALsizei SamplesToDo, ALsizei numchans) \ +static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ + DistanceComp *distcomp, ALsizei SamplesToDo, \ + ALsizei numchans) \ { \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ { \ const ALfloat *in = InBuffer[j]; \ T *restrict out = (T*)OutBuffer + j; \ - for(i = 0;i < SamplesToDo;i++) \ + const ALfloat gain = distcomp[j].Gain; \ + const ALsizei base = distcomp[j].Length; \ + if(base > 0 || gain != 1.0f) \ + { \ + if(SamplesToDo >= base) \ + { \ + for(i = 0;i < base;i++) \ + out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \ + for(;i < SamplesToDo;i++) \ + out[i*numchans] = func(in[i-base]*gain); \ + memcpy(distcomp[j].Buffer, &in[SamplesToDo-base], \ + base*sizeof(ALfloat)); \ + } \ + else \ + { \ + for(i = 0;i < SamplesToDo;i++) \ + out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \ + memmove(distcomp[j].Buffer, distcomp[j].Buffer+SamplesToDo, \ + (base-SamplesToDo)*sizeof(ALfloat)); \ + memcpy(distcomp[j].Buffer+base-SamplesToDo, in, \ + SamplesToDo*sizeof(ALfloat)); \ + } \ + } \ + else for(i = 0;i < SamplesToDo;i++) \ out[i*numchans] = func(in[i]); \ } \ } @@ -1564,33 +1588,34 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; + DistanceComp *DistComp = device->ChannelDelay; -#define WRITE(T, a, b, c, d) do { \ - Write_##T((a), (b), (c), (d)); \ - buffer = (T*)buffer + (c)*(d); \ +#define WRITE(T, a, b, c, d, e) do { \ + Write_##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \ + buffer = (T*)buffer + (d)*(e); \ } while(0) switch(device->FmtType) { case DevFmtByte: - WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALbyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtUByte: - WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALubyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtShort: - WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALshort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtUShort: - WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALushort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtInt: - WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtUInt: - WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALuint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; case DevFmtFloat: - WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels); + WRITE(ALfloat, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); break; } #undef WRITE diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 549cd42c..5b848ee0 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -156,10 +156,6 @@ static void init_bformatdec(void) } -#define MAX_DELAY_LENGTH 128 - -#define INVALID_UPSAMPLE_INDEX INT_MAX - /* NOTE: BandSplitter filters are unused with single-band decoding */ typedef struct BFormatDec { ALboolean Enabled[MAX_OUTPUT_CHANNELS]; @@ -178,11 +174,6 @@ typedef struct BFormatDec { alignas(16) ALfloat ChannelMix[BUFFERSIZE]; - struct { - alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; - ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ - } Delay[MAX_OUTPUT_CHANNELS]; - struct { BandSplitter XOver; ALfloat Gains[FB_Max]; @@ -235,14 +226,13 @@ int bformatdec_isPeriphonic(const struct BFormatDec *dec) return dec->Periphonic; } -void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags) +void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; - ALfloat distgain[MAX_OUTPUT_CHANNELS]; - ALfloat maxdist, ratio; + ALfloat ratio; ALsizei i; al_free(dec->Samples); @@ -300,41 +290,6 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f; } - maxdist = 0.0f; - for(i = 0;i < conf->NumSpeakers;i++) - { - maxdist = maxf(maxdist, conf->Speakers[i].Distance); - distgain[i] = 1.0f; - } - - memset(dec->Delay, 0, sizeof(dec->Delay)); - if((flags&BFDF_DistanceComp) && maxdist > 0.0f) - { - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = chanmap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - (ALfloat)srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); - - dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1)); - distgain[i] = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i] - ); - } - } - memset(&dec->Matrix, 0, sizeof(dec->Matrix)); if(conf->FreqBands == 1) { @@ -356,7 +311,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 5) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * - gain * distgain[i]; + gain; } } else @@ -369,7 +324,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 9) gain = conf->HFOrderGain[3]; if((conf->ChanMask&(1<Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * - gain * distgain[i]; + gain; } } } @@ -400,8 +355,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 5) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / - coeff_scale[l] * gain * - distgain[i]; + coeff_scale[l] * gain; } for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { @@ -412,8 +366,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / - coeff_scale[l] * gain * - distgain[i]; + coeff_scale[l] * gain; } } else @@ -426,8 +379,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / - coeff_scale[j] * gain * - distgain[i]; + coeff_scale[j] * gain; } for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) { @@ -437,8 +389,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / - coeff_scale[j] * gain * - distgain[i]; + coeff_scale[j] * gain; } } } @@ -471,29 +422,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU SamplesToDo ); - if(dec->Delay[chan].Length > 0) - { - const ALsizei base = dec->Delay[chan].Length; - if(SamplesToDo >= base) - { - for(i = 0;i < base;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; - for(;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i-base]; - memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], - base*sizeof(ALfloat)); - } - else - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; - memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, - base - SamplesToDo); - memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, - SamplesToDo*sizeof(ALfloat)); - } - } - else for(i = 0;i < SamplesToDo;i++) + for(i = 0;i < SamplesToDo;i++) OutBuffer[chan][i] += dec->ChannelMix[i]; } } @@ -508,29 +437,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, dec->NumChannels, 0, SamplesToDo); - if(dec->Delay[chan].Length > 0) - { - const ALsizei base = dec->Delay[chan].Length; - if(SamplesToDo >= base) - { - for(i = 0;i < base;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; - for(;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->ChannelMix[i-base]; - memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base], - base*sizeof(ALfloat)); - } - else - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[chan][i] += dec->Delay[chan].Buffer[i]; - memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo, - base - SamplesToDo); - memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix, - SamplesToDo*sizeof(ALfloat)); - } - } - else for(i = 0;i < SamplesToDo;i++) + for(i = 0;i < SamplesToDo;i++) OutBuffer[chan][i] += dec->ChannelMix[i]; } } @@ -570,6 +477,8 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B } +#define INVALID_UPSAMPLE_INDEX INT_MAX + static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn) { ALsizei i; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 5f6e230d..97f36d0e 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -33,7 +33,7 @@ struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); int bformatdec_isPeriphonic(const struct BFormatDec *dec); -void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS], int flags); +void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); diff --git a/Alc/panning.c b/Alc/panning.c index eb2ec0c8..80532bc4 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -693,13 +693,10 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { const char *devname; - int decflags = 0; size_t count; size_t i; devname = al_string_get_cstr(device->DeviceName); - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1)) - decflags |= BFDF_DistanceComp; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { @@ -731,8 +728,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first", (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : "" ); - bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, - speakermap, decflags); + bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); if(bformatdec_getOrder(device->AmbiDecoder) < 2) { @@ -759,6 +755,41 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz } device->FOAOut.CoeffCount = 0; } + + ALfloat maxdist = 0.0f; + for(i = 0;i < (size_t)conf->NumSpeakers;i++) + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) + { + ALfloat srate = (ALfloat)device->Frequency; + for(i = 0;i < (size_t)conf->NumSpeakers;i++) + { + ALsizei chan = speakermap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + device->ChannelDelay[chan].Length = (ALsizei)clampf( + delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) + ); + device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + device->ChannelDelay[chan].Gain + ); + } + } } static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) @@ -887,6 +918,13 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; + memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + } + if(device->FmtChans != DevFmtStereo) { ALsizei speakermap[MAX_OUTPUT_CHANNELS]; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 947a16ba..bb8a57ce 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -603,6 +603,15 @@ typedef struct HrtfEntry { TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry) +/* Maximum delay in samples for speaker distance compensation. */ +#define MAX_DELAY_LENGTH 128 + +typedef struct DistanceComp { + ALfloat Gain; + ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ + alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; +} DistanceComp; + /* Size for temporary storage of buffer data, in ALfloats. Larger values need * 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 @@ -723,6 +732,9 @@ struct ALCdevice_struct ALsizei NumChannels; } RealOut; + /* Delay buffers used to compensate for speaker distances. */ + DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; + /* Running count of the mixer invocations, in 31.1 fixed point. This * actually increments *twice* when mixing, first at the start and then at * the end, so the bottom bit indicates if the device is currently mixing -- cgit v1.2.3 From b23f81b686f4c72044d0d6f85b5049822f3c6a78 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Feb 2017 22:59:55 -0800 Subject: Remove the separate surround51rear decoder option Both 5.1 Side and Rear configurations use 'surround51' to look up the appropriate decoder file. The decoder loader already handles mapping between rear and side channels, so there's no need for separate options. --- Alc/panning.c | 4 +-- alsoftrc.sample | 9 ++----- utils/alsoft-config/mainwindow.cpp | 8 +----- utils/alsoft-config/mainwindow.h | 1 - utils/alsoft-config/mainwindow.ui | 55 ++++++-------------------------------- 5 files changed, 13 insertions(+), 64 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 80532bc4..00cf9e0b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -940,8 +940,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; - case DevFmtX51: layout = "surround51"; break; - case DevFmtX51Rear: layout = "surround51rear"; break; + case DevFmtX51: /* fall-through */ + case DevFmtX51Rear: layout = "surround51"; break; case DevFmtX61: layout = "surround61"; break; case DevFmtX71: layout = "surround71"; break; /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ diff --git a/alsoftrc.sample b/alsoftrc.sample index d5913ff0..256a4d06 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -246,15 +246,10 @@ distance-comp = true quad = ## surround51: -# Decoder configuration file for 5.1 Surround (Side) channel output. See -# docs/ambdec.txt for a description of the file format. +# Decoder configuration file for 5.1 Surround (Side and Rear) channel output. +# See docs/ambdec.txt for a description of the file format. surround51 = -## surround51rear: -# Decoder configuration file for 5.1 Surround (Rear) channel output. See -# docs/ambdec.txt for a description of the file format. -surround51rear = - ## surround61: # Decoder configuration file for 6.1 Surround channel output. See # docs/ambdec.txt for a description of the file format. diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 89e4c30a..ab992843 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -335,8 +335,6 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoder51Button, SIGNAL(clicked()), this, SLOT(select51DecoderFile())); - connect(ui->decoder51RearLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoder51RearButton, SIGNAL(clicked()), this, SLOT(select51RearDecoderFile())); connect(ui->decoder61LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); connect(ui->decoder71LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); @@ -671,7 +669,6 @@ void MainWindow::loadConfig(const QString &fname) ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); - ui->decoder51RearLineEdit->setText(settings.value("decoder/surround51rear").toString()); ui->decoder61LineEdit->setText(settings.value("decoder/surround61").toString()); ui->decoder71LineEdit->setText(settings.value("decoder/surround71").toString()); @@ -901,7 +898,6 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); - settings.setValue("decoder/surround51rear", ui->decoder51RearLineEdit->text()); settings.setValue("decoder/surround61", ui->decoder61LineEdit->text()); settings.setValue("decoder/surround71", ui->decoder71LineEdit->text()); @@ -1123,9 +1119,7 @@ void MainWindow::toggleHqState(int state) void MainWindow::selectQuadDecoderFile() { selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} void MainWindow::select51DecoderFile() -{ selectDecoderFile(ui->decoder51LineEdit, "Select 5.1 Surround (Side) Decoder");} -void MainWindow::select51RearDecoderFile() -{ selectDecoderFile(ui->decoder51RearLineEdit, "Select 5.1 Surround (Rear) Decoder");} +{ selectDecoderFile(ui->decoder51LineEdit, "Select 5.1 Surround Decoder");} void MainWindow::select61DecoderFile() { selectDecoderFile(ui->decoder61LineEdit, "Select 6.1 Surround Decoder");} void MainWindow::select71DecoderFile() diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 3bf2fb83..6d572df6 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -39,7 +39,6 @@ private slots: void selectQuadDecoderFile(); void select51DecoderFile(); - void select51RearDecoderFile(); void select61DecoderFile(); void select71DecoderFile(); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 06f12546..f14554e6 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -622,7 +622,7 @@ configuration file. -10 100 551 - 191 + 161 @@ -703,56 +703,17 @@ configuration file. - 5.1 Surround (Side): - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 20 - 90 - 121 - 21 - - - - 5.1 Surround (Rear): + 5.1 Surround: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - 150 - 90 - 281 - 21 - - - - - - - 440 - 90 - 91 - 21 - - - - Browse... - - 20 - 120 + 90 121 21 @@ -768,7 +729,7 @@ configuration file. 150 - 120 + 90 281 21 @@ -778,7 +739,7 @@ configuration file. 440 - 120 + 90 91 21 @@ -791,7 +752,7 @@ configuration file. 440 - 150 + 120 91 21 @@ -804,7 +765,7 @@ configuration file. 150 - 150 + 120 281 21 @@ -814,7 +775,7 @@ configuration file. 20 - 150 + 120 121 21 -- cgit v1.2.3 From 5a2ef2590f38c72883f9ee2e18cc9980634df7be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Feb 2017 09:08:57 -0800 Subject: Allow distance compensation for non-HQ rendering as well It still requires a custom configuration to specify appropriate speaker distances. --- Alc/panning.c | 81 +++++++++++++++++++++----------------- alsoftrc.sample | 5 +-- utils/alsoft-config/mainwindow.cpp | 9 +---- utils/alsoft-config/mainwindow.h | 2 - utils/alsoft-config/mainwindow.ui | 5 +-- 5 files changed, 49 insertions(+), 53 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 00cf9e0b..52618a5e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -610,6 +610,47 @@ static void InitPanning(ALCdevice *device) } } +static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + const char *devname = al_string_get_cstr(device->DeviceName); + ALfloat maxdist = 0.0f; + ALsizei i; + + for(i = 0;i < conf->NumSpeakers;i++) + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) + { + ALfloat srate = (ALfloat)device->Frequency; + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = speakermap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + device->ChannelDelay[chan].Length = (ALsizei)clampf( + delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) + ); + device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + device->ChannelDelay[chan].Gain + ); + } + } +} + static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; @@ -688,16 +729,15 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; + + InitDistanceComp(device, conf, speakermap); } static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - const char *devname; size_t count; size_t i; - devname = al_string_get_cstr(device->DeviceName); - if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { count = (conf->ChanMask > 0x1ff) ? 16 : @@ -756,40 +796,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->FOAOut.CoeffCount = 0; } - ALfloat maxdist = 0.0f; - for(i = 0;i < (size_t)conf->NumSpeakers;i++) - maxdist = maxf(maxdist, conf->Speakers[i].Distance); - - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) - { - ALfloat srate = (ALfloat)device->Frequency; - for(i = 0;i < (size_t)conf->NumSpeakers;i++) - { - ALsizei chan = speakermap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); - - device->ChannelDelay[chan].Length = (ALsizei)clampf( - delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) - ); - device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, - device->ChannelDelay[chan].Gain - ); - } - } + InitDistanceComp(device, conf, speakermap); } static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) diff --git a/alsoftrc.sample b/alsoftrc.sample index 256a4d06..36d930bf 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -235,9 +235,8 @@ hq-mode = false # Enables compensation for the speakers' relative distances to the listener. # This applies the necessary delays and attenuation to make the speakers # behave as though they are all equidistant, which is important for proper -# playback of 3D sound rendering. Requires the high-quality ambisonic decoder, -# as well as the proper distances to be specified in the decoder configuration -# file. +# playback of 3D sound rendering. Requires the proper distances to be +# specified in the decoder configuration file. distance-comp = true ## quad: diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index ab992843..e4dc10fc 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -329,7 +329,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); - connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(toggleHqState(int))); + connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); @@ -665,7 +665,6 @@ void MainWindow::loadConfig(const QString &fname) ui->decoderHQModeCheckBox->setChecked(hqmode); bool distcomp = settings.value("decoder/distance-comp", true).toBool(); ui->decoderDistCompCheckBox->setChecked(distcomp); - ui->decoderDistCompCheckBox->setEnabled(hqmode); ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); @@ -1110,12 +1109,6 @@ void MainWindow::updatePeriodCountSlider() } -void MainWindow::toggleHqState(int state) -{ - ui->decoderDistCompCheckBox->setEnabled(state); - enableApplyButton(); -} - void MainWindow::selectQuadDecoderFile() { selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} void MainWindow::select51DecoderFile() diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 6d572df6..8b763845 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -35,8 +35,6 @@ private slots: void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); - void toggleHqState(int state); - void selectQuadDecoderFile(); void select51DecoderFile(); void select61DecoderFile(); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index f14554e6..afb91996 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -601,9 +601,8 @@ appropriate speaker configuration you intend to use. This applies the necessary delays and attenuation to make the speakers behave as though they are all equidistant, which is important for proper -playback of 3D sound rendering. Requires the high -quality ambisonic renderer, as well as the proper -distances to be specified in the decoder +playback of 3D sound rendering. Requires the +proper distances to be specified in the decoder configuration file. -- cgit v1.2.3 From 23a34f732bf27bb75905b07c83e948a9e832c59c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Feb 2017 09:13:08 -0800 Subject: Remove mention of the sinc8 resampler --- alsoftrc.sample | 1 - 1 file changed, 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 36d930bf..52e93ad1 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -149,7 +149,6 @@ # point - nearest sample, no interpolation # linear - extrapolates samples using a linear slope between samples # sinc4 - extrapolates samples using a 4-point Sinc filter -# sinc8 - extrapolates samples using an 8-point Sinc filter # bsinc - extrapolates samples using a band-limited Sinc filter (varying # between 12 and 24 points, with anti-aliasing) # Specifying other values will result in using the default (linear). -- cgit v1.2.3 From f5e8a8c75e98e7a720a42a840701808b3f869a8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Feb 2017 09:25:09 -0800 Subject: Remove an unused flag enum --- Alc/bformatdec.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 97f36d0e..7447e382 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -25,9 +25,6 @@ struct AmbDecConf; struct BFormatDec; struct AmbiUpsampler; -enum BFormatDecFlags { - BFDF_DistanceComp = 1<<0 -}; struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); -- cgit v1.2.3 From bb4726d52038befc53ab219da8b75193a2605c5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Feb 2017 16:57:25 -0800 Subject: Avoid duplicating device buffer layout logic --- Alc/ALc.c | 49 +++++++++++++------------------------------------ Alc/bformatdec.c | 1 + Alc/panning.c | 26 ++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d200733b..c831ca9d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2116,22 +2116,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ); aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq); + TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, + device->FOAOut.NumChannels, device->RealOut.NumChannels); /* Allocate extra channels for any post-filter output. */ - size = device->Dry.NumChannels; - if(device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) - { - size += ChannelsFromDevFmt(device->FmtChans); - size += bformatdec_isPeriphonic(device->AmbiDecoder) ? 4 : 3; - } - else - { - if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) - size += ChannelsFromDevFmt(device->FmtChans); - if(device->AmbiUp) - size += 4; - } - size *= sizeof(device->Dry.Buffer[0]); + size = (device->Dry.NumChannels + device->FOAOut.NumChannels + + device->RealOut.NumChannels)*sizeof(device->Dry.Buffer[0]); TRACE("Allocating "SZFMT" channels, "SZFMT" bytes\n", size/sizeof(device->Dry.Buffer[0]), size); device->Dry.Buffer = al_calloc(16, size); @@ -2141,35 +2131,22 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_DEVICE; } - if((device->AmbiDecoder && bformatdec_getOrder(device->AmbiDecoder) >= 2) || device->AmbiUp) - { - /* Higher-order rendering requires upsampling first-order content, so - * make sure to mix it separately. - */ - device->FOAOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; - if((device->AmbiDecoder && bformatdec_isPeriphonic(device->AmbiDecoder)) || device->AmbiUp) - device->FOAOut.NumChannels = 4; - else - device->FOAOut.NumChannels = 3; - } + if(device->RealOut.NumChannels != 0) + device->RealOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels + + device->FOAOut.NumChannels; else { - device->FOAOut.Buffer = device->Dry.Buffer; - device->FOAOut.NumChannels = device->Dry.NumChannels; + device->RealOut.Buffer = device->Dry.Buffer; + device->RealOut.NumChannels = device->Dry.NumChannels; } - if(device->Hrtf.Handle || device->Uhj_Encoder || device->AmbiDecoder) - { - device->RealOut.Buffer = device->FOAOut.Buffer + device->FOAOut.NumChannels; - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); - } + if(device->FOAOut.NumChannels != 0) + device->FOAOut.Buffer = device->Dry.Buffer + device->Dry.NumChannels; else { - device->RealOut.Buffer = device->Dry.Buffer; - device->RealOut.NumChannels = device->Dry.NumChannels; + device->FOAOut.Buffer = device->Dry.Buffer; + device->FOAOut.NumChannels = device->Dry.NumChannels; } - TRACE("Channel config, Dry: %d, FOA: %d, Real: %d\n", device->Dry.NumChannels, - device->FOAOut.NumChannels, device->RealOut.NumChannels); SetMixerFPUMode(&oldMode); if(device->DefaultSlot) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 5b848ee0..955b9e4a 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -401,6 +401,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU { ALsizei chan, i; + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); if(dec->DualBand) { for(i = 0;i < dec->NumChannels;i++) diff --git a/Alc/panning.c b/Alc/panning.c index 52618a5e..70355b41 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -569,6 +569,7 @@ static void InitPanning(ALCdevice *device) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; } else { @@ -582,6 +583,7 @@ static void InitPanning(ALCdevice *device) device->FOAOut.Ambi.Map[i].Index = i; } device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = 4; ambiup_reset(device->AmbiUp, device); } @@ -607,7 +609,9 @@ static void InitPanning(ALCdevice *device) device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; + device->FOAOut.NumChannels = 0; } + device->RealOut.NumChannels = 0; } static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) @@ -729,6 +733,9 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * xyz_scale; } device->FOAOut.CoeffCount = 4; + device->FOAOut.NumChannels = 0; + + device->RealOut.NumChannels = 0; InitDistanceComp(device, conf, speakermap); } @@ -774,28 +781,36 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; } else { memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) - for(i = 0;i < 4;i++) + { + count = 4; + for(i = 0;i < count;i++) { device->FOAOut.Ambi.Map[i].Scale = 1.0f; device->FOAOut.Ambi.Map[i].Index = i; } + } else { static const int map[3] = { 0, 1, 3 }; - for(i = 0;i < 3;i++) + count = 3; + for(i = 0;i < count;i++) { device->FOAOut.Ambi.Map[i].Scale = 1.0f; device->FOAOut.Ambi.Map[i].Index = map[i]; } } device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = count; } + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + InitDistanceComp(device, conf, speakermap); } @@ -868,6 +883,7 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; } else { @@ -878,10 +894,13 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) device->FOAOut.Ambi.Map[i].Index = i; } device->FOAOut.CoeffCount = 0; + device->FOAOut.NumChannels = 4; ambiup_reset(device->AmbiUp, device); } + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs)); device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle, device->Hrtf.Coeffs, device->Dry.NumChannels, @@ -908,6 +927,9 @@ static void InitUhjPanning(ALCdevice *device) device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); } void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) -- cgit v1.2.3 From e0e6efbfeac7bb07dce82b63b7688648e1067da3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 10:17:48 -0800 Subject: Print warnings about missing libraries and functions --- Alc/backends/alsa.c | 9 ++++++++- Alc/backends/jack.c | 9 ++++++++- Alc/backends/pulseaudio.c | 8 ++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 7a9045bb..2fa806ae 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -199,15 +199,21 @@ static ALCboolean alsa_load(void) #ifdef HAVE_DYNLOAD if(!alsa_handle) { + al_string missing_funcs = AL_STRING_INIT_STATIC(); + alsa_handle = LoadLib("libasound.so.2"); if(!alsa_handle) + { + WARN("Failed to load %s\n", "libasound.so.2"); return ALC_FALSE; + } error = ALC_FALSE; #define LOAD_FUNC(f) do { \ p##f = GetSymbol(alsa_handle, #f); \ if(p##f == NULL) { \ error = ALC_TRUE; \ + al_string_append_cstr(&missing_funcs, "\n" #f); \ } \ } while(0) ALSA_FUNCS(LOAD_FUNC); @@ -215,10 +221,11 @@ static ALCboolean alsa_load(void) if(error) { + WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); CloseLib(alsa_handle); alsa_handle = NULL; - return ALC_FALSE; } + al_string_deinit(&missing_funcs); } #endif diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index fa04c594..f1cd82bd 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -96,6 +96,8 @@ static ALCboolean jack_load(void) #ifdef HAVE_DYNLOAD if(!jack_handle) { + al_string missing_funcs = AL_STRING_INIT_STATIC(); + #ifdef _WIN32 #define JACKLIB "libjack.dll" #else @@ -103,13 +105,17 @@ static ALCboolean jack_load(void) #endif jack_handle = LoadLib(JACKLIB); if(!jack_handle) + { + WARN("Failed to load %s\n", JACKLIB); return ALC_FALSE; + } error = ALC_FALSE; #define LOAD_FUNC(f) do { \ p##f = GetSymbol(jack_handle, #f); \ if(p##f == NULL) { \ error = ALC_TRUE; \ + al_string_append_cstr(&missing_funcs, "\n" #f); \ } \ } while(0) JACK_FUNCS(LOAD_FUNC); @@ -117,10 +123,11 @@ static ALCboolean jack_load(void) if(error) { + WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); CloseLib(jack_handle); jack_handle = NULL; - return ALC_FALSE; } + al_string_deinit(&missing_funcs); } #endif diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index fa07da3e..14b37ee6 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -182,6 +182,8 @@ static ALCboolean pulse_load(void) #ifdef HAVE_DYNLOAD if(!pa_handle) { + al_string missing_funcs = AL_STRING_INIT_STATIC(); + #ifdef _WIN32 #define PALIB "libpulse-0.dll" #elif defined(__APPLE__) && defined(__MACH__) @@ -191,12 +193,16 @@ static ALCboolean pulse_load(void) #endif pa_handle = LoadLib(PALIB); if(!pa_handle) + { + WARN("Failed to load %s\n", PALIB); return ALC_FALSE; + } #define LOAD_FUNC(x) do { \ p##x = GetSymbol(pa_handle, #x); \ if(!(p##x)) { \ ret = ALC_FALSE; \ + al_string_append_cstr(&missing_funcs, "\n" #x); \ } \ } while(0) LOAD_FUNC(pa_context_unref); @@ -270,9 +276,11 @@ static ALCboolean pulse_load(void) if(ret == ALC_FALSE) { + WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); CloseLib(pa_handle); pa_handle = NULL; } + al_string_deinit(&missing_funcs); } #endif /* HAVE_DYNLOAD */ return ret; -- cgit v1.2.3 From cd24e42b3f7887867735db2cd35a0c4137163379 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 11:17:47 -0800 Subject: Make the voices' Send[] array dynamically sized The voices are still all allocated in one chunk to avoid memory fragmentation. But they're accessed as an array of pointers since the size isn't static. --- Alc/ALc.c | 40 ++++++++++++++++++++++++++++------------ Alc/ALu.c | 22 +++++++++++----------- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 16 ++++++++-------- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c831ca9d..5a382d6e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2607,21 +2607,26 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) ALsizei num_sends = device->NumAuxSends; struct ALsourceProps *props; size_t sizeof_props; - ALvoice *voices; + size_t sizeof_voice; + ALvoice **voices; + ALvoice *voice; ALsizei v = 0; size_t size; if(num_voices == context->MaxVoices && num_sends == old_sends) return; - /* Allocate the voices, and the voices' stored source property set - * (including the dynamically-sized Send[] array) in one chunk. + /* Allocate the voice pointers, voices, and the voices' stored source + * property set (including the dynamically-sized Send[] array) in one + * chunk. */ sizeof_props = RoundUp(offsetof(struct ALsourceProps, Send[num_sends]), 16); - size = sizeof(*voices) + sizeof_props; + sizeof_voice = RoundUp(offsetof(ALvoice, Send[num_sends]), 16); + size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; - voices = al_calloc(16, size * num_voices); - props = (struct ALsourceProps*)(voices + num_voices); + voices = al_calloc(16, RoundUp(size*num_voices, 16)); + voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); + props = (struct ALsourceProps*)((char*)voice + num_voices*sizeof_voice); if(context->Voices) { @@ -2634,23 +2639,34 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) /* Copy the old voice data and source property set to the new * storage. */ - voices[v] = context->Voices[v]; - *props = *(context->Voices[v].Props); + *voice = *(context->Voices[v]); for(i = 0;i < s_count;i++) - props->Send[i] = context->Voices[v].Props->Send[i]; + voice->Send[i] = context->Voices[v]->Send[i]; + *props = *(context->Voices[v]->Props); + for(i = 0;i < s_count;i++) + props->Send[i] = context->Voices[v]->Props->Send[i]; /* Set this voice's property set pointer and increment 'props' to * the next property storage space. */ - voices[v].Props = props; + voice->Props = props; props = (struct ALsourceProps*)((char*)props + sizeof_props); + + /* Set this voice's reference and increment 'voice' to the next + * voice storage space. + */ + voices[v] = voice; + voice = (ALvoice*)((char*)voice + sizeof_voice); } } - /* Finish setting the voices' property set pointers. */ + /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) { - voices[v].Props = props; + voice->Props = props; props = (struct ALsourceProps*)((char*)props + sizeof_props); + + voices[v] = voice; + voice = (ALvoice*)((char*)voice + sizeof_voice); } al_free(context->Voices); diff --git a/Alc/ALu.c b/Alc/ALu.c index 1fca0ed0..edb23128 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1313,7 +1313,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) { - ALvoice *voice, *voice_end; + ALvoice **voice, **voice_end; ALsource *source; IncrementRef(&ctx->UpdateCount); @@ -1330,11 +1330,11 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - if(!(source=voice->Source)) continue; + if(!(source=(*voice)->Source)) continue; if(!IsPlayingOrPaused(source)) - voice->Source = NULL; + (*voice)->Source = NULL; else - CalcSourceParams(voice, ctx, force); + CalcSourceParams(*voice, ctx, force); } } IncrementRef(&ctx->UpdateCount); @@ -1424,7 +1424,7 @@ DECL_TEMPLATE(ALbyte, aluF2B) void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALsizei SamplesToDo; - ALvoice *voice, *voice_end; + ALvoice **voice, **voice_end; ALeffectslot *slot; ALsource *source; ALCcontext *ctx; @@ -1475,11 +1475,11 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - ALboolean IsVoiceInit = (voice->Step > 0); - source = voice->Source; + ALboolean IsVoiceInit = ((*voice)->Step > 0); + source = (*voice)->Source; if(IsVoiceInit && source && ATOMIC_LOAD(&source->state, almemory_order_relaxed) == AL_PLAYING) - MixSource(voice, source, device, SamplesToDo); + MixSource(*voice, source, device, SamplesToDo); } /* effect slot processing */ @@ -1637,15 +1637,15 @@ void aluHandleDisconnect(ALCdevice *device) Context = ATOMIC_LOAD_SEQ(&device->ContextList); while(Context) { - ALvoice *voice, *voice_end; + ALvoice **voice, **voice_end; voice = Context->Voices; voice_end = voice + Context->VoiceCount; while(voice != voice_end) { ALenum playing = AL_PLAYING; - ALsource *source = voice->Source; - voice->Source = NULL; + ALsource *source = (*voice)->Source; + (*voice)->Source = NULL; if(source && ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &source->state, &playing, AL_STOPPED)) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bb8a57ce..76862f38 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -812,7 +812,7 @@ struct ALCcontext_struct { ALfloat GainBoost; - struct ALvoice *Voices; + struct ALvoice **Voices; ALsizei VoiceCount; ALsizei MaxVoices; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index c63aef70..53e9a2f4 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -106,7 +106,7 @@ typedef struct ALvoice { ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; - } Send[MAX_SENDS]; + } Send[]; } ALvoice; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 395bc8c2..c541884b 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -128,12 +128,12 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context) { - ALvoice *voice = context->Voices; - ALvoice *voice_end = voice + context->VoiceCount; + ALvoice **voice = context->Voices; + ALvoice **voice_end = voice + context->VoiceCount; while(voice != voice_end) { - if(voice->Source == source) - return voice; + if((*voice)->Source == source) + return *voice; ++voice; } return NULL; @@ -2915,7 +2915,7 @@ void UpdateAllSourceProps(ALCcontext *context) for(pos = 0;pos < context->VoiceCount;pos++) { - ALvoice *voice = &context->Voices[pos]; + ALvoice *voice = context->Voices[pos]; ALsource *source = voice->Source; if(source != NULL && source->NeedsUpdate && IsPlayingOrPaused(source)) { @@ -2982,16 +2982,16 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { for(i = 0;i < Context->VoiceCount;i++) { - if(Context->Voices[i].Source == NULL) + if(Context->Voices[i]->Source == NULL) { - voice = &Context->Voices[i]; + voice = Context->Voices[i]; voice->Source = Source; break; } } if(voice == NULL) { - voice = &Context->Voices[Context->VoiceCount++]; + voice = Context->Voices[Context->VoiceCount++]; voice->Source = Source; } discontinuity = AL_TRUE; -- cgit v1.2.3 From 29994aa2de828ce96950451219186b44bac54a75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 12:29:25 -0800 Subject: Interleave the voice and source property objects --- Alc/ALc.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 5a382d6e..3d49538f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2625,8 +2625,11 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; voices = al_calloc(16, RoundUp(size*num_voices, 16)); + /* The voice and property objects are stored interleaved since they're + * paired together. + */ voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - props = (struct ALsourceProps*)((char*)voice + num_voices*sizeof_voice); + props = (struct ALsourceProps*)((char*)voice + sizeof_voice); if(context->Voices) { @@ -2646,27 +2649,23 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) for(i = 0;i < s_count;i++) props->Send[i] = context->Voices[v]->Props->Send[i]; - /* Set this voice's property set pointer and increment 'props' to - * the next property storage space. - */ + /* Set this voice's property set pointer and voice reference. */ voice->Props = props; - props = (struct ALsourceProps*)((char*)props + sizeof_props); - - /* Set this voice's reference and increment 'voice' to the next - * voice storage space. - */ voices[v] = voice; - voice = (ALvoice*)((char*)voice + sizeof_voice); + + /* Increment pointers to the next storage space. */ + voice = (ALvoice*)((char*)props + sizeof_props); + props = (struct ALsourceProps*)((char*)voice + sizeof_voice); } } /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) { voice->Props = props; - props = (struct ALsourceProps*)((char*)props + sizeof_props); - voices[v] = voice; - voice = (ALvoice*)((char*)voice + sizeof_voice); + + voice = (ALvoice*)((char*)props + sizeof_props); + props = (struct ALsourceProps*)((char*)voice + sizeof_voice); } al_free(context->Voices); -- cgit v1.2.3 From 864d5387dda119d9faecfd62226b62f1a8af8532 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 16:31:59 -0800 Subject: Dynamically allocate the ALsource Send[] array --- Alc/ALc.c | 102 +++++++++++++++++++++++++------------------- Alc/mixer.c | 2 +- OpenAL32/Include/alMain.h | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 55 ++++++++++++++---------- 5 files changed, 94 insertions(+), 69 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3d49538f..e63323b4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1766,15 +1766,17 @@ static inline void UpdateClockBase(ALCdevice *device) */ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { - ALCcontext *context; - enum HrtfRequestMode hrtf_appreq = Hrtf_Default; enum HrtfRequestMode hrtf_userreq = Hrtf_Default; - ALsizei old_sends = device->NumAuxSends; + enum HrtfRequestMode hrtf_appreq = Hrtf_Default; + const ALsizei old_sends = device->NumAuxSends; + ALsizei new_sends = device->NumAuxSends; enum DevFmtChannels oldChans; enum DevFmtType oldType; + ALboolean update_failed; + ALCsizei hrtf_id = -1; + ALCcontext *context; ALCuint oldFreq; FPUCtl oldMode; - ALCsizei hrtf_id = -1; size_t size; // Check for attributes @@ -1800,10 +1802,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) numMono = device->NumMonoSources; numStereo = device->NumStereoSources; - numSends = device->NumAuxSends; schans = device->FmtChans; stype = device->FmtType; freq = device->Frequency; + numSends = old_sends; #define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) while(attrList[attrIdx]) @@ -1880,9 +1882,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_VALUE; } - ConfigValueUInt(NULL, NULL, "sends", &numSends); - numSends = minu(MAX_SENDS, numSends); - if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; @@ -1894,7 +1893,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FmtType = stype; device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - device->NumAuxSends = numSends; + + ConfigValueUInt(NULL, NULL, "sends", &numSends); + new_sends = clampi(numSends, 1, MAX_SENDS); } else if(attrList && attrList[0]) { @@ -1907,10 +1908,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; + UpdateClockBase(device); + freq = device->Frequency; numMono = device->NumMonoSources; numStereo = device->NumStereoSources; - numSends = device->NumAuxSends; + numSends = old_sends; #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) @@ -1962,11 +1965,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); - ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); - numSends = minu(MAX_SENDS, numSends); - - UpdateClockBase(device); - device->UpdateSize = (ALuint64)device->UpdateSize * freq / device->Frequency; /* SSE and Neon do best with the update size being a multiple of 4 */ @@ -1976,7 +1974,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Frequency = freq; device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - device->NumAuxSends = numSends; + + ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); + new_sends = clampi(numSends, 1, MAX_SENDS); } if((device->Flags&DEVICE_RUNNING)) @@ -2148,6 +2148,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FOAOut.NumChannels = device->Dry.NumChannels; } + /* Need to delay returning failure until replacement Send arrays have been + * allocated with the appropriate size. + */ + device->NumAuxSends = new_sends; + update_failed = AL_FALSE; SetMixerFPUMode(&oldMode); if(device->DefaultSlot) { @@ -2157,11 +2162,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) state->OutBuffer = device->Dry.Buffer; state->OutChannels = device->Dry.NumChannels; if(V(state,deviceUpdate)(device) == AL_FALSE) - { - RestoreFPUMode(&oldMode); - return ALC_INVALID_DEVICE; - } - UpdateEffectSlotProps(slot); + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot); } context = ATOMIC_LOAD_SEQ(&device->ContextList); @@ -2179,14 +2182,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) state->OutBuffer = device->Dry.Buffer; state->OutChannels = device->Dry.NumChannels; if(V(state,deviceUpdate)(device) == AL_FALSE) - { - UnlockUIntMapRead(&context->EffectSlotMap); - ReadUnlock(&context->PropLock); - RestoreFPUMode(&oldMode); - return ALC_INVALID_DEVICE; - } - - UpdateEffectSlotProps(slot); + update_failed = AL_TRUE; + else + UpdateEffectSlotProps(slot); } UnlockUIntMapRead(&context->EffectSlotMap); @@ -2195,25 +2193,39 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALsource *source = context->SourceMap.values[pos]; struct ALsourceProps *props; - ALsizei s; - for(s = device->NumAuxSends;s < MAX_SENDS;s++) + if(old_sends != device->NumAuxSends) { - if(source->Send[s].Slot) - DecrementRef(&source->Send[s].Slot->ref); - source->Send[s].Slot = NULL; - source->Send[s].Gain = 1.0f; - source->Send[s].GainHF = 1.0f; - source->Send[s].HFReference = LOWPASSFREQREF; - source->Send[s].GainLF = 1.0f; - source->Send[s].LFReference = HIGHPASSFREQREF; + ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); + ALsizei s; + + memcpy(sends, source->Send, + mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) + ); + for(s = device->NumAuxSends;s < old_sends;s++) + { + if(source->Send[s].Slot) + DecrementRef(&source->Send[s].Slot->ref); + source->Send[s].Slot = NULL; + } + al_free(source->Send); + source->Send = sends; + for(s = old_sends;s < device->NumAuxSends;s++) + { + source->Send[s].Slot = NULL; + source->Send[s].Gain = 1.0f; + source->Send[s].GainHF = 1.0f; + source->Send[s].HFReference = LOWPASSFREQREF; + source->Send[s].GainLF = 1.0f; + source->Send[s].LFReference = HIGHPASSFREQREF; + } } source->NeedsUpdate = AL_TRUE; /* Clear any pre-existing source property structs, in case the * number of auxiliary sends changed. Playing (or paused) sources - * will have updates specified. + * will have updates respecified in UpdateAllSourceProps. */ props = ATOMIC_EXCHANGE_SEQ(struct ALsourceProps*, &source->Update, NULL); al_free(props); @@ -2237,6 +2249,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = context->next; } RestoreFPUMode(&oldMode); + if(update_failed) + return ALC_INVALID_DEVICE; if(!(device->Flags&DEVICE_PAUSED)) { @@ -3720,8 +3734,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; - ConfigValueUInt(deviceName, NULL, "sends", &device->NumAuxSends); - if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; + ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends); + device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; @@ -4126,8 +4140,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; - ConfigValueUInt(NULL, NULL, "sends", &device->NumAuxSends); - if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; + ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends); + device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; diff --git a/Alc/mixer.c b/Alc/mixer.c index a48b0e29..46ca0892 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -381,7 +381,7 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp ALsizei Counter; ALsizei IrSize; ALsizei chan, j; - ALuint send; + ALsizei send; /* Get source info */ State = AL_PLAYING; /* Only called while playing. */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 76862f38..0b467403 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -648,7 +648,7 @@ struct ALCdevice_struct ALCuint NumMonoSources; ALCuint NumStereoSources; - ALuint NumAuxSends; + ALsizei NumAuxSends; // Map of Buffers for this device UIntMap BufferMap; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 53e9a2f4..72b05fc8 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -161,7 +161,7 @@ typedef struct ALsource { ALfloat HFReference; ALfloat GainLF; ALfloat LFReference; - } Send[MAX_SENDS]; + } *Send; /** * Last user-specified offset, and the offset type (bytes, samples, or diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c541884b..1b3f4c56 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -48,9 +48,9 @@ extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); extern inline ALboolean IsPlayingOrPaused(const ALsource *source); -static void InitSourceParams(ALsource *Source); -static void DeinitSource(ALsource *source); -static void UpdateSourceProps(ALsource *source, ALuint num_sends); +static void InitSourceParams(ALsource *Source, ALsizei num_sends); +static void DeinitSource(ALsource *source, ALsizei num_sends); +static void UpdateSourceProps(ALsource *source, ALsizei num_sends); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); @@ -816,7 +816,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: LockEffectSlotsRead(Context); LockFiltersRead(device); - if(!((ALuint)values[1] < device->NumAuxSends && + if(!((ALuint)values[1] < (ALuint)device->NumAuxSends && (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) { @@ -1539,6 +1539,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) { + ALCdevice *device; ALCcontext *context; ALsizei cur = 0; ALenum err; @@ -1548,6 +1549,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + device = context->Device; for(cur = 0;cur < n;cur++) { ALsource *source = al_calloc(16, sizeof(ALsource)); @@ -1556,7 +1558,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) alDeleteSources(cur, sources); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } - InitSourceParams(source); + InitSourceParams(source, device->NumAuxSends); err = NewThunkEntry(&source->id); if(err == AL_NO_ERROR) @@ -1581,6 +1583,7 @@ done: AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) { + ALCdevice *device; ALCcontext *context; ALsource *Source; ALsizei i; @@ -1598,6 +1601,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) if(LookupSource(context, sources[i]) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } + device = context->Device; for(i = 0;i < n;i++) { ALvoice *voice; @@ -1606,12 +1610,12 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) continue; FreeThunkEntry(Source->id); - ALCdevice_Lock(context->Device); + ALCdevice_Lock(device); voice = GetSourceVoice(Source, context); if(voice) voice->Source = NULL; - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); - DeinitSource(Source); + DeinitSource(Source, device->NumAuxSends); memset(Source, 0, sizeof(*Source)); al_free(Source); @@ -2692,9 +2696,9 @@ done: } -static void InitSourceParams(ALsource *Source) +static void InitSourceParams(ALsource *Source, ALsizei num_sends) { - ALuint i; + ALsizei i; RWLockInit(&Source->queue_lock); @@ -2745,7 +2749,8 @@ static void InitSourceParams(ALsource *Source) Source->Direct.HFReference = LOWPASSFREQREF; Source->Direct.GainLF = 1.0f; Source->Direct.LFReference = HIGHPASSFREQREF; - for(i = 0;i < MAX_SENDS;i++) + Source->Send = al_calloc(16, num_sends*sizeof(Source->Send[0])); + for(i = 0;i < num_sends;i++) { Source->Send[i].Slot = NULL; Source->Send[i].Gain = 1.0f; @@ -2775,12 +2780,12 @@ static void InitSourceParams(ALsource *Source) ATOMIC_INIT(&Source->FreeList, NULL); } -static void DeinitSource(ALsource *source) +static void DeinitSource(ALsource *source, ALsizei num_sends) { ALbufferlistitem *BufferList; struct ALsourceProps *props; size_t count = 0; - size_t i; + ALsizei i; props = ATOMIC_LOAD_SEQ(&source->Update); if(props) al_free(props); @@ -2810,18 +2815,23 @@ static void DeinitSource(ALsource *source) BufferList = next; } - for(i = 0;i < MAX_SENDS;i++) + if(source->Send) { - if(source->Send[i].Slot) - DecrementRef(&source->Send[i].Slot->ref); - source->Send[i].Slot = NULL; + for(i = 0;i < num_sends;i++) + { + if(source->Send[i].Slot) + DecrementRef(&source->Send[i].Slot->ref); + source->Send[i].Slot = NULL; + } + al_free(source->Send); + source->Send = NULL; } } -static void UpdateSourceProps(ALsource *source, ALuint num_sends) +static void UpdateSourceProps(ALsource *source, ALsizei num_sends) { struct ALsourceProps *props; - size_t i; + ALsizei i; /* Get an unused property container, or allocate a new one as needed. */ props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); @@ -2856,7 +2866,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed); for(i = 0;i < 2;i++) { - size_t j; + ALsizei j; for(j = 0;j < 3;j++) ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j], almemory_order_relaxed); @@ -2910,7 +2920,7 @@ static void UpdateSourceProps(ALsource *source, ALuint num_sends) void UpdateAllSourceProps(ALCcontext *context) { - ALuint num_sends = context->Device->NumAuxSends; + ALsizei num_sends = context->Device->NumAuxSends; ALsizei pos; for(pos = 0;pos < context->VoiceCount;pos++) @@ -3390,13 +3400,14 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) */ ALvoid ReleaseALSources(ALCcontext *Context) { + ALCdevice *device = Context->Device; ALsizei pos; for(pos = 0;pos < Context->SourceMap.size;pos++) { ALsource *temp = Context->SourceMap.values[pos]; Context->SourceMap.values[pos] = NULL; - DeinitSource(temp); + DeinitSource(temp, device->NumAuxSends); FreeThunkEntry(temp->id); memset(temp, 0, sizeof(*temp)); -- cgit v1.2.3 From d3cc867bd42759cb8e294d691354187984f96ff4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 16:54:55 -0800 Subject: Increase the default effect slot and send count The default number of auxiliary effect slots is now 64. This can still be raised by the config file without a hard maximum, but incurs processing cost for each effect slot generated by the app. The default number of source sends is now actually 2, as per the EFX docs. However, it can be raised up to 16 via ALC_MAX_AUXILIARY_SENDS attribute requests, rather than the previous 4. --- Alc/ALc.c | 28 +++++++++++++++------------- OpenAL32/Include/alSource.h | 3 ++- alsoftrc.sample | 4 ++-- utils/alsoft-config/mainwindow.cpp | 4 ++-- utils/alsoft-config/mainwindow.ui | 6 +++--- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e63323b4..e33f397b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1788,11 +1788,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) GotType = 1<<2, GotAll = GotFreq|GotChans|GotType }; - ALCuint freq, numMono, numStereo, numSends; + ALCuint freq, numMono, numStereo; enum DevFmtChannels schans; enum DevFmtType stype; ALCuint attrIdx = 0; ALCint gotFmt = 0; + ALCsizei numSends; if(!attrList) { @@ -1894,13 +1895,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - ConfigValueUInt(NULL, NULL, "sends", &numSends); - new_sends = clampi(numSends, 1, MAX_SENDS); + ConfigValueInt(NULL, NULL, "sends", &numSends); + new_sends = clampi(numSends, 0, MAX_SENDS); } else if(attrList && attrList[0]) { - ALCuint freq, numMono, numStereo, numSends; + ALCuint freq, numMono, numStereo; ALCuint attrIdx = 0; + ALCsizei numSends; /* If a context is already running on the device, stop playback so the * device attributes can be updated. */ @@ -1921,8 +1923,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_FREQUENCY) { freq = attrList[attrIdx + 1]; - device->Flags |= DEVICE_FREQUENCY_REQUEST; TRACE_ATTR(ALC_FREQUENCY, freq); + device->Flags |= DEVICE_FREQUENCY_REQUEST; } if(attrList[attrIdx] == ALC_STEREO_SOURCES) @@ -1975,8 +1977,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); - new_sends = clampi(numSends, 1, MAX_SENDS); + ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); + new_sends = clampi(numSends, 0, MAX_SENDS); } if((device->Flags&DEVICE_RUNNING)) @@ -3620,8 +3622,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->SamplesDone = 0; device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 4; - device->NumAuxSends = MAX_SENDS; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); @@ -3732,7 +3734,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(device->SourcesMax == 0) device->SourcesMax = 256; ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends); device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); @@ -4107,8 +4109,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->SamplesDone = 0; device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 4; - device->NumAuxSends = MAX_SENDS; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); @@ -4138,7 +4140,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN if(device->SourcesMax == 0) device->SourcesMax = 256; ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); - if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends); device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 72b05fc8..8889ed24 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -1,7 +1,8 @@ #ifndef _AL_SOURCE_H_ #define _AL_SOURCE_H_ -#define MAX_SENDS 4 +#define MAX_SENDS 16 +#define DEFAULT_SENDS 2 #include "alMain.h" #include "alu.h" diff --git a/alsoftrc.sample b/alsoftrc.sample index 52e93ad1..d676c8aa 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -173,12 +173,12 @@ # 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. -#slots = 4 +#slots = 64 ## sends: # Sets the number of auxiliary sends per source. When not specified (default), # it allows the app to request how many it wants. The maximum value currently -# possible is 4. +# possible is 16. #sends = ## volume-adjust: diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index e4dc10fc..200f6811 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -295,9 +295,9 @@ MainWindow::MainWindow(QWidget *parent) : mSourceCountValidator = new QIntValidator(0, 4096, this); ui->srcCountLineEdit->setValidator(mSourceCountValidator); - mEffectSlotValidator = new QIntValidator(0, 16, this); + mEffectSlotValidator = new QIntValidator(0, 64, this); ui->effectSlotLineEdit->setValidator(mEffectSlotValidator); - mSourceSendValidator = new QIntValidator(0, 4, this); + mSourceSendValidator = new QIntValidator(0, 16, this); ui->srcSendLineEdit->setValidator(mSourceSendValidator); mSampleRateValidator = new QIntValidator(8000, 192000, this); ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index afb91996..b886dc00 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1649,13 +1649,13 @@ may help when apps use more than the system can handle. - 1 + 3 true - 4 + 64 @@ -1686,7 +1686,7 @@ may help when apps use more than the system can handle. 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. +value currently possible is 16. 1 -- cgit v1.2.3 From 2dd142fed006549655bd55d3dc80388fe7e36e2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 17:19:02 -0800 Subject: Make the "sends" config option act as a limit Instead of forcing the device to always use the specified send count, it simply limits requests to it. --- Alc/ALc.c | 24 ++++++++++++++++-------- alsoftrc.sample | 7 +++---- utils/alsoft-config/mainwindow.ui | 23 +++++------------------ 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e33f397b..f91fc09b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1895,8 +1895,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - ConfigValueInt(NULL, NULL, "sends", &numSends); - new_sends = clampi(numSends, 0, MAX_SENDS); + if(ConfigValueInt(NULL, NULL, "sends", &new_sends)) + new_sends = clampi(numSends, 0, clampi(new_sends, 0, MAX_SENDS)); + else + new_sends = clampi(numSends, 0, MAX_SENDS); } else if(attrList && attrList[0]) { @@ -1977,8 +1979,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); - new_sends = clampi(numSends, 0, MAX_SENDS); + if(ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &new_sends)) + new_sends = clampi(numSends, 0, clampi(new_sends, 0, MAX_SENDS)); + else + new_sends = clampi(numSends, 0, MAX_SENDS); } if((device->Flags&DEVICE_RUNNING)) @@ -3736,8 +3740,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends); - device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); + if(ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends)) + device->NumAuxSends = clampi( + DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) + ); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; @@ -4142,8 +4148,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; - ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends); - device->NumAuxSends = clampi(device->NumAuxSends, 0, MAX_SENDS); + if(ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends)) + device->NumAuxSends = clampi( + DEFAULT_SENDS, 0, clampi(device->NumAuxSends, 0, MAX_SENDS) + ); device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; diff --git a/alsoftrc.sample b/alsoftrc.sample index d676c8aa..3cc205b0 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -176,10 +176,9 @@ #slots = 64 ## sends: -# Sets the number of auxiliary sends per source. When not specified (default), -# it allows the app to request how many it wants. The maximum value currently -# possible is 16. -#sends = +# Limits the number of auxiliary sends allowed per source. Setting this higher +# than the default has no effect. +#sends = 16 ## volume-adjust: # A global volume adjustment for source output, expressed in decibels. The diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index b886dc00..e074d63b 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -1585,14 +1585,8 @@ during updates. help for systems with apps that try to play more sounds than the CPU can handle. - - - - 3 - - - true + 4 256 @@ -1645,15 +1639,9 @@ 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. - - - 3 - - true - 64 @@ -1684,15 +1672,14 @@ may help when apps use more than the system can handle. - 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 16. + Limits the number of auxiliary sends allowed per source. +Setting this higher than the default has no effect. - 1 + 2 - Auto + 16 -- cgit v1.2.3 From 5181e78c1ed098866df7b498de335fb25022f97e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Feb 2017 18:28:09 -0800 Subject: Reduce some code --- Alc/ALu.c | 94 ++++++++++++++++++++++----------------------------------------- 1 file changed, 33 insertions(+), 61 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index edb23128..503fde6c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -541,23 +541,19 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) { for(c = 0;c < num_channels;c++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } + ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, + matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target + ); } else { for(c = 0;c < num_channels;c++) - { - const ALeffectslot *Slot = SendSlots[i]; - ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, - matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - } + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } @@ -589,18 +585,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } - else - { - const ALeffectslot *Slot = SendSlots[i]; + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - } + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } @@ -647,18 +639,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } - else - { - const ALeffectslot *Slot = SendSlots[i]; + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - } + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } @@ -683,7 +671,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(i = 0;i < NumSends;i++) { - ALuint j; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Direct.Params[c].Gains.Target[j] = 0.0f; } @@ -711,19 +698,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) - { - ALuint j; - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } - else - { - const ALeffectslot *Slot = SendSlots[i]; + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - } + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } @@ -808,7 +790,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro ALfloat Pitch; ALuint Frequency; ALint NumSends; - ALint i; + ALint i, j; /* Get context/device properties */ DopplerFactor = Listener->Params.DopplerFactor; @@ -1159,19 +1141,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) - { - ALuint j; - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[0].Gains.Target[j] = 0.0f; - } - else - { - const ALeffectslot *Slot = SendSlots[i]; + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target ); - } + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } voice->IsHrtf = AL_TRUE; @@ -1217,19 +1194,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro for(i = 0;i < NumSends;i++) { - if(!SendSlots[i]) - { - ALuint j; - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[0].Gains.Target[j] = 0.0f; - } - else - { - const ALeffectslot *Slot = SendSlots[i]; + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target ); - } + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } voice->IsHrtf = AL_FALSE; -- cgit v1.2.3 From e720faf2d40e9e4ec27479ffbbcba1a3b3838956 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 15:00:41 -0800 Subject: Fix OpenSL latency calculation --- Alc/backends/opensl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index a667dc70..b8d6d29a 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -694,8 +694,8 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) ALCopenslPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ll_ringbuffer_read_space(self->mRing) * DEVICE_CLOCK_RES / - device->Frequency; + ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize * + DEVICE_CLOCK_RES / device->Frequency; ALCopenslPlayback_unlock(self); return ret; -- cgit v1.2.3 From 2e1f1449bc7bd9f50822298577be203693deca7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 15:44:47 -0800 Subject: Don't remove a period from the OSS buffer Since we're now waiting for space to be available before mixing, the mixing buffer isn't adding another period. --- Alc/backends/oss.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 8934181b..b22e87ba 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -419,17 +419,10 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) periods = device->NumUpdates; numChannels = ChannelsFromDevFmt(device->FmtChans); - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - ossSpeed = device->Frequency; - log2FragmentSize = log2i(device->UpdateSize * frameSize); - - /* according to the OSS spec, 16 bytes are the minimum */ - if (log2FragmentSize < 4) - log2FragmentSize = 4; - /* Subtract one period since the temp mixing buffer counts as one. Still - * need at least two on the card, though. */ - if(periods > 2) periods--; + frameSize = numChannels * BytesFromDevFmt(device->FmtType); + /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ + log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4); numFragmentsLogSize = (periods << 16) | log2FragmentSize; #define CHECKERR(func) if((func) < 0) { \ @@ -467,7 +460,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) device->Frequency = ossSpeed; device->UpdateSize = info.fragsize / frameSize; - device->NumUpdates = info.fragments + 1; + device->NumUpdates = info.fragments; SetDefaultChannelOrder(device); -- cgit v1.2.3 From 55e3b840b351d59e9e746080ab0eac93fea93e04 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 15:56:09 -0800 Subject: Reduce the default period count to 3 --- Alc/ALc.c | 2 +- alsoftrc.sample | 2 +- utils/alsoft-config/mainwindow.ui | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f91fc09b..c829d8e7 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3639,7 +3639,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Frequency = DEFAULT_OUTPUT_RATE; device->IsHeadphones = AL_FALSE; device->AmbiFmt = AmbiFormat_Default; - device->NumUpdates = 4; + device->NumUpdates = 3; device->UpdateSize = 1024; if(!PlaybackBackend.getFactory) diff --git a/alsoftrc.sample b/alsoftrc.sample index 3cc205b0..df6bb326 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -81,7 +81,7 @@ # which helps protect against skips when the CPU is under load, but increases # the delay between a sound getting mixed and being heard. Acceptable values # range between 2 and 16. -#periods = 4 +#periods = 3 ## stereo-mode: # Specifies if stereo output is treated as being headphones or speakers. With diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index e074d63b..4db93c36 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -343,7 +343,7 @@ mixed and being heard. - 4 + 3 -- cgit v1.2.3 From 629980d15ee8f87c916cefee79bbb692e34a1266 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 16:31:24 -0800 Subject: Update ChangeLog --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 18bcf251..6663dd03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,14 @@ openal-soft-1.18.0: Added an option to the example apps to open a specific device. + Increased the maximum auxiliary send limit to 16 (up from 4). Requires + requesting them with the ALC_MAX_AUXILIARY_SENDS context creation + attribute. + + Increased the default auxiliary effect slot count to 64 (up from 4). + + Reduced the default period count to 3 (down from 4). + Slightly improved automatic naming for enumerated HRTFs. Improved B-Format decoding with HRTF output. -- cgit v1.2.3 From d04cc28f33c5a21273fc42c023b41dbcfa89632b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 18:07:41 -0800 Subject: Limit filter gains to -24dB --- Alc/ALu.c | 58 ++++++++++++++++++++++--------------------------- Alc/effects/echo.c | 2 +- Alc/effects/equalizer.c | 8 +++---- Alc/effects/reverb.c | 4 ++-- OpenAL32/alFilter.c | 2 +- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 503fde6c..d2c2ec19 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -374,6 +374,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; ALeffectslot *SendSlots[MAX_SENDS]; + ALfloat HFScale, LFScale; ALuint NumSends, Frequency; ALboolean Relative; const struct ChanMap *chans = NULL; @@ -714,12 +715,10 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } { - ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / - Frequency; - ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / - Frequency; - DryGainHF = maxf(DryGainHF, 0.0001f); - DryGainLF = maxf(DryGainLF, 0.0001f); + HFScale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / Frequency; + LFScale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / Frequency; + DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ + DryGainLF = maxf(DryGainLF, 0.0625f); for(c = 0;c < num_channels;c++) { voice->Direct.Params[c].FilterType = AF_None; @@ -727,22 +726,20 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(DryGainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[c].LowPass, ALfilterType_HighShelf, - DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) + DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( &voice->Direct.Params[c].HighPass, ALfilterType_LowShelf, - DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) + DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } } for(i = 0;i < NumSends;i++) { - ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / - Frequency; - ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / - Frequency; - WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); - WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); + HFScale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / Frequency; + LFScale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / Frequency; + WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); for(c = 0;c < num_channels;c++) { voice->Send[i].Params[c].FilterType = AF_None; @@ -750,11 +747,11 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(WetGainLF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[c].LowPass, ALfilterType_HighShelf, - WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) + WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( &voice->Send[i].Params[c].HighPass, ALfilterType_LowShelf, - WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) + WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } @@ -785,6 +782,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; + ALfloat HFScale, LFScale; ALboolean WetGainAuto; ALboolean WetGainHFAuto; ALfloat Pitch; @@ -1208,42 +1206,38 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } { - ALfloat hfscale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / - Frequency; - ALfloat lfscale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / - Frequency; - DryGainHF = maxf(DryGainHF, 0.0001f); - DryGainLF = maxf(DryGainLF, 0.0001f); + HFScale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / Frequency; + LFScale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / Frequency; + DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ + DryGainLF = maxf(DryGainLF, 0.0625f); voice->Direct.Params[0].FilterType = AF_None; if(DryGainHF != 1.0f) voice->Direct.Params[0].FilterType |= AF_LowPass; if(DryGainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, - DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) + DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, - DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) + DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } for(i = 0;i < NumSends;i++) { - ALfloat hfscale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / - Frequency; - ALfloat lfscale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / - Frequency; - WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); - WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); + HFScale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / Frequency; + LFScale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / Frequency; + WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); voice->Send[i].Params[0].FilterType = AF_None; if(WetGainHF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_LowPass; if(WetGainLF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, - WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) + WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, - WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) + WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 3ad1e975..4a11d811 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -126,7 +126,7 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co state->FeedGain = props->Echo.Feedback; - gain = minf(1.0f - props->Echo.Damping, 0.01f); + gain = minf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, gain, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gain, 0.75f)); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 13826a3b..36683d79 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -138,7 +138,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * * filters' gain is for the reference frequency, which is the centerpoint * of the transition band. */ - gain = sqrtf(props->Equalizer.LowGain); + gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ freq_mult = props->Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) @@ -153,7 +153,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[0][i].a2 = state->filter[0][0].a2; } - gain = props->Equalizer.Mid1Gain; + gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); freq_mult = props->Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( @@ -169,7 +169,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[1][i].a2 = state->filter[1][0].a2; } - gain = props->Equalizer.Mid2Gain; + gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); freq_mult = props->Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( @@ -185,7 +185,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * state->filter[2][i].a2 = state->filter[2][0].a2; } - gain = sqrtf(props->Equalizer.HighGain); + gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); freq_mult = props->Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 456b25dc..afae2943 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1089,11 +1089,11 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device // Calculate the master filters hfscale = props->Reverb.HFReference / frequency; - gainhf = maxf(props->Reverb.GainHF, 0.0001f); + gainhf = maxf(props->Reverb.GainHF, 0.0625f); /* Limit -24dB */ ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); lfscale = props->Reverb.LFReference / frequency; - gainlf = maxf(props->Reverb.GainLF, 0.0001f); + gainlf = maxf(props->Reverb.GainLF, 0.0625f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); for(i = 1;i < 4;i++) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 150d84b5..855a7c6b 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -362,7 +362,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; // Limit gain to -100dB - gain = maxf(gain, 0.00001f); + assert(gain > 0.00001f); w0 = F_TAU * freq_mult; sin_w0 = sinf(w0); -- cgit v1.2.3 From 0ce4c9b8fa90df6111fb81debf583b0fc9200063 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Feb 2017 19:18:01 -0800 Subject: Rename stereo-panning option to stereo-encoding Also rename the 'paired' value to 'panpot', and make it the default. --- Alc/ALu.c | 8 ++++---- Alc/panning.c | 14 +++++++------- alsoftrc.sample | 15 ++++++++------- utils/alsoft-config/mainwindow.cpp | 24 ++++++++++++------------ utils/alsoft-config/mainwindow.ui | 16 +++++++++------- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d2c2ec19..bc48dd59 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -683,8 +683,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Params[c].Gains.Target[0] = coeffs[0] * DryGain; - voice->Direct.Params[c].Gains.Target[1] = (1.0f-coeffs[0]) * DryGain; + voice->Direct.Params[c].Gains.Target[0] = sqrtf(coeffs[0]) * DryGain; + voice->Direct.Params[c].Gains.Target[1] = sqrtf(1.0f-coeffs[0]) * DryGain; for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Params[c].Gains.Target[j] = 0.0f; @@ -1176,8 +1176,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f)); x = clampf(x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Params[0].Gains.Target[0] = x * DryGain; - voice->Direct.Params[0].Gains.Target[1] = (1.0f-x) * DryGain; + voice->Direct.Params[0].Gains.Target[0] = sqrtf(x) * DryGain; + voice->Direct.Params[0].Gains.Target[1] = sqrtf(1.0f-x) * DryGain; for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) voice->Direct.Params[0].Gains.Target[i] = 0.0f; diff --git a/Alc/panning.c b/Alc/panning.c index 70355b41..72b55792 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1143,6 +1143,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf no_hrtf: TRACE("HRTF disabled\n"); + device->Render_Mode = StereoPair; + ambiup_free(device->AmbiUp); device->AmbiUp = NULL; @@ -1154,7 +1156,6 @@ no_hrtf: { device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); - device->Render_Mode = StereoPair; TRACE("BS2B enabled\n"); InitPanning(device); return; @@ -1162,13 +1163,12 @@ no_hrtf: TRACE("BS2B disabled\n"); - device->Render_Mode = NormalRender; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) { - if(strcasecmp(mode, "paired") == 0) - device->Render_Mode = StereoPair; - else if(strcasecmp(mode, "uhj") != 0) - ERR("Unexpected stereo-panning: %s\n", mode); + if(strcasecmp(mode, "uhj") == 0) + device->Render_Mode = NormalRender; + else if(strcasecmp(mode, "panpot") != 0) + ERR("Unexpected stereo-encoding: %s\n", mode); } if(device->Render_Mode == NormalRender) { diff --git a/alsoftrc.sample b/alsoftrc.sample index df6bb326..1068e311 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -89,13 +89,14 @@ # Valid settings are auto, speakers, and headphones. #stereo-mode = auto -## stereo-panning: -# Specifies the panning method for non-HRTF stereo output. uhj (default) -# creates stereo-compatible two-channel UHJ output, which encodes some -# surround sound information, while paired uses standard pair-wise panning -# between -30 and +30 degrees. If crossfeed filters are used, uhj panning is -# disabled. -#stereo-panning = uhj +## stereo-encoding: +# Specifies the encoding method for non-HRTF stereo output. 'panpot' (default) +# uses standard amplitude panning (aka pair-wise, stereo pair, etc) between +# -30 and +30 degrees, while 'uhj' creates stereo-compatible two-channel UHJ +# output, which encodes some surround sound information into stereo output +# that can be decoded with a surround sound receiver. If crossfeed filters are +# used, UHJ is disabled. +#stereo-encoding = panpot ## ambi-format: # Specifies the channel order and normalization for the "ambi*" set of channel diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 200f6811..93641e85 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -110,10 +110,10 @@ static const struct NameValuePair { { "Headphones", "headphones" }, { "", "" } -}, stereoPanList[] = { +}, stereoEncList[] = { { "Default", "" }, + { "Pan Pot", "panpot" }, { "UHJ", "uhj" }, - { "Pair-Wise", "paired" }, { "", "" } }, ambiFormatList[] = { @@ -234,9 +234,9 @@ MainWindow::MainWindow(QWidget *parent) : for(int i = 0;stereoModeList[i].name[0];i++) ui->stereoModeCombo->addItem(stereoModeList[i].name); ui->stereoModeCombo->adjustSize(); - for(int i = 0;stereoPanList[i].name[0];i++) - ui->stereoPanningComboBox->addItem(stereoPanList[i].name); - ui->stereoPanningComboBox->adjustSize(); + for(int i = 0;stereoEncList[i].name[0];i++) + ui->stereoEncodingComboBox->addItem(stereoEncList[i].name); + ui->stereoEncodingComboBox->adjustSize(); for(int i = 0;ambiFormatList[i].name[0];i++) ui->ambiFormatComboBox->addItem(ambiFormatList[i].name); ui->ambiFormatComboBox->adjustSize(); @@ -326,7 +326,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); - connect(ui->stereoPanningComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->stereoEncodingComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -637,15 +637,15 @@ void MainWindow::loadConfig(const QString &fname) updatePeriodCountSlider(); } - QString stereopan = settings.value("stereo-panning").toString(); - ui->stereoPanningComboBox->setCurrentIndex(0); + QString stereopan = settings.value("stereo-encoding").toString(); + ui->stereoEncodingComboBox->setCurrentIndex(0); if(stereopan.isEmpty() == false) { - QString str = getNameFromValue(stereoPanList, stereopan); + QString str = getNameFromValue(stereoEncList, stereopan); if(!str.isEmpty()) { - int j = ui->stereoPanningComboBox->findText(str); - if(j > 0) ui->stereoPanningComboBox->setCurrentIndex(j); + int j = ui->stereoEncodingComboBox->findText(str); + if(j > 0) ui->stereoEncodingComboBox->setCurrentIndex(j); } } @@ -885,7 +885,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("resampler", resamplerList[ui->resamplerSlider->value()].value); settings.setValue("stereo-mode", getValueFromName(stereoModeList, ui->stereoModeCombo->currentText())); - settings.setValue("stereo-panning", getValueFromName(stereoPanList, ui->stereoPanningComboBox->currentText())); + settings.setValue("stereo-encoding", getValueFromName(stereoEncList, ui->stereoEncodingComboBox->currentText())); settings.setValue("ambi-format", getValueFromName(ambiFormatList, ui->ambiFormatComboBox->currentText())); settings.setValue("decoder/hq-mode", diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 4db93c36..18392430 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -428,7 +428,7 @@ frames needed for each mixing update. - + 130 @@ -438,11 +438,13 @@ frames needed for each mixing update. - Selects the panning method for non-HRTF stereo -mixing. UHJ creates stereo-compatible two-channel -output, which encodes some surround information. -Pair-Wise uses standard pair-wise panning between --30 and +30 degrees. The default is UHJ. + Pan Pot uses standard amplitude panning (aka +pair-wise, stereo pair, etc) between -30 and +30 +degrees, while UHJ creates a stereo-compatible +two-channel UHJ mix, which encodes some +surround sound information into stereo output +that can be decoded with a surround sound +receiver. @@ -455,7 +457,7 @@ Pair-Wise uses standard pair-wise panning between - Stereo Panning: + Stereo Encoding: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter -- cgit v1.2.3 From 08948079e93cbb7321be5715df36f54c5e6be3b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Feb 2017 00:23:16 -0800 Subject: Alter how panpot/pair-wise panning works This change allows pair-wise panning to mostly go through the normal ambisonic panning methods, with one special-case. First, a term is added to the stereo decoder matrix's X coefficient so that a centered sound is reduced by -3dB on each output channel. Panning in front creates a similar gain response to the typical L = sqrt(1-pan) R = sqrt(pan) for pan = [0,1]. Panning behind the listener can reduce (up to) an additional -10dB, creating a audible difference between front and back sounds as if simulating head obstruction. Secondly, as a special-case, the source positions are warped when calculating the ambisonic coefficients so that full left panning is reached at -30 degrees and full right at +30 degrees. This is to retain the expected 60-degree stereo width. This warping does not apply to B-Format buffer input, although it otherwise has the same gain responses. --- Alc/ALu.c | 38 ++++++++++---------------------------- Alc/panning.c | 16 ++++++++++++---- OpenAL32/Include/alu.h | 10 ++++++++++ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index bc48dd59..5a5e6fdf 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -679,23 +679,12 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } if(Device->Render_Mode == StereoPair) - { - /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ - ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); - coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Params[c].Gains.Target[0] = sqrtf(coeffs[0]) * DryGain; - voice->Direct.Params[c].Gains.Target[1] = sqrtf(1.0f-coeffs[0]) * DryGain; - for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - } + CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); else - { CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - ComputePanningGains(Device->Dry, coeffs, DryGain, - voice->Direct.Params[c].Gains.Target); - } + ComputePanningGains(Device->Dry, + coeffs, DryGain, voice->Direct.Params[c].Gains.Target + ); for(i = 0;i < NumSends;i++) { @@ -1173,22 +1162,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(Device->Render_Mode == StereoPair) { - /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ - ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f)); - x = clampf(x, -0.5f, 0.5f) + 0.5f; - voice->Direct.Params[0].Gains.Target[0] = sqrtf(x) * DryGain; - voice->Direct.Params[0].Gains.Target[1] = sqrtf(1.0f-x) * DryGain; - for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) - voice->Direct.Params[0].Gains.Target[i] = 0.0f; - - CalcDirectionCoeffs(dir, spread, coeffs); + ALfloat ev = asinf(clampf(dir[1], -1.0f, 1.0f)); + ALfloat az = atan2f(dir[0], -dir[2]); + CalcAnglePairwiseCoeffs(az, ev, radius, coeffs); } else - { CalcDirectionCoeffs(dir, spread, coeffs); - ComputePanningGains(Device->Dry, coeffs, DryGain, - voice->Direct.Params[0].Gains.Target); - } + ComputePanningGains(Device->Dry, + coeffs, DryGain, voice->Direct.Params[0].Gains.Target + ); for(i = 0;i < NumSends;i++) { diff --git a/Alc/panning.c b/Alc/panning.c index 72b55792..7b551100 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -202,6 +202,14 @@ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat CalcDirectionCoeffs(dir, spread, coeffs); } +void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + ALfloat sign = (azimuth < 0.0f) ? -1.0f : 1.0f; + if(!(fabsf(azimuth) > F_PI_2)) + azimuth = minf(fabsf(azimuth) * F_PI_2 / (F_PI/6.0f), F_PI_2) * sign; + CalcAngleCoeffs(azimuth, elevation, spread, coeffs); +} + void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { @@ -237,7 +245,7 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL float gain = 0.0f; for(j = 0;j < numcoeffs;j++) gain += chancoeffs[i][j]*coeffs[j]; - gains[i] = gain * ingain; + gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; } for(;i < MAX_OUTPUT_CHANNELS;i++) gains[i] = 0.0f; @@ -262,7 +270,7 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, float gain = 0.0f; for(j = 0;j < 4;j++) gain += chancoeffs[i][j] * mtx[j]; - gains[i] = gain * ingain; + gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; } for(;i < MAX_OUTPUT_CHANNELS;i++) gains[i] = 0.0f; @@ -454,8 +462,8 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp static const ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 0.00000000e+0f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 0.00000000e+0f } }, + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 1.19573156e-1f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 1.19573156e-1f } }, }, QuadCfg[4] = { { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c9f8760e..402c3181 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -296,6 +296,16 @@ inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALflo */ void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +/** + * CalcAnglePairwiseCoeffs + * + * Calculates ambisonic coefficients based on azimuth and elevation. The + * azimuth and elevation parameters are in radians, going right and up + * respectively. This pairwise variant warps the result such that +30 azimuth + * is full right, and -30 azimuth is full left. + */ +void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); + /** * ComputeAmbientGains * -- cgit v1.2.3 From c2a79f0f7b1d8f9a868e3411797005cefcebafa1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Feb 2017 16:44:59 -0800 Subject: Remove CalcXYZCoeffs and inline CalcAngleCoeffs --- Alc/effects/chorus.c | 4 ++-- Alc/effects/dedicated.c | 10 ++++++---- Alc/effects/echo.c | 4 ++-- Alc/effects/flanger.c | 4 ++-- Alc/panning.c | 12 +----------- OpenAL32/Include/alu.h | 22 +++++++++------------- 6 files changed, 22 insertions(+), 34 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 63d0ca01..a44f9262 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -136,9 +136,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device state->delay = fastf2i(props->Chorus.Delay * frequency); /* Gains for left and right sides */ - CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); + CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]); - CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); + CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); phase = props->Chorus.Phase; diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 818cbb6b..93c7416e 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -98,7 +98,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * else { ALfloat coeffs[MAX_AMBI_COEFFS]; - CalcXYZCoeffs(0.0f, 0.0f, -1.0f, 0.0f, coeffs); + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; @@ -109,16 +109,18 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - const ALfloat *gains = state->gains; ALuint i, c; + SamplesIn = ASSUME_ALIGNED(SamplesIn, 16); + SamplesOut = ASSUME_ALIGNED(SamplesOut, 16); for(c = 0;c < NumChannels;c++) { - if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD)) + const ALfloat gain = state->gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(i = 0;i < SamplesToDo;i++) - SamplesOut[c][i] += SamplesIn[0][i] * gains[c]; + SamplesOut[c][i] += SamplesIn[0][i] * gain; } } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 4a11d811..07eba9eb 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -134,11 +134,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co gain = Slot->Params.Gain; /* First tap panning */ - CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs); + CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]); /* Second tap panning */ - CalcXYZCoeffs( lrpan, 0.0f, 0.0f, spread, coeffs); + CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]); } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 1575212b..2a5d230c 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -136,9 +136,9 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi state->delay = fastf2i(props->Flanger.Delay * frequency); /* Gains for left and right sides */ - CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs); + CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]); - CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs); + CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]); phase = props->Flanger.Phase; diff --git a/Alc/panning.c b/Alc/panning.c index 7b551100..46f134a6 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -36,7 +36,7 @@ #include "bs2b.h" -extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { @@ -192,16 +192,6 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MA } } -void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) -{ - ALfloat dir[3] = { - sinf(azimuth) * cosf(elevation), - sinf(elevation), - -cosf(azimuth) * cosf(elevation) - }; - CalcDirectionCoeffs(dir, spread, coeffs); -} - void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { ALfloat sign = (azimuth < 0.0f) ? -1.0f : 1.0f; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 402c3181..326cde62 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -275,18 +275,6 @@ void aluInitEffectPanning(struct ALeffectslot *slot); */ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -/** - * CalcXYZCoeffs - * - * Same as CalcDirectionCoeffs except the direction is specified as separate x, - * y, and z parameters instead of an array. - */ -inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) -{ - ALfloat dir[3] = { x, y, z }; - CalcDirectionCoeffs(dir, spread, coeffs); -} - /** * CalcAngleCoeffs * @@ -294,7 +282,15 @@ inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALflo * azimuth and elevation parameters are in radians, going right and up * respectively. */ -void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + ALfloat dir[3] = { + sinf(azimuth) * cosf(elevation), + sinf(elevation), + -cosf(azimuth) * cosf(elevation) + }; + CalcDirectionCoeffs(dir, spread, coeffs); +} /** * CalcAnglePairwiseCoeffs -- cgit v1.2.3 From 652ef2b7fd53bbc5040b9288e2c6a03ef1934879 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Feb 2017 20:40:16 -0800 Subject: Remove an unused function --- Alc/bformatdec.c | 5 ----- Alc/bformatdec.h | 1 - 2 files changed, 6 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 955b9e4a..a0aa4e44 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -221,11 +221,6 @@ int bformatdec_getOrder(const struct BFormatDec *dec) return 0; } -int bformatdec_isPeriphonic(const struct BFormatDec *dec) -{ - return dec->Periphonic; -} - void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 7447e382..889d59f4 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -29,7 +29,6 @@ struct AmbiUpsampler; struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); int bformatdec_getOrder(const struct BFormatDec *dec); -int bformatdec_isPeriphonic(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ -- cgit v1.2.3 From eceeabaf2ff3814c2a8dbb5b67f79e87cfaa97cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Feb 2017 01:47:34 -0800 Subject: Improve handling of source state reads This avoids using seq_cst for loading the source state when either inside the mixer, or otherwise protected from inconsistencies with async updates. It also fixes potential race conditions with getting the source offset just as a source stops. --- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 159 ++++++++++++++++++++++++-------------------- 2 files changed, 89 insertions(+), 72 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 8889ed24..6282939e 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -226,7 +226,7 @@ ALboolean ApplyOffset(ALsource *Source); inline ALboolean IsPlayingOrPaused(const ALsource *source) { - ALenum state = ATOMIC_LOAD_SEQ(&source->state); + ALenum state = ATOMIC_LOAD(&source->state, almemory_order_relaxed); return state == AL_PLAYING || state == AL_PAUSED; } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1b3f4c56..bb70a056 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -139,9 +139,15 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * return NULL; } +static inline bool IsPlayingOrPausedSeq(const ALsource *source) +{ + ALenum state = ATOMIC_LOAD_SEQ(&source->state); + return state == AL_PLAYING || state == AL_PAUSED; +} + static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) { - return IsPlayingOrPaused(source) && + return IsPlayingOrPausedSeq(source) && !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); } @@ -525,18 +531,24 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPaused(Source) && + if(IsPlayingOrPausedSeq(Source) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { ALCdevice_Lock(Context->Device); - WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + /* Double-check that the source is still playing while we have + * the lock. + */ + if(IsPlayingOrPaused(Source)) { + WriteLock(&Source->queue_lock); + if(ApplyOffset(Source) == AL_FALSE) + { + WriteUnlock(&Source->queue_lock); + ALCdevice_Unlock(Context->Device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + } WriteUnlock(&Source->queue_lock); - ALCdevice_Unlock(Context->Device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } - WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); } return AL_TRUE; @@ -672,7 +684,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } WriteLock(&Source->queue_lock); - if(IsPlayingOrPaused(Source)) + if(IsPlayingOrPausedSeq(Source)) { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -726,18 +738,21 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPaused(Source) && + if(IsPlayingOrPausedSeq(Source) && !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) { ALCdevice_Lock(Context->Device); - WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + if(IsPlayingOrPaused(Source)) { + WriteLock(&Source->queue_lock); + if(ApplyOffset(Source) == AL_FALSE) + { + WriteUnlock(&Source->queue_lock); + ALCdevice_Unlock(Context->Device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + } WriteUnlock(&Source->queue_lock); - ALCdevice_Unlock(Context->Device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } - WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); } return AL_TRUE; @@ -844,7 +859,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } UnlockFiltersRead(device); - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPausedSeq(Source)) { /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); @@ -2927,7 +2942,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = voice->Source; - if(source != NULL && source->NeedsUpdate && IsPlayingOrPaused(source)) + if(source != NULL && source->NeedsUpdate && IsPlayingOrPausedSeq(source)) { source->NeedsUpdate = AL_FALSE; UpdateSourceProps(source, num_sends); @@ -3080,31 +3095,25 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint ALuint refcount; ReadLock(&Source->queue_lock); - if(!IsPlayingOrPaused(Source)) - { - ReadUnlock(&Source->queue_lock); - do { - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - return 0; - } - do { + BufferList = Current = NULL; + readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + if(IsPlayingOrPaused(Source)) + { + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; - readPos |= (ALuint64)ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << - (32-FRACTIONBITS); + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; + readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << + (32-FRACTIONBITS); + } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + while(BufferList && BufferList != Current) { if(BufferList->buffer) @@ -3125,55 +3134,59 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; - const ALbuffer *Buffer = NULL; ALuint64 readPos; ALuint refcount; + ALdouble offset; ReadLock(&Source->queue_lock); - if(!IsPlayingOrPaused(Source)) - { - ReadUnlock(&Source->queue_lock); - do { - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - *clocktime = GetDeviceClockTime(device); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - return 0.0; - } - do { + BufferList = Current = NULL; + readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + if(IsPlayingOrPaused(Source)) + { + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed)<position_fraction, almemory_order_relaxed); + readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << + FRACTIONBITS; + readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - while(BufferList && BufferList != Current) + + if(!Current) + offset = 0.0; + else { - const ALbuffer *buffer = BufferList->buffer; - if(buffer != NULL) + const ALbuffer *Buffer = NULL; + while(BufferList && BufferList != Current) { - if(!Buffer) Buffer = buffer; - readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; + const ALbuffer *buffer = BufferList->buffer; + if(buffer != NULL) + { + if(!Buffer) Buffer = buffer; + readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; + } + BufferList = BufferList->next; } - BufferList = BufferList->next; - } - while(BufferList && !Buffer) - { - Buffer = BufferList->buffer; - BufferList = BufferList->next; + while(BufferList && !Buffer) + { + Buffer = BufferList->buffer; + BufferList = BufferList->next; + } + assert(Buffer != NULL); + + offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / + (ALdouble)Buffer->Frequency; } - assert(Buffer != NULL); ReadUnlock(&Source->queue_lock); - return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency; + return offset; } /* GetSourceOffset @@ -3190,21 +3203,17 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ALboolean readFin = AL_FALSE; ALuint readPos, readPosFrac; ALuint totalBufferLen; - ALdouble offset = 0.0; ALboolean looping; ALuint refcount; + ALdouble offset; + ALenum state; ReadLock(&Source->queue_lock); - if(!IsPlayingOrPaused(Source)) - { - ReadUnlock(&Source->queue_lock); - return 0.0; - } - - totalBufferLen = 0; do { while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); + state = ATOMIC_LOAD(&Source->state, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); @@ -3215,6 +3224,13 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + if(state != AL_PLAYING && state != AL_PAUSED) + { + ReadUnlock(&Source->queue_lock); + return 0.0; + } + + totalBufferLen = 0; while(BufferList != NULL) { const ALbuffer *buffer; @@ -3238,6 +3254,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device readPos = readPosFrac = 0; } + offset = 0.0; switch(name) { case AL_SEC_OFFSET: -- cgit v1.2.3 From 9539ccc18be1ddda6ef32c2d4bd4c15b4ed4115c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 Feb 2017 16:29:27 -0800 Subject: Set CMP0020 for Qt --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7149351a..a8aa079b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,9 @@ PROJECT(OpenAL) IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0003 NEW) CMAKE_POLICY(SET CMP0005 NEW) + IF(POLICY CMP0020) + CMAKE_POLICY(SET CMP0020 NEW) + ENDIF(POLICY CMP0020) IF(POLICY CMP0042) CMAKE_POLICY(SET CMP0042 NEW) ENDIF(POLICY CMP0042) -- cgit v1.2.3 From 513c18fdc4d0d9184e061570209eb59f4ad0e392 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 Feb 2017 16:46:30 -0800 Subject: Ensure a non-playing or -paused source does not use a mixing voice --- Alc/ALu.c | 5 ++- Alc/mixer.c | 3 +- OpenAL32/Include/alu.h | 2 +- OpenAL32/alSource.c | 98 ++++++++++++++++++++++++++++---------------------- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 5a5e6fdf..3b83711f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1427,7 +1427,10 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) source = (*voice)->Source; if(IsVoiceInit && source && ATOMIC_LOAD(&source->state, almemory_order_relaxed) == AL_PLAYING) - MixSource(*voice, source, device, SamplesToDo); + { + if(!MixSource(*voice, source, device, SamplesToDo)) + (*voice)->Source = NULL; + } } /* effect slot processing */ diff --git a/Alc/mixer.c b/Alc/mixer.c index 46ca0892..be09ed67 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -366,7 +366,7 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter } -void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) +ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { ResamplerFunc Resample; ALbufferlistitem *BufferListItem; @@ -685,4 +685,5 @@ void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Samp ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed); ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed); ATOMIC_STORE(&Source->position_fraction, DataPosFrac, almemory_order_release); + return State == AL_PLAYING; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 326cde62..b6f0e769 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -348,7 +348,7 @@ void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo); +ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); /* Caller must lock the device. */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index bb70a056..1fc2c5bd 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2957,13 +2957,13 @@ void UpdateAllSourceProps(ALCcontext *context) */ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { + ALvoice *voice; + WriteLock(&Source->queue_lock); if(state == AL_PLAYING) { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; - ALboolean discontinuity; - ALvoice *voice = NULL; ALsizei i; /* Check that there is a queue containing at least one valid, non zero @@ -2977,62 +2977,69 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) BufferList = BufferList->next; } - if(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel) == AL_PAUSED) - discontinuity = AL_FALSE; - else - { - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); - discontinuity = AL_TRUE; - } + /* If there's nothing to play, or the device is disconnected, go right + * to stopped. + */ + if(!BufferList || !device->Connected) + goto do_stop; - // Check if an Offset has been set - if(Source->OffsetType != AL_NONE) + voice = GetSourceVoice(Source, Context); + switch(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel)) { - ApplyOffset(Source); - /* discontinuity = AL_TRUE;??? */ - } + case AL_PLAYING: + /* A source that's already playing is restarted. */ + ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); + /* fall-through */ + case AL_PAUSED: + /* A source that's paused simply resumes. Make sure it uses the + * volume last specified; there's no reason to fade from where + * it stopped at. + */ + assert(voice != NULL); + voice->Moving = AL_FALSE; + goto done; - /* If there's nothing to play, or device is disconnected, go right to - * stopped */ - if(!BufferList || !device->Connected) - goto do_stop; + default: + /* A source that's not playing or paused has its offset + * applied, and then starts playing. + */ + ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); + if(Source->OffsetType != AL_NONE) + ApplyOffset(Source); + break; + } /* Make sure this source isn't already active, and if not, look for an * unused voice to put it in. */ - voice = GetSourceVoice(Source, Context); - if(voice == NULL) + assert(voice == NULL); + for(i = 0;i < Context->VoiceCount;i++) { - for(i = 0;i < Context->VoiceCount;i++) - { - if(Context->Voices[i]->Source == NULL) - { - voice = Context->Voices[i]; - voice->Source = Source; - break; - } - } - if(voice == NULL) + if(Context->Voices[i]->Source == NULL) { - voice = Context->Voices[Context->VoiceCount++]; + voice = Context->Voices[i]; voice->Source = Source; + break; } - discontinuity = AL_TRUE; } - - if(discontinuity) + if(voice == NULL) { - /* Clear previous samples if playback is discontinuous. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - - /* Clear the stepping value so the mixer knows not to mix this - * until the update gets applied. - */ - voice->Step = 0; + voice = Context->Voices[Context->VoiceCount++]; + voice->Source = Source; } + /* Clear previous samples. */ + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->Step = 0; + voice->Moving = AL_FALSE; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { @@ -3057,6 +3064,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) else if(state == AL_STOPPED) { do_stop: + voice = GetSourceVoice(Source, Context); + if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) { ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); @@ -3067,6 +3076,8 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } else if(state == AL_INITIAL) { + voice = GetSourceVoice(Source, Context); + if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) { ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); @@ -3078,6 +3089,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->OffsetType = AL_NONE; Source->Offset = 0.0; } +done: WriteUnlock(&Source->queue_lock); } -- cgit v1.2.3 From 5c859af24ea44dabbbb31631309bb08a858a523e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 Feb 2017 15:35:15 -0800 Subject: Move the current buffer queue entry and play position to the voice This has a couple behavioral changes. First and biggest is that querying AL_BUFFERS_PROCESSED from a source will always return all buffers processed when in an AL_STOPPED state. Previously all buffers would be set as processed when first becoming stopped, but newly queued buffers would *not* be indicated as processed. That old behavior was not compliant with the spec, which unequivocally states "On a source in the AL_STOPPED state, all buffers are processed." Secondly, querying AL_BUFFER on an AL_STREAMING source will now always return 0. Previously it would return the current "active" buffer in the queue, but there's no basis for that in the spec. --- Alc/ALc.c | 26 +++--- Alc/ALu.c | 9 +-- Alc/mixer.c | 14 ++-- OpenAL32/Include/alSource.h | 24 +++--- OpenAL32/alSource.c | 191 +++++++++++++++++++++++--------------------- 5 files changed, 137 insertions(+), 127 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c829d8e7..bf683ba3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1692,22 +1692,24 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) LockUIntMapRead(&context->SourceMap); V0(device->Backend,lock)(); - for(pos = 0;pos < context->SourceMap.size;pos++) + for(pos = 0;pos < context->VoiceCount;pos++) { - ALsource *Source = context->SourceMap.values[pos]; - ALenum new_state; - - if(Source->OffsetType != AL_NONE && IsPlayingOrPaused(Source)) + ALvoice *voice = context->Voices[pos]; + ALsource *source = voice->Source; + if(source && source->OffsetType != AL_NONE) { - WriteLock(&Source->queue_lock); - ApplyOffset(Source); - WriteUnlock(&Source->queue_lock); + WriteLock(&source->queue_lock); + ApplyOffset(source, voice); + WriteUnlock(&source->queue_lock); } - - new_state = Source->new_state; - Source->new_state = AL_NONE; + } + for(pos = 0;pos < context->SourceMap.size;pos++) + { + ALsource *source = context->SourceMap.values[pos]; + ALenum new_state = source->new_state; + source->new_state = AL_NONE; if(new_state) - SetSourceState(Source, context, new_state); + SetSourceState(source, context, new_state); } V0(device->Backend,unlock)(); UnlockUIntMapRead(&context->SourceMap); diff --git a/Alc/ALu.c b/Alc/ALu.c index 3b83711f..b4938152 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1594,16 +1594,13 @@ void aluHandleDisconnect(ALCdevice *device) voice_end = voice + Context->VoiceCount; while(voice != voice_end) { - ALenum playing = AL_PLAYING; ALsource *source = (*voice)->Source; (*voice)->Source = NULL; - if(source && - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &source->state, &playing, AL_STOPPED)) + if(source) { - ATOMIC_STORE(&source->current_buffer, NULL, almemory_order_relaxed); - ATOMIC_STORE(&source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&source->position_fraction, 0, almemory_order_release); + ALenum playing = AL_PLAYING; + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &source->state, &playing, AL_STOPPED); } voice++; diff --git a/Alc/mixer.c b/Alc/mixer.c index be09ed67..b332030e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -385,9 +385,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei /* Get source info */ State = AL_PLAYING; /* Only called while playing. */ - BufferListItem = ATOMIC_LOAD(&Source->current_buffer, almemory_order_acquire); - DataPosInt = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); - DataPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); + DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); NumChannels = Source->NumChannels; SampleSize = Source->SampleSize; @@ -681,9 +681,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei voice->Moving = AL_TRUE; /* Update source info */ - ATOMIC_STORE(&Source->state, State, almemory_order_relaxed); - ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, DataPosFrac, almemory_order_release); + ATOMIC_STORE(&Source->state, State, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); return State == AL_PLAYING; } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 6282939e..f8a32f71 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -81,6 +81,17 @@ typedef struct ALvoice { struct ALsource *Source; + /* Current buffer queue item being played. */ + ATOMIC(ALbufferlistitem*) current_buffer; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue, and the fractional (fixed-point) offset to the next + * sample. + */ + ATOMIC(ALuint) position; + ATOMIC(ALuint) position_fraction; + /** Current target parameters used for mixing. */ ALint Step; @@ -178,18 +189,9 @@ typedef struct ALsource { ATOMIC(ALenum) state; ALenum new_state; - /** Source Buffer Queue info. */ + /** Source Buffer Queue head. */ RWLock queue_lock; ATOMIC(ALbufferlistitem*) queue; - ATOMIC(ALbufferlistitem*) current_buffer; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue, and the fractional (fixed-point) offset to the next - * sample. - */ - ATOMIC(ALuint) position; - ATOMIC(ALuint) position_fraction; ATOMIC(ALboolean) looping; @@ -222,7 +224,7 @@ inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); -ALboolean ApplyOffset(ALsource *Source); +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); inline ALboolean IsPlayingOrPaused(const ALsource *source) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1fc2c5bd..b8345e04 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -51,9 +51,9 @@ extern inline ALboolean IsPlayingOrPaused(const ALsource *source); static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); static void UpdateSourceProps(ALsource *source, ALsizei num_sends); -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); -static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); typedef enum SourceProp { @@ -531,17 +531,20 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPausedSeq(Source) && - !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) + if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPausedSeq(Source)) { + ALvoice *voice; + ALCdevice_Lock(Context->Device); /* Double-check that the source is still playing while we have * the lock. */ - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, Context); + if(voice) { WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + if(ApplyOffset(Source, voice) == AL_FALSE) { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); @@ -714,7 +717,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p newlist = NULL; } oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist); - ATOMIC_STORE_SEQ(&Source->current_buffer, newlist); WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -738,14 +740,17 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPausedSeq(Source) && - !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) + if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPausedSeq(Source)) { + ALvoice *voice; + ALCdevice_Lock(Context->Device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, Context); + if(voice) { WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + if(ApplyOffset(Source, voice) == AL_FALSE) { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); @@ -1091,7 +1096,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, device); + *values = GetSourceOffset(Source, prop, Context); return AL_TRUE; case AL_CONE_OUTER_GAINHF: @@ -1144,7 +1149,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ - values[0] = GetSourceSecOffset(Source, device, &srcclock); + values[0] = GetSourceSecOffset(Source, Context, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = (ALdouble)clocktime.Latency / 1000000000.0; @@ -1235,8 +1240,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFER: ReadLock(&Source->queue_lock); BufferList = (Source->SourceType == AL_STATIC) ? - ATOMIC_LOAD_SEQ(&Source->queue) : - ATOMIC_LOAD_SEQ(&Source->current_buffer); + ATOMIC_LOAD_SEQ(&Source->queue) : NULL; *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0; ReadUnlock(&Source->queue_lock); return AL_TRUE; @@ -1326,8 +1330,15 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p else { const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue); - const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer); + const ALbufferlistitem *Current = NULL; ALsizei played = 0; + ALvoice *voice; + + if((voice=GetSourceVoice(Source, Context)) != NULL) + Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL) + Current = BufferList; + while(BufferList && BufferList != Current) { played++; @@ -1442,7 +1453,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ - values[0] = GetSourceSampleOffset(Source, device, &srcclock); + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = clocktime.Latency; @@ -2606,12 +2617,6 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = BufferList->next; BufferList->next = BufferListStart; } - /* If the current buffer was at the end (NULL), put it at the start of the newly queued - * buffers. - */ - BufferList = NULL; - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer, - &BufferList, BufferListStart); WriteUnlock(&source->queue_lock); done: @@ -2626,11 +2631,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint ALbufferlistitem *OldHead; ALbufferlistitem *OldTail; ALbufferlistitem *Current; + ALvoice *voice; ALsizei i = 0; - if(nb == 0) - return; - context = GetContextRef(); if(!context) return; @@ -2641,6 +2644,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if((source=LookupSource(context, src)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + /* Nothing to unqueue. */ + if(nb == 0) goto done; + WriteLock(&source->queue_lock); if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING) { @@ -2651,7 +2657,11 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint /* Find the new buffer queue head */ OldTail = ATOMIC_LOAD_SEQ(&source->queue); - Current = ATOMIC_LOAD_SEQ(&source->current_buffer); + Current = NULL; + if((voice=GetSourceVoice(source, context)) != NULL) + Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL) + Current = OldTail; if(OldTail != Current) { for(i = 1;i < nb;i++) @@ -2782,10 +2792,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->new_state = AL_NONE; ATOMIC_INIT(&Source->queue, NULL); - ATOMIC_INIT(&Source->current_buffer, NULL); - - ATOMIC_INIT(&Source->position, 0); - ATOMIC_INIT(&Source->position_fraction, 0); ATOMIC_INIT(&Source->looping, AL_FALSE); @@ -2987,29 +2993,22 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) switch(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel)) { case AL_PLAYING: + assert(voice != NULL); /* A source that's already playing is restarted. */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); /* fall-through */ case AL_PAUSED: + assert(voice != NULL); /* A source that's paused simply resumes. Make sure it uses the * volume last specified; there's no reason to fade from where * it stopped at. */ - assert(voice != NULL); voice->Moving = AL_FALSE; goto done; default: - /* A source that's not playing or paused has its offset - * applied, and then starts playing. - */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); - if(Source->OffsetType != AL_NONE) - ApplyOffset(Source); break; } @@ -3032,6 +3031,15 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Source = Source; } + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + if(Source->OffsetType != AL_NONE) + ApplyOffset(Source, voice); + /* Clear previous samples. */ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); @@ -3067,10 +3075,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice = GetSourceVoice(Source, Context); if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - { ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); - ATOMIC_STORE_SEQ(&Source->current_buffer, NULL); - } Source->OffsetType = AL_NONE; Source->Offset = 0.0; } @@ -3079,13 +3084,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice = GetSourceVoice(Source, Context); if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - { ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); - ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue), - almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE_SEQ(&Source->position_fraction, 0); - } Source->OffsetType = AL_NONE; Source->Offset = 0.0; } @@ -3099,42 +3098,49 @@ done: * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { - BufferList = Current = NULL; + Current = NULL; readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, context); + if(voice) { - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; - readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; + readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - while(BufferList && BufferList != Current) + if(voice) { - if(BufferList->buffer) - readPos += (ALuint64)BufferList->buffer->SampleLen << 32; - BufferList = BufferList->next; + while(BufferList && BufferList != Current) + { + if(BufferList->buffer) + readPos += (ALuint64)BufferList->buffer->SampleLen << 32; + BufferList = BufferList->next; + } + readPos = minu64(readPos, U64(0x7fffffffffffffff)); } ReadUnlock(&Source->queue_lock); - return (ALint64)minu64(readPos, U64(0x7fffffffffffffff)); + return (ALint64)readPos; } /* GetSourceSecOffset @@ -3142,37 +3148,39 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; ALdouble offset; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { - BufferList = Current = NULL; + Current = NULL; readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, context); + if(voice) { - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << FRACTIONBITS; - readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(!Current) - offset = 0.0; - else + offset = 0.0; + if(voice) { const ALbuffer *Buffer = NULL; while(BufferList && BufferList != Current) @@ -3207,8 +3215,9 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 * (Bytes, Samples or Seconds). The offset is relative to the start of the * queue (not the start of the current buffer). */ -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device) +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; @@ -3218,25 +3227,26 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ALboolean looping; ALuint refcount; ALdouble offset; - ALenum state; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); do { while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); - state = ATOMIC_LOAD(&Source->state, almemory_order_relaxed); - - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); - - readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); - readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); + readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); + readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(state != AL_PLAYING && state != AL_PAUSED) + if(!voice) { ReadUnlock(&Source->queue_lock); return 0.0; @@ -3314,7 +3324,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device * Apply the stored playback offset to the Source. This function will update * the number of buffers "played" given the stored offset. */ -ALboolean ApplyOffset(ALsource *Source) +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) { ALbufferlistitem *BufferList; const ALbuffer *Buffer; @@ -3335,10 +3345,9 @@ ALboolean ApplyOffset(ALsource *Source) if(bufferLen > offset-totalBufferLen) { /* Offset is in this buffer */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - - ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release); return AL_TRUE; } -- cgit v1.2.3 From a9610b3607e8dd23f731b614c3b0761c38cb36a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 Feb 2017 16:11:45 -0800 Subject: Use separate enums for the ambisonic channel order and normalization --- Alc/ALc.c | 24 ++++++++++++++++++------ Alc/backends/wave.c | 3 ++- Alc/panning.c | 8 ++++---- OpenAL32/Include/alMain.h | 20 ++++++++++++++------ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index bf683ba3..56063bb1 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3640,7 +3640,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; device->IsHeadphones = AL_FALSE; - device->AmbiFmt = AmbiFormat_Default; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; device->NumUpdates = 3; device->UpdateSize = 1024; @@ -3763,11 +3764,20 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { if(strcasecmp(fmt, "fuma") == 0) - device->AmbiFmt = AmbiFormat_FuMa; + { + device->AmbiLayout = AmbiLayout_FuMa; + device->AmbiScale = AmbiNorm_FuMa; + } else if(strcasecmp(fmt, "acn+sn3d") == 0) - device->AmbiFmt = AmbiFormat_ACN_SN3D; + { + device->AmbiLayout = AmbiLayout_ACN; + device->AmbiScale = AmbiNorm_SN3D; + } else if(strcasecmp(fmt, "acn+n3d") == 0) - device->AmbiFmt = AmbiFormat_ACN_N3D; + { + device->AmbiLayout = AmbiLayout_ACN; + device->AmbiScale = AmbiNorm_N3D; + } else ERR("Unsupported ambi-format: %s\n", fmt); } @@ -3939,7 +3949,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return NULL; } device->IsHeadphones = AL_FALSE; - device->AmbiFmt = AmbiFormat_Default; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; device->UpdateSize = samples; device->NumUpdates = 1; @@ -4142,7 +4153,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->IsHeadphones = AL_FALSE; - device->AmbiFmt = AmbiFormat_Default; + device->AmbiLayout = AmbiLayout_Default; + device->AmbiScale = AmbiNorm_Default; ConfigValueUInt(NULL, NULL, "sources", &device->SourcesMax); if(device->SourcesMax == 0) device->SourcesMax = 256; diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index ac0ffd80..1b13746e 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -283,7 +283,8 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtAmbi2: case DevFmtAmbi3: /* .amb output requires FuMa */ - device->AmbiFmt = AmbiFormat_FuMa; + device->AmbiLayout = AmbiLayout_FuMa; + device->AmbiScale = AmbiNorm_FuMa; isbformat = 1; chanmask = 0; break; diff --git a/Alc/panning.c b/Alc/panning.c index 46f134a6..77f8e31b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -546,10 +546,10 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { - const ALsizei *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN; - const ALfloat *n3dscale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale : - (device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale : - /*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale; + const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; + const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : + (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : + /*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale; count = (device->FmtChans == DevFmtAmbi3) ? 16 : (device->FmtChans == DevFmtAmbi2) ? 9 : diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0b467403..23572a90 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -510,12 +510,19 @@ inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType ty return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); } -enum AmbiFormat { - AmbiFormat_FuMa, /* FuMa channel order and normalization */ - AmbiFormat_ACN_SN3D, /* ACN channel order and SN3D normalization */ - AmbiFormat_ACN_N3D, /* ACN channel order and N3D normalization */ +enum AmbiLayout { + AmbiLayout_FuMa, /* FuMa channel order */ + AmbiLayout_ACN, /* ACN channel order */ - AmbiFormat_Default = AmbiFormat_ACN_SN3D + AmbiLayout_Default = AmbiLayout_ACN +}; + +enum AmbiNorm { + AmbiNorm_FuMa, /* FuMa normalization */ + AmbiNorm_SN3D, /* SN3D normalization */ + AmbiNorm_N3D, /* N3D normalization */ + + AmbiNorm_Default = AmbiNorm_SN3D }; @@ -635,7 +642,8 @@ struct ALCdevice_struct /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ - enum AmbiFormat AmbiFmt; + enum AmbiLayout AmbiLayout; + enum AmbiNorm AmbiScale; al_string DeviceName; -- cgit v1.2.3 From 45d6c34015a5dc971d1e3ca095ad758339c46441 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 Feb 2017 20:43:16 -0800 Subject: Avoid standard malloc for buffer queue entries --- OpenAL32/alSource.c | 14 +++++++------- include/almalloc.h | 3 +++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b8345e04..40aa855c 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -697,7 +697,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(buffer != NULL) { /* Add the selected buffer to a one-item queue */ - newlist = malloc(sizeof(ALbufferlistitem)); + newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); newlist->buffer = buffer; newlist->next = NULL; IncrementRef(&buffer->ref); @@ -728,7 +728,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(temp->buffer) DecrementRef(&temp->buffer->ref); - free(temp); + al_free(temp); } return AL_TRUE; @@ -2545,12 +2545,12 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(!BufferListStart) { - BufferListStart = malloc(sizeof(ALbufferlistitem)); + BufferListStart = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); BufferList = BufferListStart; } else { - BufferList->next = malloc(sizeof(ALbufferlistitem)); + BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); BufferList = BufferList->next; } BufferList->buffer = buffer; @@ -2588,7 +2588,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu DecrementRef(&buffer->ref); ReadUnlock(&buffer->lock); } - free(BufferListStart); + al_free(BufferListStart); BufferListStart = next; } UnlockBuffersRead(device); @@ -2711,7 +2711,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint DecrementRef(&buffer->ref); } - free(OldHead); + al_free(OldHead); OldHead = next; } @@ -2832,7 +2832,7 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) ALbufferlistitem *next = BufferList->next; if(BufferList->buffer != NULL) DecrementRef(&BufferList->buffer->ref); - free(BufferList); + al_free(BufferList); BufferList = next; } diff --git a/include/almalloc.h b/include/almalloc.h index 355db795..8eadb5b3 100644 --- a/include/almalloc.h +++ b/include/almalloc.h @@ -7,6 +7,9 @@ extern "C" { #endif +/* Minimum alignment required by posix_memalign. */ +#define DEF_ALIGN sizeof(void*) + void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); void al_free(void *ptr); -- cgit v1.2.3 From 52d1f7883b9ff83ff1e3b7d7109e76003361b860 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 Feb 2017 20:56:34 -0800 Subject: Print WARNs when a device or context error is generated --- Alc/ALc.c | 1 + OpenAL32/alError.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 56063bb1..2bff2bc4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1731,6 +1731,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) */ static void alcSetError(ALCdevice *device, ALCenum errorCode) { + WARN("Error generated on device %p, code 0x%04x\n", device, errorCode); if(TrapALCError) { #ifdef _WIN32 diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index 6b7684ce..19fcaa6d 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -36,6 +36,8 @@ ALboolean TrapALError = AL_FALSE; ALvoid alSetError(ALCcontext *Context, ALenum errorCode) { ALenum curerr = AL_NO_ERROR; + + WARN("Error generated on context %p, code 0x%04x\n", Context, errorCode); if(TrapALError) { #ifdef _WIN32 @@ -46,6 +48,7 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode) raise(SIGTRAP); #endif } + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Context->LastError, &curerr, errorCode); } @@ -57,6 +60,8 @@ AL_API ALenum AL_APIENTRY alGetError(void) Context = GetContextRef(); if(!Context) { + WARN("Querying error state on null context (implicitly 0x%04x)\n", + AL_INVALID_OPERATION); if(TrapALError) { #ifdef _WIN32 -- cgit v1.2.3 From 1cd6617ff6404cfdcc1ccaf1c08c9d763e27366c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 03:50:42 -0800 Subject: Don't use the mutex in the base getClockLatency implementation --- Alc/backends/base.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Alc/backends/base.c b/Alc/backends/base.c index e4305653..902c4310 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -42,17 +42,22 @@ ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) ClockLatency ALCbackend_getClockLatency(ALCbackend *self) { ALCdevice *device = self->mDevice; + ALuint refcount; ClockLatency ret; - almtx_lock(&self->mMutex); - ret.ClockTime = GetDeviceClockTime(device); + do { + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + ret.ClockTime = GetDeviceClockTime(device); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); + /* NOTE: The device will generally have about all but one periods filled at * any given time during playback. Without a more accurate measurement from * the output, this is an okay approximation. */ ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency * maxu(device->NumUpdates-1, 1); - almtx_unlock(&self->mMutex); return ret; } -- cgit v1.2.3 From f8558ed2b7a2e51cd9e47ffe2937cda9a1ccfe36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 04:21:16 -0800 Subject: Use a variable counter for an array size limit --- Alc/ALc.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2bff2bc4..41d5cb44 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -106,9 +106,8 @@ static struct BackendInfo BackendList[] = { #ifdef HAVE_WAVE { "wave", ALCwaveBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif - - { NULL, NULL, NULL, NULL, NULL, EmptyFuncs } }; +static ALsizei BackendListSize = COUNTOF(BackendList); #undef EmptyFuncs static struct BackendInfo PlaybackBackend; @@ -911,8 +910,11 @@ static void alc_initconfig(void) ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); { char buf[1024] = ""; - int len = snprintf(buf, sizeof(buf), "%s", BackendList[0].name); - for(i = 1;BackendList[i].name;i++) + int len = 0; + + if(BackendListSize > 0) + len += snprintf(buf, sizeof(buf), "%s", BackendList[0].name); + for(i = 1;i < BackendListSize;i++) len += snprintf(buf+len, sizeof(buf)-len, ", %s", BackendList[i].name); TRACE("Supported backends: %s\n", buf); } @@ -1042,26 +1044,22 @@ static void alc_initconfig(void) len = (next ? ((size_t)(next-devs)) : strlen(devs)); while(len > 0 && isspace(devs[len-1])) len--; - for(n = i;BackendList[n].name;n++) + for(n = i;n < BackendListSize;n++) { if(len == strlen(BackendList[n].name) && strncmp(BackendList[n].name, devs, len) == 0) { if(delitem) { - do { + for(;n+1 < BackendListSize;n++) BackendList[n] = BackendList[n+1]; - ++n; - } while(BackendList[n].name); + BackendListSize--; } else { struct BackendInfo Bkp = BackendList[n]; - while(n > i) - { + for(;n > i;n--) BackendList[n] = BackendList[n-1]; - --n; - } BackendList[n] = Bkp; i++; @@ -1072,16 +1070,10 @@ static void alc_initconfig(void) } while(next++); if(endlist) - { - BackendList[i].name = NULL; - BackendList[i].getFactory = NULL; - BackendList[i].Init = NULL; - BackendList[i].Deinit = NULL; - BackendList[i].Probe = NULL; - } + BackendListSize = i; } - for(i = 0;(BackendList[i].Init || BackendList[i].getFactory) && (!PlaybackBackend.name || !CaptureBackend.name);i++) + for(i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) { if(BackendList[i].getFactory) { @@ -1289,7 +1281,7 @@ static void alc_deinit(void) memset(&PlaybackBackend, 0, sizeof(PlaybackBackend)); memset(&CaptureBackend, 0, sizeof(CaptureBackend)); - for(i = 0;BackendList[i].Deinit || BackendList[i].getFactory;i++) + for(i = 0;i < BackendListSize;i++) { if(!BackendList[i].getFactory) BackendList[i].Deinit(); -- cgit v1.2.3 From d3365f1b5b538dd261d9114fb31877b8dba5285d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 18:34:23 -0800 Subject: Start a ALC_SOFT_loopback2 extension This extends the base ALC_SOFT_loopback extension with support for B-Format. When ALC_FORMAT_CHANNELS_SOFT is set to ALC_BFORMAT3D_SOFT, then additional attributes must be specified. ALC_AMBISONIC_LAYOUT_SOFT must be set to ALC_ACN_SOFT or ALC_FUMA_SOFT for the desired channel layout, ALC_AMBISONIC_SCALING_SOFT must be set to ALC_N3D_SOFT, ALC_SN3D_SOFT, or ALC_FUMA_SOFT for the desired channel scaling/normalization scheme, and ALC_AMBISONIC_ORDER_SOFT must be set to an integer value greater than 0 for the ambisonic order (maximum allowed is implementation-dependent). Note that the number of channels required for ALC_BFORMAT3D_SOFT is dependent on the ambisonic order. The number of channels can be calculated by: num_channels = (order+1) * (order+1); /* or pow(order+1, 2); */ In addition, a new alcIsAmbisonicFormatSupportedSOFT function allows apps to determine which layout/scaling/order combinations are supported by the loopback device. For example, alcIsAmbisonicFormatSupported(device, ALC_ACN_SOFT, ALC_SN3D_SOFT, 2) will check if 2nd order AmbiX (ACN layout and SN3D scaling) rendering is supported for ALC_BFORMAT3D_SOFT output. --- Alc/ALc.c | 240 ++++++++++++++++++++++++++++++++++++---------- OpenAL32/Include/alMain.h | 33 ++++++- 2 files changed, 218 insertions(+), 55 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 41d5cb44..aedcd493 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -157,6 +157,8 @@ static const ALCfunction alcFunctions[] = { DECL(alcIsRenderFormatSupportedSOFT), DECL(alcRenderSamplesSOFT), + DECL(alcIsAmbisonicFormatSupportedSOFT), + DECL(alcDevicePauseSOFT), DECL(alcDeviceResumeSOFT), @@ -335,6 +337,7 @@ static const ALCenums enumeration[] = { DECL(ALC_5POINT1_SOFT), DECL(ALC_6POINT1_SOFT), DECL(ALC_7POINT1_SOFT), + DECL(ALC_BFORMAT3D_SOFT), DECL(ALC_BYTE_SOFT), DECL(ALC_UNSIGNED_BYTE_SOFT), @@ -357,6 +360,14 @@ static const ALCenums enumeration[] = { DECL(ALC_HRTF_SPECIFIER_SOFT), DECL(ALC_HRTF_ID_SOFT), + DECL(ALC_AMBISONIC_LAYOUT_SOFT), + DECL(ALC_AMBISONIC_SCALING_SOFT), + DECL(ALC_AMBISONIC_ORDER_SOFT), + DECL(ALC_ACN_SOFT), + DECL(ALC_FUMA_SOFT), + DECL(ALC_N3D_SOFT), + DECL(ALC_SN3D_SOFT), + DECL(ALC_NO_ERROR), DECL(ALC_INVALID_DEVICE), DECL(ALC_INVALID_CONTEXT), @@ -1478,11 +1489,34 @@ static ALCboolean IsValidALCChannels(ALCenum channels) case ALC_5POINT1_SOFT: case ALC_6POINT1_SOFT: case ALC_7POINT1_SOFT: + case ALC_BFORMAT3D_SOFT: return ALC_TRUE; } return ALC_FALSE; } +static ALCboolean IsValidAmbiLayout(ALCenum layout) +{ + switch(layout) + { + case ALC_ACN_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidAmbiScaling(ALCenum scaling) +{ + switch(scaling) + { + case ALC_N3D_SOFT: + case ALC_SN3D_SOFT: + case ALC_FUMA_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} /************************************************ * Miscellaneous ALC helpers @@ -1777,18 +1811,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) // Check for attributes if(device->Type == Loopback) { - enum { - GotFreq = 1<<0, - GotChans = 1<<1, - GotType = 1<<2, - GotAll = GotFreq|GotChans|GotType - }; - ALCuint freq, numMono, numStereo; - enum DevFmtChannels schans; - enum DevFmtType stype; - ALCuint attrIdx = 0; - ALCint gotFmt = 0; - ALCsizei numSends; + ALCsizei numMono, numStereo, numSends; + ALCenum alayout = AL_NONE; + ALCenum ascale = AL_NONE; + ALCenum schans = AL_NONE; + ALCenum stype = AL_NONE; + ALCsizei attrIdx = 0; + ALCsizei aorder = 0; + ALCuint freq = 0; if(!attrList) { @@ -1798,9 +1828,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) numMono = device->NumMonoSources; numStereo = device->NumStereoSources; - schans = device->FmtChans; - stype = device->FmtType; - freq = device->Frequency; numSends = old_sends; #define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) @@ -1808,22 +1835,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { if(attrList[attrIdx] == ALC_FORMAT_CHANNELS_SOFT) { - ALCint val = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, val); - if(!IsValidALCChannels(val) || !ChannelsFromDevFmt(val)) + schans = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); + if(!IsValidALCChannels(schans)) return ALC_INVALID_VALUE; - schans = val; - gotFmt |= GotChans; } if(attrList[attrIdx] == ALC_FORMAT_TYPE_SOFT) { - ALCint val = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, val); - if(!IsValidALCType(val) || !BytesFromDevFmt(val)) + stype = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); + if(!IsValidALCType(stype)) return ALC_INVALID_VALUE; - stype = val; - gotFmt |= GotType; } if(attrList[attrIdx] == ALC_FREQUENCY) @@ -1832,16 +1855,38 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE_ATTR(ALC_FREQUENCY, freq); if(freq < MIN_OUTPUT_RATE) return ALC_INVALID_VALUE; - gotFmt |= GotFreq; + } + + if(attrList[attrIdx] == ALC_AMBISONIC_LAYOUT_SOFT) + { + alayout = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); + if(!IsValidAmbiLayout(alayout)) + return ALC_INVALID_VALUE; + } + + if(attrList[attrIdx] == ALC_AMBISONIC_SCALING_SOFT) + { + ascale = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); + if(!IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + } + + if(attrList[attrIdx] == ALC_AMBISONIC_ORDER_SOFT) + { + aorder = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; } if(attrList[attrIdx] == ALC_STEREO_SOURCES) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - if(numStereo > device->SourcesMax) - numStereo = device->SourcesMax; + numStereo = clampi(numStereo, 0, device->SourcesMax); numMono = device->SourcesMax - numStereo; } @@ -1849,14 +1894,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { numSends = attrList[attrIdx + 1]; TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); } if(attrList[attrIdx] == ALC_HRTF_SOFT) { - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) + ALCint val = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_SOFT, val); + if(val == ALC_FALSE) hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) + else if(val == ALC_TRUE) hrtf_appreq = Hrtf_Enable; else hrtf_appreq = Hrtf_Default; @@ -1872,11 +1919,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } #undef TRACE_ATTR - if(gotFmt != GotAll) + if(!schans || !stype || !freq) { WARN("Missing format for loopback device\n"); return ALC_INVALID_VALUE; } + if(schans == ALC_BFORMAT3D_SOFT && (!alayout || !ascale || !aorder)) + { + WARN("Missing ambisonic info for loopback device\n"); + return ALC_INVALID_VALUE; + } if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); @@ -1884,22 +1936,29 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); + if(schans == ALC_BFORMAT3D_SOFT) + { + device->FmtChans = DevFmtAmbi1 + aorder; + device->AmbiLayout = alayout; + device->AmbiScale = ascale; + } + else + device->FmtChans = schans; device->Frequency = freq; - device->FmtChans = schans; device->FmtType = stype; device->NumMonoSources = numMono; device->NumStereoSources = numStereo; if(ConfigValueInt(NULL, NULL, "sends", &new_sends)) - new_sends = clampi(numSends, 0, clampi(new_sends, 0, MAX_SENDS)); + new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else - new_sends = clampi(numSends, 0, MAX_SENDS); + new_sends = numSends; } else if(attrList && attrList[0]) { - ALCuint freq, numMono, numStereo; - ALCuint attrIdx = 0; - ALCsizei numSends; + ALCsizei numMono, numStereo, numSends; + ALCsizei attrIdx = 0; + ALCuint freq; /* If a context is already running on the device, stop playback so the * device attributes can be updated. */ @@ -1928,9 +1987,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - if(numStereo > device->SourcesMax) - numStereo = device->SourcesMax; + numStereo = clampi(numStereo, 0, device->SourcesMax); numMono = device->SourcesMax - numStereo; } @@ -1938,6 +1996,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { numSends = attrList[attrIdx + 1]; TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); } if(attrList[attrIdx] == ALC_HRTF_SOFT) @@ -1975,9 +2034,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumStereoSources = numStereo; if(ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &new_sends)) - new_sends = clampi(numSends, 0, clampi(new_sends, 0, MAX_SENDS)); + new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else - new_sends = clampi(numSends, 0, MAX_SENDS); + new_sends = numSends; } if((device->Flags&DEVICE_RUNNING)) @@ -2883,6 +2942,14 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para } +static inline ALCsizei NumAttrsForDevice(ALCdevice *device) +{ + if(device->Type == Loopback && device->FmtChans >= DevFmtAmbi1 && + device->FmtChans <= DevFmtAmbi3) + return 23; + return 17; +} + static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) { ALCsizei i; @@ -2914,6 +2981,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC case ALC_CAPTURE_SAMPLES: case ALC_FORMAT_CHANNELS_SOFT: case ALC_FORMAT_TYPE_SOFT: + case ALC_AMBISONIC_LAYOUT_SOFT: + case ALC_AMBISONIC_SCALING_SOFT: + case ALC_AMBISONIC_ORDER_SOFT: alcSetError(NULL, ALC_INVALID_DEVICE); return 0; @@ -2965,11 +3035,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_ATTRIBUTES_SIZE: - values[0] = 17; + values[0] = NumAttrsForDevice(device); return 1; case ALC_ALL_ATTRIBUTES: - if(size < 17) + if(size < NumAttrsForDevice(device)) { alcSetError(device, ALC_INVALID_VALUE); return 0; @@ -2990,8 +3060,25 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC } else { - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + { + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = ALC_BFORMAT3D_SOFT; + + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = device->AmbiLayout; + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = device->AmbiScale; + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->FmtChans-DevFmtAmbi1+1; + } + else + { + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + } values[i++] = ALC_FORMAT_TYPE_SOFT; values[i++] = device->FmtType; @@ -3046,7 +3133,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->FmtChans; + if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + values[0] = ALC_BFORMAT3D_SOFT; + else + values[0] = device->FmtChans; return 1; case ALC_FORMAT_TYPE_SOFT: @@ -3058,6 +3148,36 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[0] = device->FmtType; return 1; + case ALC_AMBISONIC_LAYOUT_SOFT: + if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && + device->FmtChans <= DevFmtAmbi3)) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->AmbiLayout; + return 1; + + case ALC_AMBISONIC_SCALING_SOFT: + if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && + device->FmtChans <= DevFmtAmbi3)) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->AmbiScale; + return 1; + + case ALC_AMBISONIC_ORDER_SOFT: + if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && + device->FmtChans <= DevFmtAmbi3)) + { + alcSetError(device, ALC_INVALID_DEVICE); + return 0; + } + values[0] = device->FmtChans - DevFmtAmbi1 + 1; + return 1; + case ALC_MONO_SOURCES: values[0] = device->NumMonoSources; return 1; @@ -4191,9 +4311,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device alcSetError(device, ALC_INVALID_VALUE); else { - if(IsValidALCType(type) && BytesFromDevFmt(type) > 0 && - IsValidALCChannels(channels) && ChannelsFromDevFmt(channels) > 0 && - freq >= MIN_OUTPUT_RATE) + if(IsValidALCType(type) && IsValidALCChannels(channels) && freq >= MIN_OUTPUT_RATE) ret = ALC_TRUE; } if(device) ALCdevice_DecRef(device); @@ -4222,6 +4340,28 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL } +/************************************************ + * ALC loopback2 functions + ************************************************/ + +ALC_API ALCboolean ALC_APIENTRY alcIsAmbisonicFormatSupportedSOFT(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order) +{ + ALCboolean ret = ALC_FALSE; + + if(!VerifyDevice(&device) || device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else if(order <= 0) + alcSetError(device, ALC_INVALID_VALUE); + else + { + if(IsValidAmbiLayout(layout) && IsValidAmbiScaling(scaling) && order <= MAX_AMBI_ORDER) + ret = ALC_TRUE; + } + if(device) ALCdevice_DecRef(device); + + return ret; +} + /************************************************ * ALC DSP pause/resume functions ************************************************/ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 23572a90..adc379c5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -29,6 +29,29 @@ #include "almalloc.h" #include "threads.h" +#ifndef ALC_SOFT_loopback2 +#define ALC_SOFT_loopback2 1 +#define ALC_AMBISONIC_LAYOUT_SOFT 0x1997 +#define ALC_AMBISONIC_SCALING_SOFT 0x1998 +#define ALC_AMBISONIC_ORDER_SOFT 0x1999 + +#define ALC_BFORMAT3D_SOFT 0x1508 + +/* Ambisonic layouts */ +#define ALC_ACN_SOFT 0x1600 +#define ALC_FUMA_SOFT 0x1601 + +/* Ambisonic scalings (normalization) */ +#define ALC_N3D_SOFT 0x1700 +#define ALC_SN3D_SOFT 0x1701 +/*#define ALC_FUMA_SOFT*/ + +typedef ALCboolean (ALC_APIENTRY*LPALCISAMBISONICFORMATSUPPORTEDSOFT)(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcIsAmbisonicFormatSupportedSOFT(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order); +#endif +#endif + #ifndef ALC_SOFT_device_clock #define ALC_SOFT_device_clock 1 typedef int64_t ALCint64SOFT; @@ -511,16 +534,16 @@ inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType ty } enum AmbiLayout { - AmbiLayout_FuMa, /* FuMa channel order */ - AmbiLayout_ACN, /* ACN channel order */ + AmbiLayout_FuMa = ALC_FUMA_SOFT, /* FuMa channel order */ + AmbiLayout_ACN = ALC_ACN_SOFT, /* ACN channel order */ AmbiLayout_Default = AmbiLayout_ACN }; enum AmbiNorm { - AmbiNorm_FuMa, /* FuMa normalization */ - AmbiNorm_SN3D, /* SN3D normalization */ - AmbiNorm_N3D, /* N3D normalization */ + AmbiNorm_FuMa = ALC_FUMA_SOFT, /* FuMa normalization */ + AmbiNorm_SN3D = ALC_SN3D_SOFT, /* SN3D normalization */ + AmbiNorm_N3D = ALC_N3D_SOFT, /* N3D normalization */ AmbiNorm_Default = AmbiNorm_SN3D }; -- cgit v1.2.3 From 6f2a30dea208f7b6fea2062bf05ebdd45562ee24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 19:44:34 -0800 Subject: Remove an unneeded function --- Alc/bformatdec.c | 28 ++++++---------------------- Alc/bformatdec.h | 1 - Alc/panning.c | 2 +- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index a0aa4e44..92a2aecf 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -6,6 +6,7 @@ #include "mixer_defs.h" #include "alu.h" +#include "bool.h" #include "threads.h" #include "almalloc.h" @@ -181,7 +182,6 @@ typedef struct BFormatDec { ALsizei NumChannels; ALboolean DualBand; - ALboolean Periphonic; } BFormatDec; BFormatDec *bformatdec_alloc() @@ -204,29 +204,13 @@ void bformatdec_free(BFormatDec *dec) } } -int bformatdec_getOrder(const struct BFormatDec *dec) -{ - if(dec->Periphonic) - { - if(dec->NumChannels > 9) return 3; - if(dec->NumChannels > 4) return 2; - if(dec->NumChannels > 1) return 1; - } - else - { - if(dec->NumChannels > 5) return 3; - if(dec->NumChannels > 3) return 2; - if(dec->NumChannels > 1) return 1; - } - return 0; -} - void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]) { static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = UnitScale; + bool periphonic; ALfloat ratio; ALsizei i; @@ -256,7 +240,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount bandsplit_init(&dec->UpSampler[i].XOver, ratio); if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { - dec->Periphonic = AL_TRUE; + periphonic = true; dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD : (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; @@ -270,7 +254,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount } else { - dec->Periphonic = AL_FALSE; + periphonic = false; dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD : (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f; @@ -295,7 +279,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount ALfloat gain; ALsizei j, k; - if(!dec->Periphonic) + if(!periphonic) { for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { @@ -339,7 +323,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount ALfloat gain; ALsizei j, k; - if(!dec->Periphonic) + if(!periphonic) { for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 889d59f4..162f2652 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -28,7 +28,6 @@ struct AmbiUpsampler; struct BFormatDec *bformatdec_alloc(); void bformatdec_free(struct BFormatDec *dec); -int bformatdec_getOrder(const struct BFormatDec *dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ diff --git a/Alc/panning.c b/Alc/panning.c index 77f8e31b..84e1dbed 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -775,7 +775,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz ); bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency, speakermap); - if(bformatdec_getOrder(device->AmbiDecoder) < 2) + if(!(conf->ChanMask > 0xf)) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; -- cgit v1.2.3 From 51092a6315cf0a307efec2d76a32dde0f38873a3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 19:58:20 -0800 Subject: Remove unused function declarations --- OpenAL32/Include/alMain.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index adc379c5..9407cdce 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -431,9 +431,6 @@ typedef struct { 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_qsa_init(BackendFuncs *func_list); void alc_qsa_deinit(void); void alc_qsa_probe(enum DevProbe type); -- cgit v1.2.3 From 521abf2e0725cc4e4abfc17e75681e47fb372f68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 21:01:13 -0800 Subject: Dynamically allocate the channel delay buffers --- Alc/ALc.c | 42 ++++++++++++++++++++++++++++++++++++++++++ Alc/ALu.c | 12 ++++++------ Alc/panning.c | 16 ++++++++++++++++ OpenAL32/Include/alMain.h | 4 ++-- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index aedcd493..b46244aa 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1807,6 +1807,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALCuint oldFreq; FPUCtl oldMode; size_t size; + ALCsizei i; // Check for attributes if(device->Type == Loopback) @@ -2048,6 +2049,13 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Bs2b); device->Bs2b = NULL; + al_free(device->ChannelDelay[0].Buffer); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + al_free(device->Dry.Buffer); device->Dry.Buffer = NULL; device->Dry.NumChannels = 0; @@ -2329,6 +2337,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ static ALCvoid FreeDevice(ALCdevice *device) { + ALsizei i; + TRACE("%p\n", device); V0(device->Backend,close)(); @@ -2382,6 +2392,14 @@ static ALCvoid FreeDevice(ALCdevice *device) ambiup_free(device->AmbiUp); device->AmbiUp = NULL; + al_free(device->ChannelDelay[0].Buffer); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + AL_STRING_DEINIT(device->DeviceName); al_free(device->Dry.Buffer); @@ -3687,6 +3705,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) const ALCchar *fmt; ALCdevice *device; ALCenum err; + ALCsizei i; DO_INITCONFIG(); @@ -3748,6 +3767,13 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + //Set output format device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; @@ -3991,6 +4017,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, { ALCdevice *device = NULL; ALCenum err; + ALCsizei i; DO_INITCONFIG(); @@ -4036,6 +4063,13 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + if(!CaptureBackend.getFactory) device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs, ALCbackend_Capture); @@ -4198,6 +4232,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN { ALCbackendFactory *factory; ALCdevice *device; + ALCsizei i; DO_INITCONFIG(); @@ -4248,6 +4283,13 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + factory = ALCloopbackFactory_getFactory(); device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); if(!device->Backend) diff --git a/Alc/ALu.c b/Alc/ALu.c index b4938152..9fe5712d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1332,24 +1332,24 @@ static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ T *restrict out = (T*)OutBuffer + j; \ const ALfloat gain = distcomp[j].Gain; \ const ALsizei base = distcomp[j].Length; \ + ALfloat *restrict distbuf = ASSUME_ALIGNED(distcomp[j].Buffer, 16); \ if(base > 0 || gain != 1.0f) \ { \ if(SamplesToDo >= base) \ { \ for(i = 0;i < base;i++) \ - out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \ + out[i*numchans] = func(distbuf[i]*gain); \ for(;i < SamplesToDo;i++) \ out[i*numchans] = func(in[i-base]*gain); \ - memcpy(distcomp[j].Buffer, &in[SamplesToDo-base], \ - base*sizeof(ALfloat)); \ + memcpy(distbuf, &in[SamplesToDo-base], base*sizeof(ALfloat)); \ } \ else \ { \ for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(distcomp[j].Buffer[i]*gain); \ - memmove(distcomp[j].Buffer, distcomp[j].Buffer+SamplesToDo, \ + out[i*numchans] = func(distbuf[i]*gain); \ + memmove(distbuf, distbuf+SamplesToDo, \ (base-SamplesToDo)*sizeof(ALfloat)); \ - memcpy(distcomp[j].Buffer+base-SamplesToDo, in, \ + memcpy(distbuf+base-SamplesToDo, in, \ SamplesToDo*sizeof(ALfloat)); \ } \ } \ diff --git a/Alc/panning.c b/Alc/panning.c index 84e1dbed..c4d3e43f 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -616,6 +616,7 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL { const char *devname = al_string_get_cstr(device->DeviceName); ALfloat maxdist = 0.0f; + ALsizei total = 0; ALsizei i; for(i = 0;i < conf->NumSpeakers;i++) @@ -649,6 +650,21 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, device->ChannelDelay[chan].Gain ); + + /* Round up to the next 4th sample, so each channel buffer starts + * 16-byte aligned. + */ + total += RoundUp(device->ChannelDelay[chan].Length, 4); + } + } + + if(total > 0) + { + device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat)); + for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) + { + size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); + device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; } } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9407cdce..cc30dcef 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -631,12 +631,12 @@ TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry) /* Maximum delay in samples for speaker distance compensation. */ -#define MAX_DELAY_LENGTH 128 +#define MAX_DELAY_LENGTH 1024 typedef struct DistanceComp { ALfloat Gain; ALsizei Length; /* Valid range is [0...MAX_DELAY_LENGTH). */ - alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH]; + ALfloat *Buffer; } DistanceComp; /* Size for temporary storage of buffer data, in ALfloats. Larger values need -- cgit v1.2.3 From d1833c7b94fef1b6af73c1f33dd2441d80d95852 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Feb 2017 23:18:51 -0800 Subject: Increment MixCount in UpdateClockBase This is to protect clocktime reads since the backend lock won't protect it. --- Alc/ALc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b46244aa..59475e48 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1780,12 +1780,15 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) * * Updates the device's base clock time with however many samples have been * done. This is used so frequency changes on the device don't cause the time - * to jump forward or back. + * to jump forward or back. Must not be called while the device is running/ + * mixing. */ static inline void UpdateClockBase(ALCdevice *device) { + IncrementRef(&device->MixCount); device->ClockBase += device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency; device->SamplesDone = 0; + IncrementRef(&device->MixCount); } /* UpdateDeviceParams -- cgit v1.2.3 From 0e8ca50d7ad6b30793772a4451b974e2d28895cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Mar 2017 20:53:52 -0800 Subject: Stretch out some GUI elements for the decoder configurations --- utils/alsoft-config/mainwindow.ui | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 18392430..806b0ce0 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -635,9 +635,9 @@ configuration file. - 150 + 120 30 - 281 + 311 21 @@ -647,7 +647,7 @@ configuration file. 20 30 - 121 + 91 21 @@ -674,9 +674,9 @@ configuration file. - 150 + 120 60 - 281 + 311 21 @@ -699,7 +699,7 @@ configuration file. 20 60 - 121 + 91 21 @@ -715,7 +715,7 @@ configuration file. 20 90 - 121 + 91 21 @@ -729,9 +729,9 @@ configuration file. - 150 + 120 90 - 281 + 311 21 @@ -765,9 +765,9 @@ configuration file. - 150 + 120 120 - 281 + 311 21 @@ -777,7 +777,7 @@ configuration file. 20 120 - 121 + 91 21 -- cgit v1.2.3 From 6d7a790183552aa783d6043c755a10693d2f9369 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 2 Mar 2017 00:49:03 -0800 Subject: Add a boolean to specify if a voice should be playing --- Alc/ALu.c | 19 ++++++++-------- OpenAL32/Include/alSource.h | 8 ++++--- OpenAL32/alSource.c | 54 ++++++++++++++++++++++++++++++++------------- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9fe5712d..0a1b919a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1224,9 +1224,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } } -static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean force) +static void CalcSourceParams(ALvoice *voice, ALsource *source, ALCcontext *context, ALboolean force) { - ALsource *source = voice->Source; const ALbufferlistitem *BufferListItem; struct ALsourceProps *props; @@ -1278,11 +1277,8 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - if(!(source=(*voice)->Source)) continue; - if(!IsPlayingOrPaused(source)) - (*voice)->Source = NULL; - else - CalcSourceParams(*voice, ctx, force); + if((source=(*voice)->Source) != NULL) + CalcSourceParams(*voice, source, ctx, force); } } IncrementRef(&ctx->UpdateCount); @@ -1423,13 +1419,15 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - ALboolean IsVoiceInit = ((*voice)->Step > 0); source = (*voice)->Source; - if(IsVoiceInit && source && - ATOMIC_LOAD(&source->state, almemory_order_relaxed) == AL_PLAYING) + if(source && ATOMIC_LOAD(&(*voice)->Playing, almemory_order_relaxed) && + (*voice)->Step > 0) { if(!MixSource(*voice, source, device, SamplesToDo)) + { (*voice)->Source = NULL; + ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release); + } } } @@ -1596,6 +1594,7 @@ void aluHandleDisconnect(ALCdevice *device) { ALsource *source = (*voice)->Source; (*voice)->Source = NULL; + ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release); if(source) { diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index f8a32f71..fc1756e5 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -1,13 +1,14 @@ #ifndef _AL_SOURCE_H_ #define _AL_SOURCE_H_ -#define MAX_SENDS 16 -#define DEFAULT_SENDS 2 - +#include "bool.h" #include "alMain.h" #include "alu.h" #include "hrtf.h" +#define MAX_SENDS 16 +#define DEFAULT_SENDS 2 + #ifdef __cplusplus extern "C" { #endif @@ -80,6 +81,7 @@ typedef struct ALvoice { struct ALsourceProps *Props; struct ALsource *Source; + ATOMIC(bool) Playing; /* Current buffer queue item being played. */ ATOMIC(ALbufferlistitem*) current_buffer; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 40aa855c..14329bc2 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1637,8 +1637,11 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) FreeThunkEntry(Source->id); ALCdevice_Lock(device); - voice = GetSourceVoice(Source, context); - if(voice) voice->Source = NULL; + if((voice=GetSourceVoice(Source, context)) != NULL) + { + voice->Source = NULL; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + } ALCdevice_Unlock(device); DeinitSource(Source, device->NumAuxSends); @@ -2963,6 +2966,8 @@ void UpdateAllSourceProps(ALCcontext *context) */ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { + ALCdevice *device = Context->Device; + ALuint refcount; ALvoice *voice; WriteLock(&Source->queue_lock); @@ -2994,11 +2999,12 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { case AL_PLAYING: assert(voice != NULL); - /* A source that's already playing is restarted. */ + /* A source that's already playing is restarted from the beginning. */ ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - /* fall-through */ + goto done; + case AL_PAUSED: assert(voice != NULL); /* A source that's paused simply resumes. Make sure it uses the @@ -3006,12 +3012,16 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) * it stopped at. */ voice->Moving = AL_FALSE; + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); goto done; default: break; } + Source->NeedsUpdate = AL_FALSE; + UpdateSourceProps(Source, device->NumAuxSends); + /* Make sure this source isn't already active, and if not, look for an * unused voice to put it in. */ @@ -3021,22 +3031,20 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Context->Voices[i]->Source == NULL) { voice = Context->Voices[i]; - voice->Source = Source; break; } } if(voice == NULL) - { voice = Context->Voices[Context->VoiceCount++]; - voice->Source = Source; - } + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + ATOMIC_THREAD_FENCE(almemory_order_acquire); /* A source that's not playing or paused has any offset applied when it * starts playing. */ ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); if(Source->OffsetType != AL_NONE) ApplyOffset(Source, voice); @@ -3061,19 +3069,30 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } - Source->NeedsUpdate = AL_FALSE; - UpdateSourceProps(Source, device->NumAuxSends); + voice->Source = Source; + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); } else if(state == AL_PAUSED) { ALenum playing = AL_PLAYING; + if((voice=GetSourceVoice(Source, Context)) != NULL) + { + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + } ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED); } else if(state == AL_STOPPED) { do_stop: - voice = GetSourceVoice(Source, Context); - if(voice) voice->Source = NULL; + if((voice=GetSourceVoice(Source, Context)) != NULL) + { + voice->Source = NULL; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + } if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); Source->OffsetType = AL_NONE; @@ -3081,8 +3100,13 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } else if(state == AL_INITIAL) { - voice = GetSourceVoice(Source, Context); - if(voice) voice->Source = NULL; + if((voice=GetSourceVoice(Source, Context)) != NULL) + { + voice->Source = NULL; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + althrd_yield(); + } if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); Source->OffsetType = AL_NONE; -- cgit v1.2.3 From 952fb94ff7e6911c26198455eb317c07e66345bf Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sat, 4 Mar 2017 21:08:07 +0100 Subject: Make logical target name `openal` uniform accross all platforms --- CMakeLists.txt | 83 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8aa079b..b71fb44c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,10 +62,7 @@ if(DEFINED LIB_SUFFIX) endif() -IF(NOT WIN32) - SET(LIBNAME openal) -ELSE() - SET(LIBNAME OpenAL32) +IF(WIN32) ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0502") # This option is mainly for static linking OpenAL Soft into another project @@ -1249,55 +1246,59 @@ ENDIF() # Build main library IF(LIBTYPE STREQUAL "STATIC") - ADD_LIBRARY(${LIBNAME} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(openal STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ELSE() - ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(openal SHARED ${OPENAL_OBJS} ${ALC_OBJS}) ENDIF() -SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) -SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) +SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) +SET_PROPERTY(TARGET openal 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) + SET_PROPERTY(TARGET openal 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") +SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc") IF(HAVE_ALSA) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) ENDIF() IF(HAVE_OSS) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${OSS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${OSS_INCLUDE_DIRS}) ENDIF() IF(HAVE_SOLARIS) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${AUDIOIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${AUDIOIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_SNDIO) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${SOUNDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${SOUNDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_QSA) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${QSA_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${QSA_INCLUDE_DIRS}) ENDIF() IF(HAVE_DSOUND) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIRS}) ENDIF() IF(HAVE_PORTAUDIO) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PORTAUDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${PORTAUDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_PULSEAUDIO) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_JACK) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) + SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) ENDIF() IF(WIN32) IF(MSVC) - SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS") + SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS") ELSEIF(CMAKE_COMPILER_IS_GNUCC) - SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " -mwindows") + SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " -mwindows") ENDIF() 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 "") +SET_TARGET_PROPERTIES(openal PROPERTIES VERSION ${LIB_VERSION} + SOVERSION ${LIB_MAJOR_VERSION}) +IF(WIN32) + SET_TARGET_PROPERTIES(openal PROPERTIES OUTPUT_NAME "OpenAL32") +ENDIF() + +if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") + SET_TARGET_PROPERTIES(openal PROPERTIES PREFIX "") IF(MINGW AND ALSOFT_BUILD_IMPORT_LIB) FIND_PROGRAM(SED_EXECUTABLE NAMES sed DOC "sed executable") @@ -1311,25 +1312,25 @@ IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") ENDIF() ELSE() - SET_PROPERTY(TARGET ${LIBNAME} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,${LIBNAME}.def") - ADD_CUSTOM_COMMAND(TARGET ${LIBNAME} POST_BUILD - COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" ${LIBNAME}.def - COMMAND "${DLLTOOL_EXECUTABLE}" -d ${LIBNAME}.def -l ${LIBNAME}.lib -D ${LIBNAME}.dll - COMMENT "Stripping ordinals from ${LIBNAME}.def and generating ${LIBNAME}.lib..." + SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,OpenAL32.def") + ADD_CUSTOM_COMMAND(TARGET openal POST_BUILD + COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def + COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll + COMMENT "Stripping ordinals from OpenAL32.def and generating OpenAL32.lib..." VERBATIM ) ENDIF() ENDIF() ENDIF() -TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS}) +TARGET_LINK_LIBRARIES(openal common ${EXTRA_LIBS}) IF(TARGET build_version) - ADD_DEPENDENCIES(${LIBNAME} build_version) + ADD_DEPENDENCIES(openal build_version) ENDIF() IF(ALSOFT_INSTALL) # Add an install target here - INSTALL(TARGETS ${LIBNAME} + INSTALL(TARGETS openal RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -1404,7 +1405,7 @@ ENDIF() IF(ALSOFT_UTILS) ADD_EXECUTABLE(openal-info utils/openal-info.c) SET_PROPERTY(TARGET openal-info APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - TARGET_LINK_LIBRARIES(openal-info ${LIBNAME}) + TARGET_LINK_LIBRARIES(openal-info openal) ADD_EXECUTABLE(makehrtf utils/makehrtf.c) SET_PROPERTY(TARGET makehrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) @@ -1438,7 +1439,7 @@ IF(ALSOFT_TESTS) SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) ADD_EXECUTABLE(altonegen examples/altonegen.c) - TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME}) + TARGET_LINK_LIBRARIES(altonegen test-common openal) SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(ALSOFT_INSTALL) @@ -1465,7 +1466,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alstream examples/alstream.c) TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) + common openal) SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1473,7 +1474,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alreverb examples/alreverb.c) TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) + common openal) SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1481,7 +1482,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(allatency examples/allatency.c) TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) + common openal) SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1489,7 +1490,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alloopback examples/alloopback.c) TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) + common openal) SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1497,7 +1498,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alhrtf examples/alhrtf.c) TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common ${LIBNAME}) + common openal) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1540,7 +1541,7 @@ IF(ALSOFT_EXAMPLES) ENDIF() IF(FFVER_OK AND NOT MSVC) ADD_EXECUTABLE(alffplay examples/alffplay.c) - TARGET_LINK_LIBRARIES(alffplay common ${SDL2_LIBRARY} ${LIBNAME} ${FFMPEG_LIBRARIES}) + TARGET_LINK_LIBRARIES(alffplay common ${SDL2_LIBRARY} openal ${FFMPEG_LIBRARIES}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS} -- cgit v1.2.3 From 9d0bf065eea4ebda8cfd3af1b5deb80f6b4ec906 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sat, 4 Mar 2017 22:01:58 +0100 Subject: Compile `common` library within dependent targets --- CMakeLists.txt | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b71fb44c..1686587f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1237,18 +1237,11 @@ CONFIGURE_FILE( "${OpenAL_BINARY_DIR}/openal.pc" @ONLY) -# Build a common library with reusable helpers -ADD_LIBRARY(common STATIC ${COMMON_OBJS}) -SET_PROPERTY(TARGET common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) -IF(NOT LIBTYPE STREQUAL "STATIC") - SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE) -ENDIF() - # Build main library IF(LIBTYPE STREQUAL "STATIC") ADD_LIBRARY(openal STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ELSE() - ADD_LIBRARY(openal SHARED ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(openal SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ENDIF() SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) @@ -1323,7 +1316,7 @@ if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") ENDIF() ENDIF() -TARGET_LINK_LIBRARIES(openal common ${EXTRA_LIBS}) +TARGET_LINK_LIBRARIES(openal ${EXTRA_LIBS}) IF(TARGET build_version) ADD_DEPENDENCIES(openal build_version) ENDIF() @@ -1438,7 +1431,7 @@ IF(ALSOFT_TESTS) ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - ADD_EXECUTABLE(altonegen examples/altonegen.c) + ADD_EXECUTABLE(altonegen examples/altonegen.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(altonegen test-common openal) SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) @@ -1464,41 +1457,41 @@ IF(ALSOFT_EXAMPLES) INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alstream examples/alstream.c) + ADD_EXECUTABLE(alstream examples/alstream.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common openal) + openal) SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alreverb examples/alreverb.c) + ADD_EXECUTABLE(alreverb examples/alreverb.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common openal) + openal) SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(allatency examples/allatency.c) + ADD_EXECUTABLE(allatency examples/allatency.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common openal) + openal) SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alloopback examples/alloopback.c) + ADD_EXECUTABLE(alloopback examples/alloopback.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common openal) + openal) SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alhrtf examples/alhrtf.c) + ADD_EXECUTABLE(alhrtf examples/alhrtf.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - common openal) + openal) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1540,8 +1533,8 @@ IF(ALSOFT_EXAMPLES) ENDIF() ENDIF() IF(FFVER_OK AND NOT MSVC) - ADD_EXECUTABLE(alffplay examples/alffplay.c) - TARGET_LINK_LIBRARIES(alffplay common ${SDL2_LIBRARY} openal ${FFMPEG_LIBRARIES}) + ADD_EXECUTABLE(alffplay examples/alffplay.c ${COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} openal ${FFMPEG_LIBRARIES}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS} -- cgit v1.2.3 From 27be429ca4b89fc23034c83a11ebcf963c36ba26 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sat, 4 Mar 2017 23:03:53 +0100 Subject: Rename logical CMake target `openal` to `OpenAL` --- CMakeLists.txt | 72 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1686587f..345ede2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,7 +328,7 @@ ELSE() # Force enable -fPIC for CMake versions before 2.8.9 (later versions have # the POSITION_INDEPENDENT_CODE target property). The static common library - # will be linked into the dynamic openal library, which requires all its + # will be linked into the dynamic OpenAL library, which requires all its # code to be position-independent. IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32) CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH) @@ -1239,59 +1239,61 @@ CONFIGURE_FILE( # Build main library IF(LIBTYPE STREQUAL "STATIC") - ADD_LIBRARY(openal STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(OpenAL STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ELSE() - ADD_LIBRARY(openal SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) + ADD_LIBRARY(OpenAL SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) ENDIF() -SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) -SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) +SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) +SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) IF(WIN32 AND ALSOFT_NO_UID_DEFS) - SET_PROPERTY(TARGET openal APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS) ENDIF() -SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc") +SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc") IF(HAVE_ALSA) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) ENDIF() IF(HAVE_OSS) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${OSS_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${OSS_INCLUDE_DIRS}) ENDIF() IF(HAVE_SOLARIS) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${AUDIOIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${AUDIOIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_SNDIO) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${SOUNDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${SOUNDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_QSA) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${QSA_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${QSA_INCLUDE_DIRS}) ENDIF() IF(HAVE_DSOUND) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIRS}) ENDIF() IF(HAVE_PORTAUDIO) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${PORTAUDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${PORTAUDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_PULSEAUDIO) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() IF(HAVE_JACK) - SET_PROPERTY(TARGET openal APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) + SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) ENDIF() IF(WIN32) IF(MSVC) - SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS") + SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS") ELSEIF(CMAKE_COMPILER_IS_GNUCC) - SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " -mwindows") + SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " -mwindows") ENDIF() ENDIF() -SET_TARGET_PROPERTIES(openal PROPERTIES VERSION ${LIB_VERSION} +SET_TARGET_PROPERTIES(OpenAL PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) -IF(WIN32) - SET_TARGET_PROPERTIES(openal PROPERTIES OUTPUT_NAME "OpenAL32") +IF(NOT WIN32) + SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME "openal") +ELSE() + SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME "OpenAL32") ENDIF() if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") - SET_TARGET_PROPERTIES(openal PROPERTIES PREFIX "") + SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") IF(MINGW AND ALSOFT_BUILD_IMPORT_LIB) FIND_PROGRAM(SED_EXECUTABLE NAMES sed DOC "sed executable") @@ -1305,8 +1307,8 @@ if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") ENDIF() ELSE() - SET_PROPERTY(TARGET openal APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,OpenAL32.def") - ADD_CUSTOM_COMMAND(TARGET openal POST_BUILD + SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,OpenAL32.def") + ADD_CUSTOM_COMMAND(TARGET OpenAL POST_BUILD COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll COMMENT "Stripping ordinals from OpenAL32.def and generating OpenAL32.lib..." @@ -1316,14 +1318,14 @@ if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") ENDIF() ENDIF() -TARGET_LINK_LIBRARIES(openal ${EXTRA_LIBS}) +TARGET_LINK_LIBRARIES(OpenAL ${EXTRA_LIBS}) IF(TARGET build_version) - ADD_DEPENDENCIES(openal build_version) + ADD_DEPENDENCIES(OpenAL build_version) ENDIF() IF(ALSOFT_INSTALL) # Add an install target here - INSTALL(TARGETS openal + INSTALL(TARGETS OpenAL RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -1398,7 +1400,7 @@ ENDIF() IF(ALSOFT_UTILS) ADD_EXECUTABLE(openal-info utils/openal-info.c) SET_PROPERTY(TARGET openal-info APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - TARGET_LINK_LIBRARIES(openal-info openal) + TARGET_LINK_LIBRARIES(openal-info OpenAL) ADD_EXECUTABLE(makehrtf utils/makehrtf.c) SET_PROPERTY(TARGET makehrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) @@ -1432,7 +1434,7 @@ IF(ALSOFT_TESTS) SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) ADD_EXECUTABLE(altonegen examples/altonegen.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(altonegen test-common openal) + TARGET_LINK_LIBRARIES(altonegen test-common OpenAL) SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(ALSOFT_INSTALL) @@ -1459,7 +1461,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alstream examples/alstream.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - openal) + OpenAL) SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1467,7 +1469,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alreverb examples/alreverb.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - openal) + OpenAL) SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1475,7 +1477,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(allatency examples/allatency.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - openal) + OpenAL) SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1483,7 +1485,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alloopback examples/alloopback.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - openal) + OpenAL) SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1491,7 +1493,7 @@ IF(ALSOFT_EXAMPLES) ADD_EXECUTABLE(alhrtf examples/alhrtf.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - openal) + OpenAL) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} @@ -1534,7 +1536,7 @@ IF(ALSOFT_EXAMPLES) ENDIF() IF(FFVER_OK AND NOT MSVC) ADD_EXECUTABLE(alffplay examples/alffplay.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} openal ${FFMPEG_LIBRARIES}) + TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} OpenAL ${FFMPEG_LIBRARIES}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS} -- cgit v1.2.3 From df87cf8002ace806879ef3646543d7f4037ba52e Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sat, 4 Mar 2017 22:15:12 +0100 Subject: Export cmake import targets for project install tree --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 345ede2e..e0f349b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1325,11 +1325,16 @@ ENDIF() IF(ALSOFT_INSTALL) # Add an install target here - INSTALL(TARGETS OpenAL + INSTALL(TARGETS OpenAL EXPORT OpenAL RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) + INSTALL(EXPORT OpenAL + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL + NAMESPACE OpenAL:: + FILE OpenALConfig.cmake) INSTALL(FILES include/AL/al.h include/AL/alc.h include/AL/alext.h -- cgit v1.2.3 From ad640245d85502f673480a21d06f6259f507f279 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sat, 4 Mar 2017 23:22:45 +0100 Subject: Export cmake import targets for project build tree --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0f349b4..70709444 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1331,6 +1331,9 @@ IF(ALSOFT_INSTALL) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) + EXPORT(TARGETS OpenAL + NAMESPACE OpenAL:: + FILE OpenALConfig.cmake) INSTALL(EXPORT OpenAL DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL NAMESPACE OpenAL:: -- cgit v1.2.3 From a11a13bdd1ce4770071d6d671619dcf7796c0200 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 00:08:37 +0100 Subject: Use Ubuntu 14.04 in TravisCI to get a less antique CMake version --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index dfae8e7a..f87cfb1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ os: - linux - osx +dist: trusty language: c script: cmake . && make -j2 -- cgit v1.2.3 From c013068003a6ccd63e335fe94f43caf1b769ff7e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Mar 2017 18:20:43 -0800 Subject: Use the LINK_FLAGS property instead of abusing libs for flags --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70709444..4b5a8553 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,10 +83,13 @@ IF(WIN32) ENDIF() +SET(EXTRA_LIBS "") +SET(EXTRA_LDFLAGS "") + # 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) + SET(EXTRA_LDFLAGS "${EXTRA_LDFLAGS} -L/usr/lib") ENDIF() IF(NOT LIBTYPE) @@ -361,7 +364,7 @@ int main() HAVE_STATIC_LIBGCC_SWITCH ) if(HAVE_STATIC_LIBGCC_SWITCH) - set(EXTRA_LIBS ${EXTRA_LIBS} -static-libgcc) + set(EXTRA_LDFLAGS "${EXTRA_LDFLAGS} -static-libgcc") endif() set(CMAKE_REQUIRED_LIBRARIES ${OLD_REQUIRED_LIBRARIES}) unset(OLD_REQUIRED_LIBRARIES) @@ -608,7 +611,7 @@ IF(NOT HAVE_WINDOWS_H) IF(HAVE_PTHREAD) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -pthread") SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -pthread") - SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread) + SET(EXTRA_LDFLAGS "${EXTRA_LDFLAGS} -pthread") ENDIF() CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD) @@ -1307,7 +1310,7 @@ if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation") ENDIF() ELSE() - SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--output-def,OpenAL32.def") + SET(EXTRA_LDFLAGS "${EXTRA_LDFLAGS} -Wl,--output-def,OpenAL32.def") ADD_CUSTOM_COMMAND(TARGET OpenAL POST_BUILD COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll @@ -1318,6 +1321,7 @@ if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") ENDIF() ENDIF() +SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS ${EXTRA_LDFLAGS}) TARGET_LINK_LIBRARIES(OpenAL ${EXTRA_LIBS}) IF(TARGET build_version) ADD_DEPENDENCIES(OpenAL build_version) -- cgit v1.2.3 From 87fd28835953bf5bb2a84f061675bddbcc5bf40d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Mar 2017 20:25:10 -0800 Subject: Remove unnecessary wrappers around SDL_sound Also remove wrappers for the now-unsupported buffer_samples extension. --- CMakeLists.txt | 6 +- examples/alhrtf.c | 75 +++++++++----- examples/allatency.c | 87 +++++++++------- examples/alloopback.c | 31 +++++- examples/alreverb.c | 91 ++++++++++------- examples/alstream.c | 118 +++++++++++---------- examples/common/alhelpers.c | 243 ++------------------------------------------ examples/common/alhelpers.h | 24 +---- examples/common/sdl_sound.c | 164 ------------------------------ examples/common/sdl_sound.h | 43 -------- 10 files changed, 253 insertions(+), 629 deletions(-) delete mode 100644 examples/common/sdl_sound.c delete mode 100644 examples/common/sdl_sound.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b5a8553..8f279951 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1464,12 +1464,8 @@ ENDIF() IF(ALSOFT_EXAMPLES) IF(SDL2_FOUND) IF(SDL_SOUND_FOUND) - ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c - examples/common/sdl_sound.c) + ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) SET_PROPERTY(TARGET ex-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) - SET_PROPERTY(TARGET ex-common APPEND PROPERTY - INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} - ) ADD_EXECUTABLE(alstream examples/alstream.c ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} diff --git a/examples/alhrtf.c b/examples/alhrtf.c index 3964a7c6..f9150ae1 100644 --- a/examples/alhrtf.c +++ b/examples/alhrtf.c @@ -28,12 +28,13 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "common/alhelpers.h" -#include "common/sdl_sound.h" #ifndef M_PI @@ -44,47 +45,63 @@ static LPALCGETSTRINGISOFT alcGetStringiSOFT; static LPALCRESETDEVICESOFT alcResetDeviceSOFT; /* LoadBuffer loads the named audio file into an OpenAL buffer object, and - * returns the new buffer ID. */ + * returns the new buffer ID. + */ static ALuint LoadSound(const char *filename) { - ALenum err, format, type, channels; - ALuint rate, buffer; - size_t datalen; - void *data; - FilePtr sound; + Sound_Sample *sample; + ALenum err, format; + ALuint buffer; + Uint32 slen; /* Open the audio file */ - sound = openAudioFile(filename, 1000); - if(!sound) + sample = Sound_NewSampleFromFile(filename, NULL, 65536); + if(!sample) { fprintf(stderr, "Could not open audio in %s\n", filename); - closeAudioFile(sound); return 0; } /* Get the sound format, and figure out the OpenAL format */ - if(getAudioInfo(sound, &rate, &channels, &type) != 0) + if(sample->actual.channels == 1) { - fprintf(stderr, "Error getting audio info for %s\n", filename); - closeAudioFile(sound); - return 0; + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_MONO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_MONO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } } - - format = GetFormat(channels, type, NULL); - if(format == AL_NONE) + else if(sample->actual.channels == 2) { - fprintf(stderr, "Unsupported format (%s, %s) for %s\n", - ChannelsName(channels), TypeName(type), filename); - closeAudioFile(sound); + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_STEREO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_STEREO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } + } + else + { + fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels); + Sound_FreeSample(sample); return 0; } /* Decode the whole audio stream to a buffer. */ - data = decodeAudioStream(sound, &datalen); - if(!data) + slen = Sound_DecodeAll(sample); + if(!sample->buffer || slen == 0) { fprintf(stderr, "Failed to read audio from %s\n", filename); - closeAudioFile(sound); + Sound_FreeSample(sample); return 0; } @@ -92,9 +109,8 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, data, datalen, rate); - free(data); - closeAudioFile(sound); + alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + Sound_FreeSample(sample); /* Check if an error occured, and clean up if so. */ err = alGetError(); @@ -219,10 +235,14 @@ int main(int argc, char **argv) } fflush(stdout); + /* Initialize SDL_sound. */ + Sound_Init(); + /* Load the sound into a buffer. */ buffer = LoadSound(soundname); if(!buffer) { + Sound_Quit(); CloseAL(); return 1; } @@ -263,10 +283,11 @@ int main(int argc, char **argv) alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); - /* All done. Delete resources, and close OpenAL. */ + /* All done. Delete resources, and close down SDL_sound and OpenAL. */ alDeleteSources(1, &source); alDeleteBuffers(1, &buffer); + Sound_Quit(); CloseAL(); return 0; diff --git a/examples/allatency.c b/examples/allatency.c index 56d96b9e..d561373f 100644 --- a/examples/allatency.c +++ b/examples/allatency.c @@ -27,16 +27,14 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "common/alhelpers.h" -#include "common/sdl_sound.h" - -static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples; -static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT; static LPALSOURCEDSOFT alSourcedSOFT; static LPALSOURCE3DSOFT alSource3dSOFT; @@ -52,47 +50,63 @@ static LPALGETSOURCE3I64SOFT alGetSource3i64SOFT; static LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; /* LoadBuffer loads the named audio file into an OpenAL buffer object, and - * returns the new buffer ID. */ + * returns the new buffer ID. + */ static ALuint LoadSound(const char *filename) { - ALenum err, format, type, channels; - ALuint rate, buffer; - size_t datalen; - void *data; - FilePtr sound; + Sound_Sample *sample; + ALenum err, format; + ALuint buffer; + Uint32 slen; /* Open the audio file */ - sound = openAudioFile(filename, 1000); - if(!sound) + sample = Sound_NewSampleFromFile(filename, NULL, 65536); + if(!sample) { fprintf(stderr, "Could not open audio in %s\n", filename); - closeAudioFile(sound); return 0; } /* Get the sound format, and figure out the OpenAL format */ - if(getAudioInfo(sound, &rate, &channels, &type) != 0) + if(sample->actual.channels == 1) { - fprintf(stderr, "Error getting audio info for %s\n", filename); - closeAudioFile(sound); - return 0; + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_MONO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_MONO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } } - - format = GetFormat(channels, type, alIsBufferFormatSupportedSOFT); - if(format == AL_NONE) + else if(sample->actual.channels == 2) { - fprintf(stderr, "Unsupported format (%s, %s) for %s\n", - ChannelsName(channels), TypeName(type), filename); - closeAudioFile(sound); + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_STEREO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_STEREO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } + } + else + { + fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels); + Sound_FreeSample(sample); return 0; } /* Decode the whole audio stream to a buffer. */ - data = decodeAudioStream(sound, &datalen); - if(!data) + slen = Sound_DecodeAll(sample); + if(!sample->buffer || slen == 0) { fprintf(stderr, "Failed to read audio from %s\n", filename); - closeAudioFile(sound); + Sound_FreeSample(sample); return 0; } @@ -100,17 +114,15 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type), - channels, type, data); - free(data); - closeAudioFile(sound); + alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + Sound_FreeSample(sample); /* 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)) + if(buffer && alIsBuffer(buffer)) alDeleteBuffers(1, &buffer); return 0; } @@ -158,18 +170,16 @@ int main(int argc, char **argv) LOAD_PROC(alGetSourcei64SOFT); LOAD_PROC(alGetSource3i64SOFT); LOAD_PROC(alGetSourcei64vSOFT); - - if(alIsExtensionPresent("AL_SOFT_buffer_samples")) - { - LOAD_PROC(alBufferSamplesSOFT); - LOAD_PROC(alIsBufferFormatSupportedSOFT); - } #undef LOAD_PROC + /* Initialize SDL_sound. */ + Sound_Init(); + /* Load the sound into a buffer. */ buffer = LoadSound(argv[0]); if(!buffer) { + Sound_Quit(); CloseAL(); return 1; } @@ -195,10 +205,11 @@ int main(int argc, char **argv) } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); printf("\n"); - /* All done. Delete resources, and close OpenAL. */ + /* All done. Delete resources, and close down SDL_sound and OpenAL. */ alDeleteSources(1, &source); alDeleteBuffers(1, &buffer); + Sound_Quit(); CloseAL(); return 0; diff --git a/examples/alloopback.c b/examples/alloopback.c index c5dee36d..95ac433f 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -61,6 +61,35 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len) } +static const char *ChannelsName(ALCenum chans) +{ + switch(chans) + { + case ALC_MONO_SOFT: return "Mono"; + case ALC_STEREO_SOFT: return "Stereo"; + case ALC_QUAD_SOFT: return "Quadraphonic"; + case ALC_5POINT1_SOFT: return "5.1 Surround"; + case ALC_6POINT1_SOFT: return "6.1 Surround"; + case ALC_7POINT1_SOFT: return "7.1 Surround"; + } + return "Unknown Channels"; +} + +static const char *TypeName(ALCenum type) +{ + switch(type) + { + case ALC_BYTE_SOFT: return "S8"; + case ALC_UNSIGNED_BYTE_SOFT: return "U8"; + case ALC_SHORT_SOFT: return "S16"; + case ALC_UNSIGNED_SHORT_SOFT: return "U16"; + case ALC_INT_SOFT: return "S32"; + case ALC_UNSIGNED_INT_SOFT: return "U32"; + case ALC_FLOAT_SOFT: return "Float32"; + } + return "Unknown Type"; +} + /* Creates a one second buffer containing a sine wave, and returns the new * buffer ID. */ static ALuint CreateSineWave(void) @@ -169,7 +198,7 @@ int main(int argc, char *argv[]) attrs[6] = 0; /* end of list */ - playback.FrameSize = FramesToBytes(1, attrs[1], attrs[3]); + playback.FrameSize = obtained.channels * SDL_AUDIO_BITSIZE(obtained.format) / 8; /* Initialize OpenAL loopback device, using our format attributes. */ playback.Device = alcLoopbackOpenDeviceSOFT(NULL); diff --git a/examples/alreverb.c b/examples/alreverb.c index ec71f354..e6c9e606 100644 --- a/examples/alreverb.c +++ b/examples/alreverb.c @@ -27,17 +27,15 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "AL/efx-presets.h" #include "common/alhelpers.h" -#include "common/sdl_sound.h" - -static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples; -static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT; /* Effect object functions */ static LPALGENEFFECTS alGenEffects; @@ -145,46 +143,63 @@ static ALuint LoadEffect(const EFXEAXREVERBPROPERTIES *reverb) /* LoadBuffer loads the named audio file into an OpenAL buffer object, and - * returns the new buffer ID. */ + * returns the new buffer ID. + */ static ALuint LoadSound(const char *filename) { - ALenum err, format, type, channels; - ALuint rate, buffer; - size_t datalen; - void *data; - FilePtr sound; - - /* Open the file and get the first stream from it */ - sound = openAudioFile(filename, 1000); - if(!sound) + Sound_Sample *sample; + ALenum err, format; + ALuint buffer; + Uint32 slen; + + /* Open the audio file */ + sample = Sound_NewSampleFromFile(filename, NULL, 65536); + if(!sample) { fprintf(stderr, "Could not open audio in %s\n", filename); return 0; } /* Get the sound format, and figure out the OpenAL format */ - if(getAudioInfo(sound, &rate, &channels, &type) != 0) + if(sample->actual.channels == 1) { - fprintf(stderr, "Error getting audio info for %s\n", filename); - closeAudioFile(sound); - return 0; + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_MONO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_MONO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } } - - format = GetFormat(channels, type, alIsBufferFormatSupportedSOFT); - if(format == AL_NONE) + else if(sample->actual.channels == 2) + { + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_STEREO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_STEREO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } + } + else { - fprintf(stderr, "Unsupported format (%s, %s) for %s\n", - ChannelsName(channels), TypeName(type), filename); - closeAudioFile(sound); + fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels); + Sound_FreeSample(sample); return 0; } /* Decode the whole audio stream to a buffer. */ - data = decodeAudioStream(sound, &datalen); - if(!data) + slen = Sound_DecodeAll(sample); + if(!sample->buffer || slen == 0) { fprintf(stderr, "Failed to read audio from %s\n", filename); - closeAudioFile(sound); + Sound_FreeSample(sample); return 0; } @@ -192,17 +207,15 @@ static ALuint LoadSound(const char *filename) * close the file. */ buffer = 0; alGenBuffers(1, &buffer); - alBufferSamplesSOFT(buffer, rate, format, BytesToFrames(datalen, channels, type), - channels, type, data); - free(data); - closeAudioFile(sound); + alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + Sound_FreeSample(sample); /* 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)) + if(buffer && alIsBuffer(buffer)) alDeleteBuffers(1, &buffer); return 0; } @@ -261,19 +274,17 @@ int main(int argc, char **argv) LOAD_PROC(alGetAuxiliaryEffectSlotiv); LOAD_PROC(alGetAuxiliaryEffectSlotf); LOAD_PROC(alGetAuxiliaryEffectSlotfv); - - if(alIsExtensionPresent("AL_SOFT_buffer_samples")) - { - LOAD_PROC(alBufferSamplesSOFT); - LOAD_PROC(alIsBufferFormatSupportedSOFT); - } #undef LOAD_PROC + /* Initialize SDL_sound. */ + Sound_Init(); + /* Load the sound into a buffer. */ buffer = LoadSound(argv[0]); if(!buffer) { CloseAL(); + Sound_Quit(); return 1; } @@ -282,6 +293,7 @@ int main(int argc, char **argv) if(!effect) { alDeleteBuffers(1, &buffer); + Sound_Quit(); CloseAL(); return 1; } @@ -316,12 +328,13 @@ int main(int argc, char **argv) alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); - /* All done. Delete resources, and close OpenAL. */ + /* All done. Delete resources, and close down SDL_sound and OpenAL. */ alDeleteSources(1, &source); alDeleteAuxiliaryEffectSlots(1, &slot); alDeleteEffects(1, &effect); alDeleteBuffers(1, &buffer); + Sound_Quit(); CloseAL(); return 0; diff --git a/examples/alstream.c b/examples/alstream.c index 65a04475..d13899d0 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -30,16 +30,13 @@ #include #include +#include + #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "common/alhelpers.h" -#include "common/sdl_sound.h" - - -static LPALBUFFERSAMPLESSOFT alBufferSamplesSOFT = wrap_BufferSamples; -static LPALISBUFFERFORMATSUPPORTEDSOFT alIsBufferFormatSupportedSOFT; /* Define the number of buffers and buffer size (in milliseconds) to use. 4 @@ -54,13 +51,11 @@ typedef struct StreamPlayer { ALuint source; /* Handle for the audio file */ - FilePtr file; + Sound_Sample *sample; /* The format of the output stream */ ALenum format; - ALenum channels; - ALenum type; - ALuint rate; + ALsizei srate; } StreamPlayer; static StreamPlayer *NewPlayer(void); @@ -77,11 +72,9 @@ static StreamPlayer *NewPlayer(void) { StreamPlayer *player; - player = malloc(sizeof(*player)); + player = calloc(1, sizeof(*player)); assert(player != NULL); - memset(player, 0, sizeof(*player)); - /* Generate the buffers and source */ alGenBuffers(NUM_BUFFERS, player->buffers); assert(alGetError() == AL_NO_ERROR && "Could not create buffers"); @@ -119,37 +112,63 @@ static void DeletePlayer(StreamPlayer *player) * it will be closed first. */ static int OpenPlayerFile(StreamPlayer *player, const char *filename) { + Uint32 frame_size; + ClosePlayerFile(player); /* Open the file and get the first stream from it */ - player->file = openAudioFile(filename, BUFFER_TIME_MS); - if(!player->file) + player->sample = Sound_NewSampleFromFile(filename, NULL, 0); + if(!player->sample) { fprintf(stderr, "Could not open audio in %s\n", filename); goto error; } /* Get the stream format, and figure out the OpenAL format */ - if(getAudioInfo(player->file, &player->rate, &player->channels, &player->type) != 0) + if(player->sample->actual.channels == 1) { - fprintf(stderr, "Error getting audio info for %s\n", filename); - goto error; + if(player->sample->actual.format == AUDIO_U8) + player->format = AL_FORMAT_MONO8; + else if(player->sample->actual.format == AUDIO_S16SYS) + player->format = AL_FORMAT_MONO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", player->sample->actual.format); + goto error; + } } - - player->format = GetFormat(player->channels, player->type, alIsBufferFormatSupportedSOFT); - if(player->format == 0) + else if(player->sample->actual.channels == 2) { - fprintf(stderr, "Unsupported format (%s, %s) for %s\n", - ChannelsName(player->channels), TypeName(player->type), - filename); + if(player->sample->actual.format == AUDIO_U8) + player->format = AL_FORMAT_STEREO8; + else if(player->sample->actual.format == AUDIO_S16SYS) + player->format = AL_FORMAT_STEREO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", player->sample->actual.format); + goto error; + } + } + else + { + fprintf(stderr, "Unsupported channel count: %d\n", player->sample->actual.channels); goto error; } + player->srate = player->sample->actual.rate; + + frame_size = player->sample->actual.channels * + SDL_AUDIO_BITSIZE(player->sample->actual.format) / 8; + + /* Set the buffer size, given the desired millisecond length. */ + Sound_SetBufferSize(player->sample, (Uint32)((Uint64)player->srate*BUFFER_TIME_MS/1000) * + frame_size); return 1; error: - closeAudioFile(player->file); - player->file = NULL; + if(player->sample) + Sound_FreeSample(player->sample); + player->sample = NULL; return 0; } @@ -157,8 +176,9 @@ error: /* Closes the audio file stream */ static void ClosePlayerFile(StreamPlayer *player) { - closeAudioFile(player->file); - player->file = NULL; + if(player->sample) + Sound_FreeSample(player->sample); + player->sample = NULL; } @@ -174,16 +194,12 @@ 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 */ - data = getAudioData(player->file, &got); - if(!data) break; + Uint32 slen = Sound_Decode(player->sample); + if(slen == 0) break; - alBufferSamplesSOFT(player->buffers[i], player->rate, player->format, - BytesToFrames(got, player->channels, player->type), - player->channels, player->type, data); + alBufferData(player->buffers[i], player->format, + player->sample->buffer, slen, player->srate); } if(alGetError() != AL_NO_ERROR) { @@ -220,20 +236,21 @@ static int UpdatePlayer(StreamPlayer *player) while(processed > 0) { ALuint bufid; - uint8_t *data; - size_t got; + Uint32 slen; alSourceUnqueueBuffers(player->source, 1, &bufid); processed--; + if((player->sample->flags&(SOUND_SAMPLEFLAG_EOF|SOUND_SAMPLEFLAG_ERROR))) + continue; + /* Read the next chunk of data, refill the buffer, and queue it * back on the source */ - data = getAudioData(player->file, &got); - if(data != NULL) + slen = Sound_Decode(player->sample); + if(slen > 0) { - alBufferSamplesSOFT(bufid, player->rate, player->format, - BytesToFrames(got, player->channels, player->type), - player->channels, player->type, data); + alBufferData(bufid, player->format, player->sample->buffer, slen, + player->srate); alSourceQueueBuffers(player->source, 1, &bufid); } if(alGetError() != AL_NO_ERROR) @@ -281,14 +298,7 @@ int main(int argc, char **argv) if(InitAL(&argv, &argc) != 0) return 1; - if(alIsExtensionPresent("AL_SOFT_buffer_samples")) - { - printf("AL_SOFT_buffer_samples supported!\n"); - alBufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT"); - alIsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT"); - } - else - printf("AL_SOFT_buffer_samples not supported\n"); + Sound_Init(); player = NewPlayer(); @@ -307,9 +317,8 @@ int main(int argc, char **argv) else namepart = argv[i]; - printf("Playing: %s (%s, %s, %dhz)\n", namepart, - TypeName(player->type), ChannelsName(player->channels), - player->rate); + printf("Playing: %s (%s, %dhz)\n", namepart, FormatName(player->format), + player->srate); fflush(stdout); if(!StartPlayer(player)) @@ -326,10 +335,11 @@ int main(int argc, char **argv) } printf("Done.\n"); - /* All files done. Delete the player, and close OpenAL */ + /* All files done. Delete the player, and close down SDL_sound and OpenAL */ DeletePlayer(player); player = NULL; + Sound_Quit(); CloseAL(); return 0; diff --git a/examples/common/alhelpers.c b/examples/common/alhelpers.c index 43548b5c..fab039e9 100644 --- a/examples/common/alhelpers.c +++ b/examples/common/alhelpers.c @@ -103,243 +103,14 @@ void CloseAL(void) } -/* GetFormat retrieves a compatible buffer format given the channel config and - * sample type. If an alIsBufferFormatSupportedSOFT-compatible function is - * provided, it will be called to find the closest-matching format from - * AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be - * found. */ -ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT) +const char *FormatName(ALenum format) { - ALenum format = AL_NONE; - - /* If using AL_SOFT_buffer_samples, try looking through its formats */ - if(palIsBufferFormatSupportedSOFT) - { - /* AL_SOFT_buffer_samples is more lenient with matching formats. The - * specified sample type does not need to match the returned format, - * but it is nice to try to get something close. */ - if(type == AL_UNSIGNED_BYTE_SOFT || type == AL_BYTE_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT; - } - else if(type == AL_UNSIGNED_SHORT_SOFT || type == AL_SHORT_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT; - } - else if(type == AL_UNSIGNED_BYTE3_SOFT || type == AL_BYTE3_SOFT || - type == AL_UNSIGNED_INT_SOFT || type == AL_INT_SOFT || - type == AL_FLOAT_SOFT || type == AL_DOUBLE_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT; - } - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - - /* A matching format was not found or supported. Try 32-bit float. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - /* 32-bit float not supported. Try 16-bit int. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - /* 16-bit int not supported. Try 8-bit int. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - - return format; - } - - /* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1, - * and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and - * AL_EXT_DOUBLE for 64-bit float samples. */ - if(type == AL_UNSIGNED_BYTE_SOFT) - { - if(channels == AL_MONO_SOFT) - format = AL_FORMAT_MONO8; - else if(channels == AL_STEREO_SOFT) - format = AL_FORMAT_STEREO8; - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD8"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN8"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN8"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN8"); - } - } - else if(type == AL_SHORT_SOFT) - { - if(channels == AL_MONO_SOFT) - format = AL_FORMAT_MONO16; - else if(channels == AL_STEREO_SOFT) - format = AL_FORMAT_STEREO16; - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD16"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN16"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN16"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN16"); - } - } - else if(type == AL_FLOAT_SOFT && alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if(channels == AL_MONO_SOFT) - format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32"); - else if(channels == AL_STEREO_SOFT) - format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32"); - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD32"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN32"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN32"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN32"); - } - } - else if(type == AL_DOUBLE_SOFT && alIsExtensionPresent("AL_EXT_DOUBLE")) - { - if(channels == AL_MONO_SOFT) - format = alGetEnumValue("AL_FORMAT_MONO_DOUBLE"); - else if(channels == AL_STEREO_SOFT) - format = alGetEnumValue("AL_FORMAT_STEREO_DOUBLE"); - } - - /* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as - * opposed to 0. Correct it. */ - if(format == -1) - format = 0; - - return format; -} - - -void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, - ALenum internalformat, ALsizei samples, - ALenum channels, ALenum type, - const ALvoid *data) -{ - alBufferData(buffer, internalformat, data, - FramesToBytes(samples, channels, type), - samplerate); -} - - -const char *ChannelsName(ALenum chans) -{ - switch(chans) - { - case AL_MONO_SOFT: return "Mono"; - case AL_STEREO_SOFT: return "Stereo"; - case AL_REAR_SOFT: return "Rear"; - case AL_QUAD_SOFT: return "Quadraphonic"; - case AL_5POINT1_SOFT: return "5.1 Surround"; - case AL_6POINT1_SOFT: return "6.1 Surround"; - case AL_7POINT1_SOFT: return "7.1 Surround"; - } - return "Unknown Channels"; -} - -const char *TypeName(ALenum type) -{ - switch(type) + switch(format) { - case AL_BYTE_SOFT: return "S8"; - case AL_UNSIGNED_BYTE_SOFT: return "U8"; - case AL_SHORT_SOFT: return "S16"; - case AL_UNSIGNED_SHORT_SOFT: return "U16"; - case AL_INT_SOFT: return "S32"; - case AL_UNSIGNED_INT_SOFT: return "U32"; - case AL_FLOAT_SOFT: return "Float32"; - case AL_DOUBLE_SOFT: return "Float64"; + case AL_FORMAT_MONO8: return "Mono, U8"; + case AL_FORMAT_MONO16: return "Mono, S16"; + case AL_FORMAT_STEREO8: return "Stereo, U8"; + case AL_FORMAT_STEREO16: return "Stereo, S16"; } - return "Unknown Type"; -} - - -ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type) -{ - switch(channels) - { - case AL_MONO_SOFT: size *= 1; break; - case AL_STEREO_SOFT: size *= 2; break; - case AL_REAR_SOFT: size *= 2; break; - case AL_QUAD_SOFT: size *= 4; break; - case AL_5POINT1_SOFT: size *= 6; break; - case AL_6POINT1_SOFT: size *= 7; break; - case AL_7POINT1_SOFT: size *= 8; break; - } - - switch(type) - { - case AL_BYTE_SOFT: size *= sizeof(ALbyte); break; - case AL_UNSIGNED_BYTE_SOFT: size *= sizeof(ALubyte); break; - case AL_SHORT_SOFT: size *= sizeof(ALshort); break; - case AL_UNSIGNED_SHORT_SOFT: size *= sizeof(ALushort); break; - case AL_INT_SOFT: size *= sizeof(ALint); break; - case AL_UNSIGNED_INT_SOFT: size *= sizeof(ALuint); break; - case AL_FLOAT_SOFT: size *= sizeof(ALfloat); break; - case AL_DOUBLE_SOFT: size *= sizeof(ALdouble); break; - } - - return size; -} - -ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type) -{ - return size / FramesToBytes(1, channels, type); + return "Unknown Format"; } diff --git a/examples/common/alhelpers.h b/examples/common/alhelpers.h index 9f60df2a..41a7ce58 100644 --- a/examples/common/alhelpers.h +++ b/examples/common/alhelpers.h @@ -11,28 +11,8 @@ extern "C" { #endif /* __cplusplus */ -/* Some helper functions to get the name from the channel and type enums. */ -const char *ChannelsName(ALenum chans); -const char *TypeName(ALenum type); - -/* Helpers to convert frame counts and byte lengths. */ -ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type); -ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type); - -/* Retrieves a compatible buffer format given the channel configuration and - * sample type. If an alIsBufferFormatSupportedSOFT-compatible function is - * provided, it will be called to find the closest-matching format from - * AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be - * found. */ -ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT); - -/* Loads samples into a buffer using the standard alBufferData call, but with a - * LPALBUFFERSAMPLESSOFT-compatible prototype. Assumes internalformat is valid - * for alBufferData, and that channels and type match it. */ -void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, - ALenum internalformat, ALsizei samples, - ALenum channels, ALenum type, - const ALvoid *data); +/* Some helper functions to get the name from the format enums. */ +const char *FormatName(ALenum type); /* Easy device init/deinit functions. InitAL returns 0 on success. */ int InitAL(char ***argv, int *argc); diff --git a/examples/common/sdl_sound.c b/examples/common/sdl_sound.c deleted file mode 100644 index 79a5bf32..00000000 --- a/examples/common/sdl_sound.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SDL_sound Decoder Helpers - * - * Copyright (c) 2013 by Chris Robinson - * - * 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 -#include -#include -#include -#include - -#include - -#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 deleted file mode 100644 index e93ab92b..00000000 --- a/examples/common/sdl_sound.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef EXAMPLES_SDL_SOUND_H -#define EXAMPLES_SDL_SOUND_H - -#include "AL/al.h" - -#include - -#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 */ -- cgit v1.2.3 From 40c5fe4c3341ddda52fe7ab2ca54e0e33414e7f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Mar 2017 23:02:52 -0800 Subject: Remove ex-common and test-common static libs --- CMakeLists.txt | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f279951..cb85a9e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1442,11 +1442,10 @@ IF(ALSOFT_UTILS) ENDIF() IF(ALSOFT_TESTS) - ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) - SET_PROPERTY(TARGET test-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET(TEST_COMMON_OBJS examples/common/alhelpers.c) - ADD_EXECUTABLE(altonegen examples/altonegen.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(altonegen test-common OpenAL) + ADD_EXECUTABLE(altonegen examples/altonegen.c ${COMMON_OBJS} ${TEST_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(altonegen OpenAL) SET_PROPERTY(TARGET altonegen APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) IF(ALSOFT_INSTALL) @@ -1464,44 +1463,38 @@ ENDIF() IF(ALSOFT_EXAMPLES) IF(SDL2_FOUND) IF(SDL_SOUND_FOUND) - ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c) - SET_PROPERTY(TARGET ex-common APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + SET(EX_COMMON_OBJS examples/common/alhelpers.c) - ADD_EXECUTABLE(alstream examples/alstream.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(alstream ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - OpenAL) + ADD_EXECUTABLE(alstream examples/alstream.c ${COMMON_OBJS} ${EX_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alstream ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} OpenAL) SET_PROPERTY(TARGET alstream APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alstream APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alreverb examples/alreverb.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(alreverb ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - OpenAL) + ADD_EXECUTABLE(alreverb examples/alreverb.c ${COMMON_OBJS} ${EX_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alreverb ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} OpenAL) SET_PROPERTY(TARGET alreverb APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alreverb APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(allatency examples/allatency.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(allatency ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - OpenAL) + ADD_EXECUTABLE(allatency examples/allatency.c ${COMMON_OBJS} ${EX_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(allatency ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} OpenAL) SET_PROPERTY(TARGET allatency APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET allatency APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alloopback examples/alloopback.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(alloopback ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - OpenAL) + ADD_EXECUTABLE(alloopback examples/alloopback.c ${COMMON_OBJS} ${EX_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alloopback ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} OpenAL) SET_PROPERTY(TARGET alloopback APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} ) - ADD_EXECUTABLE(alhrtf examples/alhrtf.c ${COMMON_OBJS}) - TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} - OpenAL) + ADD_EXECUTABLE(alhrtf examples/alhrtf.c ${COMMON_OBJS} ${EX_COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alhrtf ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} OpenAL) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR} -- cgit v1.2.3 From c0404916150c48769d08ac32921b9a6a66dc0c0a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 Mar 2017 01:13:26 -0800 Subject: Update alffplay for newer ffmpeg and convert to C++ --- CMakeLists.txt | 24 +- examples/alffplay.c | 1573 ------------------------------------------------- examples/alffplay.cpp | 1546 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1558 insertions(+), 1585 deletions(-) delete mode 100644 examples/alffplay.c create mode 100644 examples/alffplay.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cb85a9e2..ed17743c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1514,29 +1514,29 @@ IF(ALSOFT_EXAMPLES) SET(FFVER_OK FALSE) IF(FFMPEG_FOUND) SET(FFVER_OK TRUE) - IF(AVFORMAT_VERSION VERSION_LESS "55.33.100") - MESSAGE(STATUS "libavformat is too old! (${AVFORMAT_VERSION}, wanted 55.33.100)") + IF(AVFORMAT_VERSION VERSION_LESS "57.56.101") + MESSAGE(STATUS "libavformat is too old! (${AVFORMAT_VERSION}, wanted 57.56.101)") SET(FFVER_OK FALSE) ENDIF() - IF(AVCODEC_VERSION VERSION_LESS "55.52.102") - MESSAGE(STATUS "libavcodec is too old! (${AVCODEC_VERSION}, wanted 55.52.102)") + IF(AVCODEC_VERSION VERSION_LESS "57.64.101") + MESSAGE(STATUS "libavcodec is too old! (${AVCODEC_VERSION}, wanted 57.64.101)") SET(FFVER_OK FALSE) ENDIF() - IF(AVUTIL_VERSION VERSION_LESS "52.66.100") - MESSAGE(STATUS "libavutil is too old! (${AVUTIL_VERSION}, wanted 52.66.100)") + IF(AVUTIL_VERSION VERSION_LESS "55.34.101") + MESSAGE(STATUS "libavutil is too old! (${AVUTIL_VERSION}, wanted 55.34.101)") SET(FFVER_OK FALSE) ENDIF() - IF(SWSCALE_VERSION VERSION_LESS "2.5.102") - MESSAGE(STATUS "libswscale is too old! (${SWSCALE_VERSION}, wanted 2.5.102)") + IF(SWSCALE_VERSION VERSION_LESS "4.2.100") + MESSAGE(STATUS "libswscale is too old! (${SWSCALE_VERSION}, wanted 4.2.100)") SET(FFVER_OK FALSE) ENDIF() - IF(SWRESAMPLE_VERSION VERSION_LESS "0.18.100") - MESSAGE(STATUS "libswresample is too old! (${SWRESAMPLE_VERSION}, wanted 0.18.100)") + IF(SWRESAMPLE_VERSION VERSION_LESS "2.3.100") + MESSAGE(STATUS "libswresample is too old! (${SWRESAMPLE_VERSION}, wanted 2.3.100)") SET(FFVER_OK FALSE) ENDIF() ENDIF() - IF(FFVER_OK AND NOT MSVC) - ADD_EXECUTABLE(alffplay examples/alffplay.c ${COMMON_OBJS}) + IF(FFVER_OK) + ADD_EXECUTABLE(alffplay examples/alffplay.cpp ${COMMON_OBJS}) TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} OpenAL ${FFMPEG_LIBRARIES}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) SET_PROPERTY(TARGET alffplay APPEND PROPERTY diff --git a/examples/alffplay.c b/examples/alffplay.c deleted file mode 100644 index b61828f0..00000000 --- a/examples/alffplay.c +++ /dev/null @@ -1,1573 +0,0 @@ -/* - * alffplay.c - * - * A pedagogical video player that really works! Now with seeking features. - * - * Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, and a tutorial by - * Martin Bohme . - * - * Requires C99. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "threads.h" -#include "bool.h" - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - - -static bool has_direct_out = false; -static bool has_latency_check = false; -static LPALGETSOURCEDVSOFT alGetSourcedvSOFT; - -#define AUDIO_BUFFER_TIME 100 /* In milliseconds, per-buffer */ -#define AUDIO_BUFFER_QUEUE_SIZE 8 /* Number of buffers to queue */ -#define MAX_AUDIOQ_SIZE (5 * 16 * 1024) /* Bytes of compressed audio data to keep queued */ -#define MAX_VIDEOQ_SIZE (5 * 256 * 1024) /* Bytes of compressed video data to keep queued */ -#define AV_SYNC_THRESHOLD 0.01 -#define AV_NOSYNC_THRESHOLD 10.0 -#define SAMPLE_CORRECTION_MAX_DIFF 0.1 -#define AUDIO_DIFF_AVG_NB 20 -#define VIDEO_PICTURE_QUEUE_SIZE 16 - -enum { - FF_UPDATE_EVENT = SDL_USEREVENT, - FF_REFRESH_EVENT, - FF_QUIT_EVENT -}; - - -typedef struct PacketQueue { - AVPacketList *first_pkt, *last_pkt; - volatile int nb_packets; - volatile int size; - volatile bool flushing; - almtx_t mutex; - alcnd_t cond; -} PacketQueue; - -typedef struct VideoPicture { - SDL_Texture *bmp; - int width, height; /* Logical image size (actual size may be larger) */ - volatile bool updated; - double pts; -} VideoPicture; - -typedef struct AudioState { - AVStream *st; - - PacketQueue q; - AVPacket pkt; - - /* Used for clock difference average computation */ - double diff_accum; - double diff_avg_coef; - double diff_threshold; - - /* Time (in seconds) of the next sample to be buffered */ - double current_pts; - - /* Decompressed sample frame, and swresample context for conversion */ - AVFrame *decoded_aframe; - struct SwrContext *swres_ctx; - - /* Conversion format, for what gets fed to OpenAL */ - int dst_ch_layout; - enum AVSampleFormat dst_sample_fmt; - - /* Storage of converted samples */ - uint8_t *samples; - ssize_t samples_len; /* In samples */ - ssize_t samples_pos; - int samples_max; - - /* OpenAL format */ - ALenum format; - ALint frame_size; - - ALuint source; - ALuint buffer[AUDIO_BUFFER_QUEUE_SIZE]; - ALuint buffer_idx; - almtx_t src_mutex; - - althrd_t thread; -} AudioState; - -typedef struct VideoState { - AVStream *st; - - PacketQueue q; - - double clock; - double frame_timer; - double frame_last_pts; - double frame_last_delay; - double current_pts; - /* time (av_gettime) at which we updated current_pts - used to have running video pts */ - int64_t current_pts_time; - - /* Decompressed video frame, and swscale context for conversion */ - AVFrame *decoded_vframe; - struct SwsContext *swscale_ctx; - - VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; - int pictq_size, pictq_rindex, pictq_windex; - almtx_t pictq_mutex; - alcnd_t pictq_cond; - - althrd_t thread; -} VideoState; - -typedef struct MovieState { - AVFormatContext *pFormatCtx; - int videoStream, audioStream; - - volatile bool seek_req; - int64_t seek_pos; - volatile bool direct_req; - - int av_sync_type; - - int64_t external_clock_base; - - AudioState audio; - VideoState video; - - althrd_t parse_thread; - - char filename[1024]; - - volatile bool quit; -} MovieState; - -enum { - AV_SYNC_AUDIO_MASTER, - AV_SYNC_VIDEO_MASTER, - AV_SYNC_EXTERNAL_MASTER, - - DEFAULT_AV_SYNC_TYPE = AV_SYNC_EXTERNAL_MASTER -}; - -static AVPacket flush_pkt = { .data = (uint8_t*)"FLUSH" }; - -static void packet_queue_init(PacketQueue *q) -{ - memset(q, 0, sizeof(PacketQueue)); - almtx_init(&q->mutex, almtx_plain); - alcnd_init(&q->cond); -} -static int packet_queue_put(PacketQueue *q, AVPacket *pkt) -{ - AVPacketList *pkt1; - if(pkt != &flush_pkt && !pkt->buf && av_dup_packet(pkt) < 0) - return -1; - - pkt1 = av_malloc(sizeof(AVPacketList)); - if(!pkt1) return -1; - pkt1->pkt = *pkt; - pkt1->next = NULL; - - almtx_lock(&q->mutex); - if(!q->last_pkt) - q->first_pkt = pkt1; - else - q->last_pkt->next = pkt1; - q->last_pkt = pkt1; - q->nb_packets++; - q->size += pkt1->pkt.size; - almtx_unlock(&q->mutex); - - alcnd_signal(&q->cond); - return 0; -} -static int packet_queue_get(PacketQueue *q, AVPacket *pkt, MovieState *state) -{ - AVPacketList *pkt1; - int ret = -1; - - almtx_lock(&q->mutex); - while(!state->quit) - { - pkt1 = q->first_pkt; - if(pkt1) - { - q->first_pkt = pkt1->next; - if(!q->first_pkt) - q->last_pkt = NULL; - q->nb_packets--; - q->size -= pkt1->pkt.size; - *pkt = pkt1->pkt; - av_free(pkt1); - ret = 1; - break; - } - - if(q->flushing) - { - ret = 0; - break; - } - alcnd_wait(&q->cond, &q->mutex); - } - almtx_unlock(&q->mutex); - return ret; -} -static void packet_queue_clear(PacketQueue *q) -{ - AVPacketList *pkt, *pkt1; - - almtx_lock(&q->mutex); - for(pkt = q->first_pkt;pkt != NULL;pkt = pkt1) - { - pkt1 = pkt->next; - if(pkt->pkt.data != flush_pkt.data) - av_free_packet(&pkt->pkt); - av_freep(&pkt); - } - q->last_pkt = NULL; - q->first_pkt = NULL; - q->nb_packets = 0; - q->size = 0; - almtx_unlock(&q->mutex); -} -static void packet_queue_flush(PacketQueue *q) -{ - almtx_lock(&q->mutex); - q->flushing = true; - almtx_unlock(&q->mutex); - alcnd_signal(&q->cond); -} -static void packet_queue_deinit(PacketQueue *q) -{ - packet_queue_clear(q); - alcnd_destroy(&q->cond); - almtx_destroy(&q->mutex); -} - - -static double get_audio_clock(AudioState *state) -{ - double pts; - - almtx_lock(&state->src_mutex); - /* The audio clock is the timestamp of the sample currently being heard. - * It's based on 4 components: - * 1 - The timestamp of the next sample to buffer (state->current_pts) - * 2 - The length of the source's buffer queue (AL_SEC_LENGTH_SOFT) - * 3 - The offset OpenAL is currently at in the source (the first value - * from AL_SEC_OFFSET_LATENCY_SOFT) - * 4 - The latency between OpenAL and the DAC (the second value from - * AL_SEC_OFFSET_LATENCY_SOFT) - * - * Subtracting the length of the source queue from the next sample's - * timestamp gives the timestamp of the sample at start of the source - * queue. Adding the source offset to that results in the timestamp for - * OpenAL's current position, and subtracting the source latency from that - * gives the timestamp of the sample currently at the DAC. - */ - pts = state->current_pts; - if(state->source) - { - ALdouble offset[2] = { 0.0, 0.0 }; - ALdouble queue_len = 0.0; - ALint status; - - /* NOTE: The source state must be checked last, in case an underrun - * occurs and the source stops between retrieving the offset+latency - * and getting the state. */ - if(has_latency_check) - { - alGetSourcedvSOFT(state->source, AL_SEC_OFFSET_LATENCY_SOFT, offset); - alGetSourcedvSOFT(state->source, AL_SEC_LENGTH_SOFT, &queue_len); - } - else - { - ALint ioffset, ilen; - alGetSourcei(state->source, AL_SAMPLE_OFFSET, &ioffset); - alGetSourcei(state->source, AL_SAMPLE_LENGTH_SOFT, &ilen); - offset[0] = (double)ioffset / state->st->codec->sample_rate; - queue_len = (double)ilen / state->st->codec->sample_rate; - } - alGetSourcei(state->source, AL_SOURCE_STATE, &status); - - /* If the source is AL_STOPPED, then there was an underrun and all - * buffers are processed, so ignore the source queue. The audio thread - * will put the source into an AL_INITIAL state and clear the queue - * when it starts recovery. */ - if(status != AL_STOPPED) - pts = pts - queue_len + offset[0]; - if(status == AL_PLAYING) - pts = pts - offset[1]; - } - almtx_unlock(&state->src_mutex); - - return (pts >= 0.0) ? pts : 0.0; -} -static double get_video_clock(VideoState *state) -{ - double delta = (av_gettime() - state->current_pts_time) / 1000000.0; - return state->current_pts + delta; -} -static double get_external_clock(MovieState *movState) -{ - return (av_gettime()-movState->external_clock_base) / 1000000.0; -} - -double get_master_clock(MovieState *movState) -{ - if(movState->av_sync_type == AV_SYNC_VIDEO_MASTER) - return get_video_clock(&movState->video); - if(movState->av_sync_type == AV_SYNC_AUDIO_MASTER) - return get_audio_clock(&movState->audio); - return get_external_clock(movState); -} - -/* Return how many samples to skip to maintain sync (negative means to - * duplicate samples). */ -static int synchronize_audio(MovieState *movState) -{ - double diff, avg_diff; - double ref_clock; - - if(movState->av_sync_type == AV_SYNC_AUDIO_MASTER) - return 0; - - ref_clock = get_master_clock(movState); - diff = ref_clock - get_audio_clock(&movState->audio); - - if(!(fabs(diff) < AV_NOSYNC_THRESHOLD)) - { - /* Difference is TOO big; reset diff stuff */ - movState->audio.diff_accum = 0.0; - return 0; - } - - /* Accumulate the diffs */ - movState->audio.diff_accum = movState->audio.diff_accum*movState->audio.diff_avg_coef + diff; - avg_diff = movState->audio.diff_accum*(1.0 - movState->audio.diff_avg_coef); - if(fabs(avg_diff) < movState->audio.diff_threshold) - return 0; - - /* Constrain the per-update difference to avoid exceedingly large skips */ - if(!(diff <= SAMPLE_CORRECTION_MAX_DIFF)) - diff = SAMPLE_CORRECTION_MAX_DIFF; - else if(!(diff >= -SAMPLE_CORRECTION_MAX_DIFF)) - diff = -SAMPLE_CORRECTION_MAX_DIFF; - return (int)(diff*movState->audio.st->codec->sample_rate); -} - -static int audio_decode_frame(MovieState *movState) -{ - AVPacket *pkt = &movState->audio.pkt; - - while(!movState->quit) - { - while(!movState->quit && pkt->size == 0) - { - av_free_packet(pkt); - - /* Get the next packet */ - int err; - if((err=packet_queue_get(&movState->audio.q, pkt, movState)) <= 0) - { - if(err == 0) - break; - return err; - } - if(pkt->data == flush_pkt.data) - { - avcodec_flush_buffers(movState->audio.st->codec); - movState->audio.diff_accum = 0.0; - movState->audio.current_pts = av_q2d(movState->audio.st->time_base)*pkt->pts; - - alSourceRewind(movState->audio.source); - alSourcei(movState->audio.source, AL_BUFFER, 0); - - av_new_packet(pkt, 0); - - return -1; - } - - /* If provided, update w/ pts */ - if(pkt->pts != AV_NOPTS_VALUE) - movState->audio.current_pts = av_q2d(movState->audio.st->time_base)*pkt->pts; - } - - AVFrame *frame = movState->audio.decoded_aframe; - int got_frame = 0; - int len1 = avcodec_decode_audio4(movState->audio.st->codec, frame, - &got_frame, pkt); - if(len1 < 0) - { - av_shrink_packet(pkt, 0); - continue; - } - - if(len1 <= pkt->size) - { - /* Move the unread data to the front and clear the end bits */ - int remaining = pkt->size - len1; - memmove(pkt->data, &pkt->data[len1], remaining); - av_shrink_packet(pkt, remaining); - } - - if(!got_frame || frame->nb_samples <= 0) - { - av_frame_unref(frame); - continue; - } - - if(frame->nb_samples > movState->audio.samples_max) - { - av_freep(&movState->audio.samples); - av_samples_alloc( - &movState->audio.samples, NULL, movState->audio.st->codec->channels, - frame->nb_samples, movState->audio.dst_sample_fmt, 0 - ); - movState->audio.samples_max = frame->nb_samples; - } - /* Return the amount of sample frames converted */ - int data_size = swr_convert(movState->audio.swres_ctx, - &movState->audio.samples, frame->nb_samples, - (const uint8_t**)frame->data, frame->nb_samples - ); - - av_frame_unref(frame); - return data_size; - } - - return -1; -} - -static int read_audio(MovieState *movState, uint8_t *samples, int length) -{ - int sample_skip = synchronize_audio(movState); - int audio_size = 0; - - /* Read the next chunk of data, refill the buffer, and queue it - * on the source */ - length /= movState->audio.frame_size; - while(audio_size < length) - { - if(movState->audio.samples_len <= 0 || movState->audio.samples_pos >= movState->audio.samples_len) - { - int frame_len = audio_decode_frame(movState); - if(frame_len < 0) return -1; - - movState->audio.samples_len = frame_len; - if(movState->audio.samples_len == 0) - break; - - movState->audio.samples_pos = (movState->audio.samples_len < sample_skip) ? - movState->audio.samples_len : sample_skip; - sample_skip -= movState->audio.samples_pos; - - movState->audio.current_pts += (double)movState->audio.samples_pos / - (double)movState->audio.st->codec->sample_rate; - continue; - } - - int rem = length - audio_size; - if(movState->audio.samples_pos >= 0) - { - int n = movState->audio.frame_size; - int len = movState->audio.samples_len - movState->audio.samples_pos; - if(rem > len) rem = len; - memcpy(samples + audio_size*n, - movState->audio.samples + movState->audio.samples_pos*n, - rem*n); - } - else - { - int n = movState->audio.frame_size; - int len = -movState->audio.samples_pos; - if(rem > len) rem = len; - - /* Add samples by copying the first sample */ - if(n == 1) - { - uint8_t sample = ((uint8_t*)movState->audio.samples)[0]; - uint8_t *q = (uint8_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 2) - { - uint16_t sample = ((uint16_t*)movState->audio.samples)[0]; - uint16_t *q = (uint16_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 4) - { - uint32_t sample = ((uint32_t*)movState->audio.samples)[0]; - uint32_t *q = (uint32_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 8) - { - uint64_t sample = ((uint64_t*)movState->audio.samples)[0]; - uint64_t *q = (uint64_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else - { - uint8_t *sample = movState->audio.samples; - uint8_t *q = samples + audio_size*n; - for(int i = 0;i < rem;i++) - { - memcpy(q, sample, n); - q += n; - } - } - } - - movState->audio.samples_pos += rem; - movState->audio.current_pts += (double)rem / movState->audio.st->codec->sample_rate; - audio_size += rem; - } - - return audio_size * movState->audio.frame_size; -} - -static int audio_thread(void *userdata) -{ - MovieState *movState = (MovieState*)userdata; - uint8_t *samples = NULL; - ALsizei buffer_len; - ALenum fmt; - - alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer); - alGenSources(1, &movState->audio.source); - - alSourcei(movState->audio.source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(movState->audio.source, AL_ROLLOFF_FACTOR, 0); - - av_new_packet(&movState->audio.pkt, 0); - - /* Find a suitable format for OpenAL. */ - movState->audio.format = AL_NONE; - if(movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8 || - movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8P) - { - movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_U8; - movState->audio.frame_size = 1; - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 8; - movState->audio.format = fmt; - } - if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || - movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 6; - movState->audio.format = fmt; - } - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; - movState->audio.frame_size *= 1; - movState->audio.format = AL_FORMAT_MONO8; - } - if(movState->audio.format == AL_NONE) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; - movState->audio.frame_size *= 2; - movState->audio.format = AL_FORMAT_STEREO8; - } - } - if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT || - movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) && - alIsExtensionPresent("AL_EXT_FLOAT32")) - { - movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT; - movState->audio.frame_size = 4; - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 8; - movState->audio.format = fmt; - } - if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || - movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 6; - movState->audio.format = fmt; - } - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; - movState->audio.frame_size *= 1; - movState->audio.format = AL_FORMAT_MONO_FLOAT32; - } - if(movState->audio.format == AL_NONE) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; - movState->audio.frame_size *= 2; - movState->audio.format = AL_FORMAT_STEREO_FLOAT32; - } - } - if(movState->audio.format == AL_NONE) - { - movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16; - movState->audio.frame_size = 2; - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 8; - movState->audio.format = fmt; - } - if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || - movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && - alIsExtensionPresent("AL_EXT_MCFORMATS") && - (fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1) - { - movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; - movState->audio.frame_size *= 6; - movState->audio.format = fmt; - } - if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; - movState->audio.frame_size *= 1; - movState->audio.format = AL_FORMAT_MONO16; - } - if(movState->audio.format == AL_NONE) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; - movState->audio.frame_size *= 2; - movState->audio.format = AL_FORMAT_STEREO16; - } - } - buffer_len = AUDIO_BUFFER_TIME * movState->audio.st->codec->sample_rate / 1000 * - movState->audio.frame_size; - samples = av_malloc(buffer_len); - - movState->audio.samples = NULL; - movState->audio.samples_max = 0; - movState->audio.samples_pos = 0; - movState->audio.samples_len = 0; - - if(!(movState->audio.decoded_aframe=av_frame_alloc())) - { - fprintf(stderr, "Failed to allocate audio frame\n"); - goto finish; - } - - movState->audio.swres_ctx = swr_alloc_set_opts(NULL, - movState->audio.dst_ch_layout, - movState->audio.dst_sample_fmt, - movState->audio.st->codec->sample_rate, - movState->audio.st->codec->channel_layout ? - movState->audio.st->codec->channel_layout : - (uint64_t)av_get_default_channel_layout(movState->audio.st->codec->channels), - movState->audio.st->codec->sample_fmt, - movState->audio.st->codec->sample_rate, - 0, NULL - ); - if(!movState->audio.swres_ctx || swr_init(movState->audio.swres_ctx) != 0) - { - fprintf(stderr, "Failed to initialize audio converter\n"); - goto finish; - } - - almtx_lock(&movState->audio.src_mutex); - while(alGetError() == AL_NO_ERROR && !movState->quit) - { - /* First remove any processed buffers. */ - ALint processed; - alGetSourcei(movState->audio.source, AL_BUFFERS_PROCESSED, &processed); - alSourceUnqueueBuffers(movState->audio.source, processed, (ALuint[AUDIO_BUFFER_QUEUE_SIZE]){}); - - /* Refill the buffer queue. */ - ALint queued; - alGetSourcei(movState->audio.source, AL_BUFFERS_QUEUED, &queued); - while(queued < AUDIO_BUFFER_QUEUE_SIZE) - { - int audio_size; - - /* Read the next chunk of data, fill the buffer, and queue it on - * the source */ - audio_size = read_audio(movState, samples, buffer_len); - if(audio_size < 0) break; - - ALuint bufid = movState->audio.buffer[movState->audio.buffer_idx++]; - movState->audio.buffer_idx %= AUDIO_BUFFER_QUEUE_SIZE; - - alBufferData(bufid, movState->audio.format, samples, audio_size, - movState->audio.st->codec->sample_rate); - alSourceQueueBuffers(movState->audio.source, 1, &bufid); - queued++; - } - - /* Check that the source is playing. */ - ALint state; - alGetSourcei(movState->audio.source, AL_SOURCE_STATE, &state); - if(state == AL_STOPPED) - { - /* AL_STOPPED means there was an underrun. Double-check that all - * processed buffers are removed, then rewind the source to get it - * back into an AL_INITIAL state. */ - alGetSourcei(movState->audio.source, AL_BUFFERS_PROCESSED, &processed); - alSourceUnqueueBuffers(movState->audio.source, processed, (ALuint[AUDIO_BUFFER_QUEUE_SIZE]){}); - alSourceRewind(movState->audio.source); - continue; - } - - almtx_unlock(&movState->audio.src_mutex); - - /* (re)start the source if needed, and wait for a buffer to finish */ - if(state != AL_PLAYING && state != AL_PAUSED) - { - alGetSourcei(movState->audio.source, AL_BUFFERS_QUEUED, &queued); - if(queued > 0) alSourcePlay(movState->audio.source); - } - SDL_Delay(AUDIO_BUFFER_TIME); - - if(movState->direct_req) - { - if(has_direct_out) - { - alGetSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, &state); - state = !state; - alSourcei(movState->audio.source, AL_DIRECT_CHANNELS_SOFT, - state ? AL_TRUE : AL_FALSE); - printf("Direct channels %s\n", state ? "on" : "off"); - fflush(stdout); - } - movState->direct_req = false; - } - - almtx_lock(&movState->audio.src_mutex); - } - almtx_unlock(&movState->audio.src_mutex); - -finish: - av_frame_free(&movState->audio.decoded_aframe); - swr_free(&movState->audio.swres_ctx); - - av_freep(&samples); - av_freep(&movState->audio.samples); - - alDeleteSources(1, &movState->audio.source); - alDeleteBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer); - - return 0; -} - - -static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) -{ - (void)interval; - - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_REFRESH_EVENT, .data1=opaque} }); - return 0; /* 0 means stop timer */ -} - -/* Schedule a video refresh in 'delay' ms */ -static void schedule_refresh(MovieState *movState, int delay) -{ - SDL_AddTimer(delay, sdl_refresh_timer_cb, movState); -} - -static void video_display(MovieState *movState, SDL_Window *screen, SDL_Renderer *renderer) -{ - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_rindex]; - - if(!vp->bmp) - return; - - float aspect_ratio; - int win_w, win_h; - int w, h, x, y; - - if(movState->video.st->codec->sample_aspect_ratio.num == 0) - aspect_ratio = 0.0f; - else - { - aspect_ratio = av_q2d(movState->video.st->codec->sample_aspect_ratio) * - movState->video.st->codec->width / - movState->video.st->codec->height; - } - if(aspect_ratio <= 0.0f) - { - aspect_ratio = (float)movState->video.st->codec->width / - (float)movState->video.st->codec->height; - } - - SDL_GetWindowSize(screen, &win_w, &win_h); - h = win_h; - w = ((int)rint(h * aspect_ratio) + 3) & ~3; - if(w > win_w) - { - w = win_w; - h = ((int)rint(w / aspect_ratio) + 3) & ~3; - } - x = (win_w - w) / 2; - y = (win_h - h) / 2; - - SDL_RenderCopy(renderer, vp->bmp, - &(SDL_Rect){ .x=0, .y=0, .w=vp->width, .h=vp->height }, - &(SDL_Rect){ .x=x, .y=y, .w=w, .h=h } - ); - SDL_RenderPresent(renderer); -} - -static void video_refresh_timer(MovieState *movState, SDL_Window *screen, SDL_Renderer *renderer) -{ - if(!movState->video.st) - { - schedule_refresh(movState, 100); - return; - } - - almtx_lock(&movState->video.pictq_mutex); -retry: - if(movState->video.pictq_size == 0) - schedule_refresh(movState, 1); - else - { - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_rindex]; - double actual_delay, delay, sync_threshold, ref_clock, diff; - - movState->video.current_pts = vp->pts; - movState->video.current_pts_time = av_gettime(); - - delay = vp->pts - movState->video.frame_last_pts; /* the pts from last time */ - if(delay <= 0 || delay >= 1.0) - { - /* if incorrect delay, use previous one */ - delay = movState->video.frame_last_delay; - } - /* save for next time */ - movState->video.frame_last_delay = delay; - movState->video.frame_last_pts = vp->pts; - - /* Update delay to sync to clock if not master source. */ - if(movState->av_sync_type != AV_SYNC_VIDEO_MASTER) - { - ref_clock = get_master_clock(movState); - diff = vp->pts - ref_clock; - - /* Skip or repeat the frame. Take delay into account. */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) - { - if(diff <= -sync_threshold) - delay = 0; - else if(diff >= sync_threshold) - delay = 2 * delay; - } - } - - movState->video.frame_timer += delay; - /* Compute the REAL delay. */ - actual_delay = movState->video.frame_timer - (av_gettime() / 1000000.0); - if(!(actual_delay >= 0.010)) - { - /* We don't have time to handle this picture, just skip to the next one. */ - movState->video.pictq_rindex = (movState->video.pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE; - movState->video.pictq_size--; - alcnd_signal(&movState->video.pictq_cond); - goto retry; - } - schedule_refresh(movState, (int)(actual_delay*1000.0 + 0.5)); - - /* Show the picture! */ - video_display(movState, screen, renderer); - - /* Update queue for next picture. */ - movState->video.pictq_rindex = (movState->video.pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE; - movState->video.pictq_size--; - alcnd_signal(&movState->video.pictq_cond); - } - almtx_unlock(&movState->video.pictq_mutex); -} - - -static void update_picture(MovieState *movState, bool *first_update, SDL_Window *screen, SDL_Renderer *renderer) -{ - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_windex]; - - /* allocate or resize the buffer! */ - if(!vp->bmp || vp->width != movState->video.st->codec->width || - vp->height != movState->video.st->codec->height) - { - if(vp->bmp) - SDL_DestroyTexture(vp->bmp); - vp->bmp = SDL_CreateTexture( - renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, - movState->video.st->codec->coded_width, movState->video.st->codec->coded_height - ); - if(!vp->bmp) - fprintf(stderr, "Failed to create YV12 texture!\n"); - vp->width = movState->video.st->codec->width; - vp->height = movState->video.st->codec->height; - - if(*first_update && vp->width > 0 && vp->height > 0) - { - /* For the first update, set the window size to the video size. */ - *first_update = false; - - int w = vp->width; - int h = vp->height; - if(movState->video.st->codec->sample_aspect_ratio.num != 0 && - movState->video.st->codec->sample_aspect_ratio.den != 0) - { - double aspect_ratio = av_q2d(movState->video.st->codec->sample_aspect_ratio); - if(aspect_ratio >= 1.0) - w = (int)(w*aspect_ratio + 0.5); - else if(aspect_ratio > 0.0) - h = (int)(h/aspect_ratio + 0.5); - } - SDL_SetWindowSize(screen, w, h); - } - } - - if(vp->bmp) - { - AVFrame *frame = movState->video.decoded_vframe; - void *pixels = NULL; - int pitch = 0; - - if(movState->video.st->codec->pix_fmt == AV_PIX_FMT_YUV420P) - SDL_UpdateYUVTexture(vp->bmp, NULL, - frame->data[0], frame->linesize[0], - frame->data[1], frame->linesize[1], - frame->data[2], frame->linesize[2] - ); - else if(SDL_LockTexture(vp->bmp, NULL, &pixels, &pitch) != 0) - fprintf(stderr, "Failed to lock texture\n"); - else - { - // Convert the image into YUV format that SDL uses - int coded_w = movState->video.st->codec->coded_width; - int coded_h = movState->video.st->codec->coded_height; - int w = movState->video.st->codec->width; - int h = movState->video.st->codec->height; - if(!movState->video.swscale_ctx) - movState->video.swscale_ctx = sws_getContext( - w, h, movState->video.st->codec->pix_fmt, - w, h, AV_PIX_FMT_YUV420P, SWS_X, NULL, NULL, NULL - ); - - /* point pict at the queue */ - AVPicture pict; - pict.data[0] = pixels; - pict.data[2] = pict.data[0] + coded_w*coded_h; - pict.data[1] = pict.data[2] + coded_w*coded_h/4; - - pict.linesize[0] = pitch; - pict.linesize[2] = pitch / 2; - pict.linesize[1] = pitch / 2; - - sws_scale(movState->video.swscale_ctx, (const uint8_t**)frame->data, - frame->linesize, 0, h, pict.data, pict.linesize); - SDL_UnlockTexture(vp->bmp); - } - } - - almtx_lock(&movState->video.pictq_mutex); - vp->updated = true; - almtx_unlock(&movState->video.pictq_mutex); - alcnd_signal(&movState->video.pictq_cond); -} - -static int queue_picture(MovieState *movState, double pts) -{ - /* Wait until we have space for a new pic */ - almtx_lock(&movState->video.pictq_mutex); - while(movState->video.pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !movState->quit) - alcnd_wait(&movState->video.pictq_cond, &movState->video.pictq_mutex); - almtx_unlock(&movState->video.pictq_mutex); - - if(movState->quit) - return -1; - - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_windex]; - - /* We have to create/update the picture in the main thread */ - vp->updated = false; - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_UPDATE_EVENT, .data1=movState} }); - - /* Wait until the picture is updated. */ - almtx_lock(&movState->video.pictq_mutex); - while(!vp->updated && !movState->quit) - alcnd_wait(&movState->video.pictq_cond, &movState->video.pictq_mutex); - almtx_unlock(&movState->video.pictq_mutex); - if(movState->quit) - return -1; - vp->pts = pts; - - movState->video.pictq_windex = (movState->video.pictq_windex+1)%VIDEO_PICTURE_QUEUE_SIZE; - almtx_lock(&movState->video.pictq_mutex); - movState->video.pictq_size++; - almtx_unlock(&movState->video.pictq_mutex); - - return 0; -} - -static double synchronize_video(MovieState *movState, double pts) -{ - double frame_delay; - - if(pts == 0.0) /* if we aren't given a pts, set it to the clock */ - pts = movState->video.clock; - else /* if we have pts, set video clock to it */ - movState->video.clock = pts; - - /* update the video clock */ - frame_delay = av_q2d(movState->video.st->codec->time_base); - /* if we are repeating a frame, adjust clock accordingly */ - frame_delay += movState->video.decoded_vframe->repeat_pict * (frame_delay * 0.5); - movState->video.clock += frame_delay; - return pts; -} - -int video_thread(void *arg) -{ - MovieState *movState = (MovieState*)arg; - AVPacket *packet = (AVPacket[1]){}; - int64_t saved_pts, pkt_pts; - int frameFinished; - - movState->video.decoded_vframe = av_frame_alloc(); - while(packet_queue_get(&movState->video.q, packet, movState) >= 0) - { - if(packet->data == flush_pkt.data) - { - avcodec_flush_buffers(movState->video.st->codec); - - almtx_lock(&movState->video.pictq_mutex); - movState->video.pictq_size = 0; - movState->video.pictq_rindex = 0; - movState->video.pictq_windex = 0; - almtx_unlock(&movState->video.pictq_mutex); - - movState->video.clock = av_q2d(movState->video.st->time_base)*packet->pts; - movState->video.current_pts = movState->video.clock; - movState->video.current_pts_time = av_gettime(); - continue; - } - - pkt_pts = packet->pts; - - /* Decode video frame */ - avcodec_decode_video2(movState->video.st->codec, movState->video.decoded_vframe, - &frameFinished, packet); - if(pkt_pts != AV_NOPTS_VALUE && !movState->video.decoded_vframe->opaque) - { - /* Store the packet's original pts in the frame, in case the frame - * is not finished decoding yet. */ - saved_pts = pkt_pts; - movState->video.decoded_vframe->opaque = &saved_pts; - } - - av_free_packet(packet); - - if(frameFinished) - { - double pts = av_q2d(movState->video.st->time_base); - if(packet->dts != AV_NOPTS_VALUE) - pts *= packet->dts; - else if(movState->video.decoded_vframe->opaque) - pts *= *(int64_t*)movState->video.decoded_vframe->opaque; - else - pts *= 0.0; - movState->video.decoded_vframe->opaque = NULL; - - pts = synchronize_video(movState, pts); - if(queue_picture(movState, pts) < 0) - break; - } - } - - sws_freeContext(movState->video.swscale_ctx); - movState->video.swscale_ctx = NULL; - av_frame_free(&movState->video.decoded_vframe); - return 0; -} - - -static int stream_component_open(MovieState *movState, int stream_index) -{ - AVFormatContext *pFormatCtx = movState->pFormatCtx; - AVCodecContext *codecCtx; - AVCodec *codec; - - if(stream_index < 0 || (unsigned int)stream_index >= pFormatCtx->nb_streams) - return -1; - - /* Get a pointer to the codec context for the video stream, and open the - * associated codec */ - codecCtx = pFormatCtx->streams[stream_index]->codec; - - codec = avcodec_find_decoder(codecCtx->codec_id); - if(!codec || avcodec_open2(codecCtx, codec, NULL) < 0) - { - fprintf(stderr, "Unsupported codec!\n"); - return -1; - } - - /* Initialize and start the media type handler */ - switch(codecCtx->codec_type) - { - case AVMEDIA_TYPE_AUDIO: - movState->audioStream = stream_index; - movState->audio.st = pFormatCtx->streams[stream_index]; - - /* Averaging filter for audio sync */ - movState->audio.diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); - /* Correct audio only if larger error than this */ - movState->audio.diff_threshold = 2.0 * 0.050/* 50 ms */; - - memset(&movState->audio.pkt, 0, sizeof(movState->audio.pkt)); - if(althrd_create(&movState->audio.thread, audio_thread, movState) != althrd_success) - { - movState->audioStream = -1; - movState->audio.st = NULL; - } - break; - - case AVMEDIA_TYPE_VIDEO: - movState->videoStream = stream_index; - movState->video.st = pFormatCtx->streams[stream_index]; - - movState->video.current_pts_time = av_gettime(); - movState->video.frame_timer = (double)movState->video.current_pts_time / - 1000000.0; - movState->video.frame_last_delay = 40e-3; - - if(althrd_create(&movState->video.thread, video_thread, movState) != althrd_success) - { - movState->videoStream = -1; - movState->video.st = NULL; - } - break; - - default: - break; - } - - return 0; -} - -static int decode_interrupt_cb(void *ctx) -{ - return ((MovieState*)ctx)->quit; -} - -int decode_thread(void *arg) -{ - MovieState *movState = (MovieState *)arg; - AVFormatContext *fmtCtx = movState->pFormatCtx; - AVPacket *packet = (AVPacket[1]){}; - int video_index = -1; - int audio_index = -1; - - movState->videoStream = -1; - movState->audioStream = -1; - - /* Dump information about file onto standard error */ - av_dump_format(fmtCtx, 0, movState->filename, 0); - - /* Find the first video and audio streams */ - for(unsigned int i = 0;i < fmtCtx->nb_streams;i++) - { - if(fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) - video_index = i; - else if(fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) - audio_index = i; - } - movState->external_clock_base = av_gettime(); - if(audio_index >= 0) - stream_component_open(movState, audio_index); - if(video_index >= 0) - stream_component_open(movState, video_index); - - if(movState->videoStream < 0 && movState->audioStream < 0) - { - fprintf(stderr, "%s: could not open codecs\n", movState->filename); - goto fail; - } - - /* Main packet handling loop */ - while(!movState->quit) - { - if(movState->seek_req) - { - int64_t seek_target = movState->seek_pos; - int stream_index= -1; - - /* Prefer seeking on the video stream. */ - if(movState->videoStream >= 0) - stream_index = movState->videoStream; - else if(movState->audioStream >= 0) - stream_index = movState->audioStream; - - /* Get a seek timestamp for the appropriate stream. */ - int64_t timestamp = seek_target; - if(stream_index >= 0) - timestamp = av_rescale_q(seek_target, AV_TIME_BASE_Q, fmtCtx->streams[stream_index]->time_base); - - if(av_seek_frame(movState->pFormatCtx, stream_index, timestamp, 0) < 0) - fprintf(stderr, "%s: error while seeking\n", movState->pFormatCtx->filename); - else - { - /* Seek successful, clear the packet queues and send a special - * 'flush' packet with the new stream clock time. */ - if(movState->audioStream >= 0) - { - packet_queue_clear(&movState->audio.q); - flush_pkt.pts = av_rescale_q(seek_target, AV_TIME_BASE_Q, - fmtCtx->streams[movState->audioStream]->time_base - ); - packet_queue_put(&movState->audio.q, &flush_pkt); - } - if(movState->videoStream >= 0) - { - packet_queue_clear(&movState->video.q); - flush_pkt.pts = av_rescale_q(seek_target, AV_TIME_BASE_Q, - fmtCtx->streams[movState->videoStream]->time_base - ); - packet_queue_put(&movState->video.q, &flush_pkt); - } - movState->external_clock_base = av_gettime() - seek_target; - } - movState->seek_req = false; - } - - if(movState->audio.q.size >= MAX_AUDIOQ_SIZE || - movState->video.q.size >= MAX_VIDEOQ_SIZE) - { - SDL_Delay(10); - continue; - } - - if(av_read_frame(movState->pFormatCtx, packet) < 0) - { - packet_queue_flush(&movState->video.q); - packet_queue_flush(&movState->audio.q); - break; - } - - /* Place the packet in the queue it's meant for, or discard it. */ - if(packet->stream_index == movState->videoStream) - packet_queue_put(&movState->video.q, packet); - else if(packet->stream_index == movState->audioStream) - packet_queue_put(&movState->audio.q, packet); - else - av_free_packet(packet); - } - - /* all done - wait for it */ - while(!movState->quit) - { - if(movState->audio.q.nb_packets == 0 && movState->video.q.nb_packets == 0) - break; - SDL_Delay(100); - } - -fail: - movState->quit = true; - packet_queue_flush(&movState->video.q); - packet_queue_flush(&movState->audio.q); - - if(movState->videoStream >= 0) - althrd_join(movState->video.thread, NULL); - if(movState->audioStream >= 0) - althrd_join(movState->audio.thread, NULL); - - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_QUIT_EVENT, .data1=movState} }); - - return 0; -} - - -static void stream_seek(MovieState *movState, double incr) -{ - if(!movState->seek_req) - { - double newtime = get_master_clock(movState)+incr; - if(newtime <= 0.0) movState->seek_pos = 0; - else movState->seek_pos = (int64_t)(newtime * AV_TIME_BASE); - movState->seek_req = true; - } -} - -int main(int argc, char *argv[]) -{ - SDL_Event event; - MovieState *movState; - bool first_update = true; - SDL_Window *screen; - SDL_Renderer *renderer; - ALCdevice *device; - ALCcontext *context; - int fileidx; - - if(argc < 2) - { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - /* Register all formats and codecs */ - av_register_all(); - /* Initialize networking protocols */ - avformat_network_init(); - - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) - { - fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); - return 1; - } - - /* Make a window to put our video */ - screen = SDL_CreateWindow("alffplay", 0, 0, 640, 480, SDL_WINDOW_RESIZABLE); - if(!screen) - { - fprintf(stderr, "SDL: could not set video mode - exiting\n"); - return 1; - } - /* Make a renderer to handle the texture image surface and rendering. */ - renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); - if(renderer) - { - SDL_RendererInfo rinf; - bool ok = false; - - /* Make sure the renderer supports YV12 textures. If not, fallback to a - * software renderer. */ - if(SDL_GetRendererInfo(renderer, &rinf) == 0) - { - for(Uint32 i = 0;!ok && i < rinf.num_texture_formats;i++) - ok = (rinf.texture_formats[i] == SDL_PIXELFORMAT_YV12); - } - if(!ok) - { - fprintf(stderr, "YV12 pixelformat textures not supported on renderer %s\n", rinf.name); - SDL_DestroyRenderer(renderer); - renderer = NULL; - } - } - if(!renderer) - renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_SOFTWARE); - if(!renderer) - { - fprintf(stderr, "SDL: could not create renderer - exiting\n"); - return 1; - } - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, NULL); - SDL_RenderPresent(renderer); - - /* Open an audio device */ - fileidx = 1; - device = NULL; - if(argc > 3 && strcmp(argv[1], "-device") == 0) - { - fileidx = 3; - device = alcOpenDevice(argv[2]); - if(!device) - fprintf(stderr, "OpenAL: could not open \"%s\" - trying default\n", argv[2]); - } - if(!device) - device = alcOpenDevice(NULL); - if(!device) - { - fprintf(stderr, "OpenAL: could not open device - exiting\n"); - return 1; - } - context = alcCreateContext(device, NULL); - if(!context) - { - fprintf(stderr, "OpenAL: could not create context - exiting\n"); - return 1; - } - if(alcMakeContextCurrent(context) == ALC_FALSE) - { - fprintf(stderr, "OpenAL: could not make context current - exiting\n"); - return 1; - } - - if(!alIsExtensionPresent("AL_SOFT_source_length")) - { - fprintf(stderr, "Required AL_SOFT_source_length not supported - exiting\n"); - return 1; - } - - if(!alIsExtensionPresent("AL_SOFT_direct_channels")) - fprintf(stderr, "AL_SOFT_direct_channels not supported.\n"); - else - has_direct_out = true; - - if(!alIsExtensionPresent("AL_SOFT_source_latency")) - fprintf(stderr, "AL_SOFT_source_latency not supported, audio may be a bit laggy.\n"); - else - { - alGetSourcedvSOFT = alGetProcAddress("alGetSourcedvSOFT"); - has_latency_check = true; - } - - - movState = av_mallocz(sizeof(MovieState)); - - av_strlcpy(movState->filename, argv[fileidx], sizeof(movState->filename)); - - packet_queue_init(&movState->audio.q); - packet_queue_init(&movState->video.q); - - almtx_init(&movState->video.pictq_mutex, almtx_plain); - alcnd_init(&movState->video.pictq_cond); - almtx_init(&movState->audio.src_mutex, almtx_recursive); - - movState->av_sync_type = DEFAULT_AV_SYNC_TYPE; - - movState->pFormatCtx = avformat_alloc_context(); - movState->pFormatCtx->interrupt_callback = (AVIOInterruptCB){.callback=decode_interrupt_cb, .opaque=movState}; - - if(avio_open2(&movState->pFormatCtx->pb, movState->filename, AVIO_FLAG_READ, - &movState->pFormatCtx->interrupt_callback, NULL)) - { - fprintf(stderr, "Failed to open %s\n", movState->filename); - return 1; - } - - /* Open movie file */ - if(avformat_open_input(&movState->pFormatCtx, movState->filename, NULL, NULL) != 0) - { - fprintf(stderr, "Failed to open %s\n", movState->filename); - return 1; - } - - /* Retrieve stream information */ - if(avformat_find_stream_info(movState->pFormatCtx, NULL) < 0) - { - fprintf(stderr, "%s: failed to find stream info\n", movState->filename); - return 1; - } - - schedule_refresh(movState, 40); - - - if(althrd_create(&movState->parse_thread, decode_thread, movState) != althrd_success) - { - fprintf(stderr, "Failed to create parse thread!\n"); - return 1; - } - while(SDL_WaitEvent(&event) == 1) - { - switch(event.type) - { - case SDL_KEYDOWN: - switch(event.key.keysym.sym) - { - case SDLK_ESCAPE: - movState->quit = true; - break; - - case SDLK_LEFT: - stream_seek(movState, -10.0); - break; - case SDLK_RIGHT: - stream_seek(movState, 10.0); - break; - case SDLK_UP: - stream_seek(movState, 30.0); - break; - case SDLK_DOWN: - stream_seek(movState, -30.0); - break; - - case SDLK_d: - movState->direct_req = true; - break; - - default: - break; - } - break; - - case SDL_WINDOWEVENT: - switch(event.window.event) - { - case SDL_WINDOWEVENT_RESIZED: - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, NULL); - break; - - default: - break; - } - break; - - case SDL_QUIT: - movState->quit = true; - break; - - case FF_UPDATE_EVENT: - update_picture(event.user.data1, &first_update, screen, renderer); - break; - - case FF_REFRESH_EVENT: - video_refresh_timer(event.user.data1, screen, renderer); - break; - - case FF_QUIT_EVENT: - althrd_join(movState->parse_thread, NULL); - - avformat_close_input(&movState->pFormatCtx); - - almtx_destroy(&movState->audio.src_mutex); - almtx_destroy(&movState->video.pictq_mutex); - alcnd_destroy(&movState->video.pictq_cond); - packet_queue_deinit(&movState->video.q); - packet_queue_deinit(&movState->audio.q); - - alcMakeContextCurrent(NULL); - alcDestroyContext(context); - alcCloseDevice(device); - - SDL_Quit(); - exit(0); - - default: - break; - } - } - - fprintf(stderr, "SDL_WaitEvent error - %s\n", SDL_GetError()); - return 1; -} diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp new file mode 100644 index 00000000..00d51673 --- /dev/null +++ b/examples/alffplay.cpp @@ -0,0 +1,1546 @@ +/* + * An example showing how to play a stream sync'd to video, using ffmpeg. + * + * Requires C++11. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +#include "libavformat/avio.h" +#include "libavutil/time.h" +#include "libavutil/pixfmt.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libswscale/swscale.h" +#include "libswresample/swresample.h" +} + +#include "SDL.h" + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + +namespace +{ + +static const std::string AppName("alffplay"); + +static bool has_latency_check = false; +static LPALGETSOURCEDVSOFT alGetSourcedvSOFT; + +#define AUDIO_BUFFER_TIME 100 /* In milliseconds, per-buffer */ +#define AUDIO_BUFFER_QUEUE_SIZE 8 /* Number of buffers to queue */ +#define MAX_QUEUE_SIZE (15 * 1024 * 1024) /* Bytes of compressed data to keep queued */ +#define AV_SYNC_THRESHOLD 0.01 +#define AV_NOSYNC_THRESHOLD 10.0 +#define SAMPLE_CORRECTION_MAX_DIFF 0.05 +#define AUDIO_DIFF_AVG_NB 20 +#define VIDEO_PICTURE_QUEUE_SIZE 16 + +enum { + FF_UPDATE_EVENT = SDL_USEREVENT, + FF_REFRESH_EVENT, + FF_MOVIE_DONE_EVENT +}; + +enum { + AV_SYNC_AUDIO_MASTER, + AV_SYNC_VIDEO_MASTER, + AV_SYNC_EXTERNAL_MASTER, + + DEFAULT_AV_SYNC_TYPE = AV_SYNC_EXTERNAL_MASTER +}; + + +struct PacketQueue { + std::deque mPackets; + std::atomic mTotalSize; + std::atomic mFinished; + std::mutex mMutex; + std::condition_variable mCond; + + PacketQueue() : mTotalSize(0), mFinished(false) + { } + ~PacketQueue() + { clear(); } + + int put(const AVPacket *pkt); + int peek(AVPacket *pkt, std::atomic &quit_var); + void pop(); + + void clear(); + void finish(); +}; + + +struct MovieState; + +struct AudioState { + MovieState *mMovie; + + AVStream *mStream; + AVCodecContext *mCodecCtx; + + PacketQueue mQueue; + + /* Used for clock difference average computation */ + struct { + std::atomic Clocks; /* In microseconds */ + double Accum; + double AvgCoeff; + double Threshold; + int AvgCount; + } mDiff; + + /* Time (in seconds) of the next sample to be buffered */ + double mCurrentPts; + + /* Decompressed sample frame, and swresample context for conversion */ + AVFrame *mDecodedFrame; + struct SwrContext *mSwresCtx; + + /* Conversion format, for what gets fed to Alure */ + int mDstChanLayout; + enum AVSampleFormat mDstSampleFmt; + + /* Storage of converted samples */ + uint8_t *mSamples; + int mSamplesLen; /* In samples */ + int mSamplesPos; + int mSamplesMax; + + /* OpenAL format */ + ALenum mFormat; + ALsizei mFrameSize; + + std::recursive_mutex mSrcMutex; + ALuint mSource; + ALuint mBuffers[AUDIO_BUFFER_QUEUE_SIZE]; + ALsizei mBufferIdx; + + AudioState(MovieState *movie) + : mMovie(movie), mStream(nullptr), mCodecCtx(nullptr) + , mDiff{{0}, 0.0, 0.0, 0.0, 0}, mCurrentPts(0.0), mDecodedFrame(nullptr) + , mSwresCtx(nullptr), mDstChanLayout(0), mDstSampleFmt(AV_SAMPLE_FMT_NONE) + , mSamples(nullptr), mSamplesLen(0), mSamplesPos(0), mSamplesMax(0) + , mFormat(AL_NONE), mFrameSize(0), mSource(0), mBufferIdx(0) + { + for(auto &buf : mBuffers) + buf = 0; + } + ~AudioState() + { + if(mSource) + alDeleteSources(1, &mSource); + alDeleteBuffers(AUDIO_BUFFER_QUEUE_SIZE, mBuffers); + + av_frame_free(&mDecodedFrame); + swr_free(&mSwresCtx); + + av_freep(&mSamples); + + avcodec_free_context(&mCodecCtx); + } + + double getClock(); + + int getSync(); + int decodeFrame(); + int readAudio(uint8_t *samples, int length); + + int handler(); +}; + +struct VideoState { + MovieState *mMovie; + + AVStream *mStream; + AVCodecContext *mCodecCtx; + + PacketQueue mQueue; + + double mClock; + double mFrameTimer; + double mFrameLastPts; + double mFrameLastDelay; + double mCurrentPts; + /* time (av_gettime) at which we updated mCurrentPts - used to have running video pts */ + int64_t mCurrentPtsTime; + + /* Decompressed video frame, and swscale context for conversion */ + AVFrame *mDecodedFrame; + struct SwsContext *mSwscaleCtx; + + struct Picture { + SDL_Texture *mImage; + int mWidth, mHeight; /* Logical image size (actual size may be larger) */ + std::atomic mUpdated; + double mPts; + + Picture() + : mImage(nullptr), mWidth(0), mHeight(0), mUpdated(false), mPts(0.0) + { } + ~Picture() + { + if(mImage) + SDL_DestroyTexture(mImage); + mImage = nullptr; + } + }; + std::array mPictQ; + size_t mPictQSize, mPictQRead, mPictQWrite; + std::mutex mPictQMutex; + std::condition_variable mPictQCond; + bool mFirstUpdate; + std::atomic mEOS; + std::atomic mFinalUpdate; + + VideoState(MovieState *movie) + : mMovie(movie), mStream(nullptr), mCodecCtx(nullptr), mClock(0.0) + , mFrameTimer(0.0), mFrameLastPts(0.0), mFrameLastDelay(0.0) + , mCurrentPts(0.0), mCurrentPtsTime(0), mDecodedFrame(nullptr) + , mSwscaleCtx(nullptr), mPictQSize(0), mPictQRead(0), mPictQWrite(0) + , mFirstUpdate(true), mEOS(false), mFinalUpdate(false) + { } + ~VideoState() + { + sws_freeContext(mSwscaleCtx); + mSwscaleCtx = nullptr; + av_frame_free(&mDecodedFrame); + avcodec_free_context(&mCodecCtx); + } + + double getClock(); + + static Uint32 SDLCALL sdl_refresh_timer_cb(Uint32 interval, void *opaque); + void schedRefresh(int delay); + void display(SDL_Window *screen, SDL_Renderer *renderer); + void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer); + void updatePicture(SDL_Window *screen, SDL_Renderer *renderer); + int queuePicture(double pts); + double synchronize(double pts); + int handler(); +}; + +struct MovieState { + AVFormatContext *mFormatCtx; + int mVideoStream, mAudioStream; + + int mAVSyncType; + + int64_t mExternalClockBase; + + std::atomic mQuit; + + AudioState mAudio; + VideoState mVideo; + + std::thread mParseThread; + std::thread mAudioThread; + std::thread mVideoThread; + + std::string mFilename; + + MovieState(std::string fname) + : mFormatCtx(nullptr), mVideoStream(0), mAudioStream(0) + , mAVSyncType(DEFAULT_AV_SYNC_TYPE), mExternalClockBase(0), mQuit(false) + , mAudio(this), mVideo(this), mFilename(std::move(fname)) + { } + ~MovieState() + { + mQuit = true; + if(mParseThread.joinable()) + mParseThread.join(); + avformat_close_input(&mFormatCtx); + } + + static int decode_interrupt_cb(void *ctx); + bool prepare(); + void setTitle(SDL_Window *window); + + double getClock(); + + double getMasterClock(); + + int streamComponentOpen(int stream_index); + int parse_handler(); +}; + + +int PacketQueue::put(const AVPacket *pkt) +{ + std::unique_lock lock(mMutex); + mPackets.push_back(AVPacket{}); + if(av_packet_ref(&mPackets.back(), pkt) != 0) + { + mPackets.pop_back(); + return -1; + } + mTotalSize += mPackets.back().size; + lock.unlock(); + + mCond.notify_one(); + return 0; +} + +int PacketQueue::peek(AVPacket *pkt, std::atomic &quit_var) +{ + std::unique_lock lock(mMutex); + while(!quit_var.load()) + { + if(!mPackets.empty()) + { + if(av_packet_ref(pkt, &mPackets.front()) != 0) + return -1; + return 1; + } + + if(mFinished.load()) + return 0; + mCond.wait(lock); + } + return -1; +} + +void PacketQueue::pop() +{ + std::unique_lock lock(mMutex); + AVPacket *pkt = &mPackets.front(); + mTotalSize -= pkt->size; + av_packet_unref(pkt); + mPackets.pop_front(); +} + +void PacketQueue::clear() +{ + std::unique_lock lock(mMutex); + std::for_each(mPackets.begin(), mPackets.end(), + [](AVPacket &pkt) { av_packet_unref(&pkt); } + ); + mPackets.clear(); + mTotalSize = 0; +} +void PacketQueue::finish() +{ + std::unique_lock lock(mMutex); + mFinished = true; + lock.unlock(); + mCond.notify_all(); +} + + +double AudioState::getClock() +{ + double pts; + + std::unique_lock lock(mSrcMutex); + /* The audio clock is the timestamp of the sample currently being heard. + * It's based on 4 components: + * 1 - The timestamp of the next sample to buffer (state->current_pts) + * 2 - The length of the source's buffer queue + * 3 - The offset OpenAL is currently at in the source (the first value + * from AL_SEC_OFFSET_LATENCY_SOFT) + * 4 - The latency between OpenAL and the DAC (the second value from + * AL_SEC_OFFSET_LATENCY_SOFT) + * + * Subtracting the length of the source queue from the next sample's + * timestamp gives the timestamp of the sample at start of the source + * queue. Adding the source offset to that results in the timestamp for + * OpenAL's current position, and subtracting the source latency from that + * gives the timestamp of the sample currently at the DAC. + */ + pts = mCurrentPts; + if(mSource) + { + ALdouble offset[2]; + ALint queue_size; + ALint status; + + /* NOTE: The source state must be checked last, in case an underrun + * occurs and the source stops between retrieving the offset+latency + * and getting the state. */ + if(has_latency_check) + { + alGetSourcedvSOFT(mSource, AL_SEC_OFFSET_LATENCY_SOFT, offset); + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queue_size); + } + else + { + ALint ioffset; + alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset); + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queue_size); + offset[0] = (double)ioffset / (double)mCodecCtx->sample_rate; + offset[1] = 0.0f; + } + alGetSourcei(mSource, AL_SOURCE_STATE, &status); + + /* If the source is AL_STOPPED, then there was an underrun and all + * buffers are processed, so ignore the source queue. The audio thread + * will put the source into an AL_INITIAL state and clear the queue + * when it starts recovery. */ + if(status != AL_STOPPED) + pts -= queue_size*((double)AUDIO_BUFFER_TIME/1000.0) - offset[0]; + if(status == AL_PLAYING) + pts -= offset[1]; + } + lock.unlock(); + + return std::max(pts, 0.0); +} + +int AudioState::getSync() +{ + double diff, avg_diff, ref_clock; + + if(mMovie->mAVSyncType == AV_SYNC_AUDIO_MASTER) + return 0; + + ref_clock = mMovie->getMasterClock(); + diff = ref_clock - getClock(); + + if(!(fabs(diff) < AV_NOSYNC_THRESHOLD)) + { + /* Difference is TOO big; reset diff stuff */ + mDiff.Accum = 0.0; + return 0; + } + + /* Accumulate the diffs */ + mDiff.Accum = mDiff.Accum*mDiff.AvgCoeff + diff; + avg_diff = mDiff.Accum*(1.0 - mDiff.AvgCoeff); + if(fabs(avg_diff) < mDiff.Threshold) + return 0; + + /* Constrain the per-update difference to avoid exceedingly large skips */ + if(!(diff <= SAMPLE_CORRECTION_MAX_DIFF)) + diff = SAMPLE_CORRECTION_MAX_DIFF; + else if(!(diff >= -SAMPLE_CORRECTION_MAX_DIFF)) + diff = -SAMPLE_CORRECTION_MAX_DIFF; + return (int)(diff*mCodecCtx->sample_rate); +} + +int AudioState::decodeFrame() +{ + while(!mMovie->mQuit.load()) + { + while(!mMovie->mQuit.load()) + { + /* Get the next packet */ + AVPacket pkt{}; + if(mQueue.peek(&pkt, mMovie->mQuit) <= 0) + return -1; + + int ret = avcodec_send_packet(mCodecCtx, &pkt); + if(ret != AVERROR(EAGAIN)) + { + if(ret < 0) + std::cerr<< "Failed to send encoded packet: 0x"<nb_samples <= 0) + { + av_frame_unref(mDecodedFrame); + continue; + } + + /* If provided, update w/ pts */ + int64_t pts = av_frame_get_best_effort_timestamp(mDecodedFrame); + if(pts != AV_NOPTS_VALUE) + mCurrentPts = av_q2d(mStream->time_base)*pts; + + if(mDecodedFrame->nb_samples > mSamplesMax) + { + av_freep(&mSamples); + av_samples_alloc( + &mSamples, nullptr, mCodecCtx->channels, + mDecodedFrame->nb_samples, mDstSampleFmt, 0 + ); + mSamplesMax = mDecodedFrame->nb_samples; + } + /* Return the amount of sample frames converted */ + int data_size = swr_convert(mSwresCtx, &mSamples, mDecodedFrame->nb_samples, + (const uint8_t**)mDecodedFrame->data, mDecodedFrame->nb_samples + ); + + av_frame_unref(mDecodedFrame); + return data_size; + } + + return 0; +} + +/* Duplicates the sample at in to out, count times. The frame size is a + * multiple of the template type size. + */ +template +static void sample_dup(uint8_t *out, const uint8_t *in, int count, int frame_size) +{ + const T *sample = reinterpret_cast(in); + T *dst = reinterpret_cast(out); + if(frame_size == sizeof(T)) + std::fill_n(dst, count, *sample); + else + { + /* NOTE: frame_size is a multiple of sizeof(T). */ + int type_mult = frame_size / sizeof(T); + int i = 0; + std::generate_n(dst, count*type_mult, + [sample,type_mult,&i]() -> T + { + T ret = sample[i]; + i = (i+1)%type_mult; + return ret; + } + ); + } +} + + +int AudioState::readAudio(uint8_t *samples, int length) +{ + int sample_skip = getSync(); + int audio_size = 0; + + /* Read the next chunk of data, refill the buffer, and queue it + * on the source */ + length /= mFrameSize; + while(audio_size < length) + { + if(mSamplesLen <= 0 || mSamplesPos >= mSamplesLen) + { + int frame_len = decodeFrame(); + if(frame_len <= 0) break; + + mSamplesLen = frame_len; + mSamplesPos = std::min(mSamplesLen, sample_skip); + sample_skip -= mSamplesPos; + + mCurrentPts += (double)mSamplesPos / (double)mCodecCtx->sample_rate; + continue; + } + + int rem = length - audio_size; + if(mSamplesPos >= 0) + { + int len = mSamplesLen - mSamplesPos; + if(rem > len) rem = len; + memcpy(samples, mSamples + mSamplesPos*mFrameSize, rem*mFrameSize); + } + else + { + rem = std::min(rem, -mSamplesPos); + + /* Add samples by copying the first sample */ + if((mFrameSize&7) == 0) + sample_dup(samples, mSamples, rem, mFrameSize); + else if((mFrameSize&3) == 0) + sample_dup(samples, mSamples, rem, mFrameSize); + else if((mFrameSize&1) == 0) + sample_dup(samples, mSamples, rem, mFrameSize); + else + sample_dup(samples, mSamples, rem, mFrameSize); + } + + mSamplesPos += rem; + mCurrentPts += (double)rem / mCodecCtx->sample_rate; + samples += rem*mFrameSize; + audio_size += rem; + } + + if(audio_size < length && audio_size > 0) + { + int rem = length - audio_size; + std::fill_n(samples, rem*mFrameSize, + (mDstSampleFmt == AV_SAMPLE_FMT_U8) ? 0x80 : 0x00); + mCurrentPts += (double)rem / mCodecCtx->sample_rate; + audio_size += rem; + } + + return audio_size * mFrameSize; +} + + +int AudioState::handler() +{ + std::unique_lock lock(mSrcMutex); + ALenum fmt; + + /* Find a suitable format for Alure. */ + mDstChanLayout = 0; + if(mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8 || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8P) + { + mDstSampleFmt = AV_SAMPLE_FMT_U8; + mFrameSize = 1; + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 8; + mFormat = fmt; + } + if((mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1 || + mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 6; + mFormat = fmt; + } + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 1; + mFormat = AL_FORMAT_MONO8; + } + if(!mDstChanLayout) + { + mDstChanLayout = AV_CH_LAYOUT_STEREO; + mFrameSize *= 2; + mFormat = AL_FORMAT_STEREO8; + } + } + if((mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLTP) && + alIsExtensionPresent("AL_EXT_FLOAT32")) + { + mDstSampleFmt = AV_SAMPLE_FMT_FLT; + mFrameSize = 4; + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 8; + mFormat = fmt; + } + if((mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1 || + mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 6; + mFormat = fmt; + } + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 1; + mFormat = AL_FORMAT_MONO_FLOAT32; + } + if(!mDstChanLayout) + { + mDstChanLayout = AV_CH_LAYOUT_STEREO; + mFrameSize *= 2; + mFormat = AL_FORMAT_STEREO_FLOAT32; + } + } + if(!mDstChanLayout) + { + mDstSampleFmt = AV_SAMPLE_FMT_S16; + mFrameSize = 2; + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 8; + mFormat = fmt; + } + if((mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1 || + mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 6; + mFormat = fmt; + } + if(mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + { + mDstChanLayout = mCodecCtx->channel_layout; + mFrameSize *= 1; + mFormat = AL_FORMAT_MONO16; + } + if(!mDstChanLayout) + { + mDstChanLayout = AV_CH_LAYOUT_STEREO; + mFrameSize *= 2; + mFormat = AL_FORMAT_STEREO16; + } + } + ALsizei buffer_len = mCodecCtx->sample_rate * AUDIO_BUFFER_TIME / 1000 * + mFrameSize; + void *samples = av_malloc(buffer_len); + + mSamples = NULL; + mSamplesMax = 0; + mSamplesPos = 0; + mSamplesLen = 0; + + if(!(mDecodedFrame=av_frame_alloc())) + { + std::cerr<< "Failed to allocate audio frame" <sample_rate, + mCodecCtx->channel_layout ? mCodecCtx->channel_layout : + (uint64_t)av_get_default_channel_layout(mCodecCtx->channels), + mCodecCtx->sample_fmt, mCodecCtx->sample_rate, + 0, nullptr + ); + if(!mSwresCtx || swr_init(mSwresCtx) != 0) + { + std::cerr<< "Failed to initialize audio converter" <mQuit.load()) + { + /* First remove any processed buffers. */ + ALint processed; + alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); + if(processed > 0) + { + std::array tmp; + alSourceUnqueueBuffers(mSource, processed, tmp.data()); + } + + /* Refill the buffer queue. */ + ALint queued; + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + while(queued < AUDIO_BUFFER_QUEUE_SIZE) + { + int audio_size; + + /* Read the next chunk of data, fill the buffer, and queue it on + * the source */ + audio_size = readAudio(reinterpret_cast(samples), buffer_len); + if(audio_size <= 0) break; + + ALuint bufid = mBuffers[mBufferIdx++]; + mBufferIdx %= AUDIO_BUFFER_QUEUE_SIZE; + + alBufferData(bufid, mFormat, samples, audio_size, mCodecCtx->sample_rate); + alSourceQueueBuffers(mSource, 1, &bufid); + queued++; + } + if(queued == 0) + break; + + /* Check that the source is playing. */ + ALint state; + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state == AL_STOPPED) + { + /* AL_STOPPED means there was an underrun. Rewind the source to get + * it back into an AL_INITIAL state. + */ + alSourceRewind(mSource); + continue; + } + + lock.unlock(); + + /* (re)start the source if needed, and wait for a buffer to finish */ + if(state != AL_PLAYING && state != AL_PAUSED) + alSourcePlay(mSource); + SDL_Delay(AUDIO_BUFFER_TIME / 3); + + lock.lock(); + } + +finish: + alSourceRewind(mSource); + alSourcei(mSource, AL_BUFFER, 0); + + av_frame_free(&mDecodedFrame); + swr_free(&mSwresCtx); + + av_freep(&mSamples); + + return 0; +} + + +double VideoState::getClock() +{ + double delta = (av_gettime() - mCurrentPtsTime) / 1000000.0; + return mCurrentPts + delta; +} + +Uint32 SDLCALL VideoState::sdl_refresh_timer_cb(Uint32 /*interval*/, void *opaque) +{ + SDL_Event evt{}; + evt.user.type = FF_REFRESH_EVENT; + evt.user.data1 = opaque; + SDL_PushEvent(&evt); + return 0; /* 0 means stop timer */ +} + +/* Schedules an FF_REFRESH_EVENT event to occur in 'delay' ms. */ +void VideoState::schedRefresh(int delay) +{ + SDL_AddTimer(delay, sdl_refresh_timer_cb, this); +} + +/* Called by VideoState::refreshTimer to display the next video frame. */ +void VideoState::display(SDL_Window *screen, SDL_Renderer *renderer) +{ + Picture *vp = &mPictQ[mPictQRead]; + + if(!vp->mImage) + return; + + float aspect_ratio; + int win_w, win_h; + int w, h, x, y; + + if(mCodecCtx->sample_aspect_ratio.num == 0) + aspect_ratio = 0.0f; + else + { + aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio) * mCodecCtx->width / + mCodecCtx->height; + } + if(aspect_ratio <= 0.0f) + aspect_ratio = (float)mCodecCtx->width / (float)mCodecCtx->height; + + SDL_GetWindowSize(screen, &win_w, &win_h); + h = win_h; + w = ((int)rint(h * aspect_ratio) + 3) & ~3; + if(w > win_w) + { + w = win_w; + h = ((int)rint(w / aspect_ratio) + 3) & ~3; + } + x = (win_w - w) / 2; + y = (win_h - h) / 2; + + SDL_Rect src_rect{ 0, 0, vp->mWidth, vp->mHeight }; + SDL_Rect dst_rect{ x, y, w, h }; + SDL_RenderCopy(renderer, vp->mImage, &src_rect, &dst_rect); + SDL_RenderPresent(renderer); +} + +/* FF_REFRESH_EVENT handler called on the main thread where the SDL_Renderer + * was created. It handles the display of the next decoded video frame (if not + * falling behind), and sets up the timer for the following video frame. + */ +void VideoState::refreshTimer(SDL_Window *screen, SDL_Renderer *renderer) +{ + if(!mStream) + { + if(mEOS) + { + mFinalUpdate = true; + std::unique_lock(mPictQMutex).unlock(); + mPictQCond.notify_all(); + return; + } + schedRefresh(100); + return; + } + + std::unique_lock lock(mPictQMutex); +retry: + if(mPictQSize == 0) + { + if(mEOS) + mFinalUpdate = true; + else + schedRefresh(1); + lock.unlock(); + mPictQCond.notify_all(); + return; + } + + Picture *vp = &mPictQ[mPictQRead]; + mCurrentPts = vp->mPts; + mCurrentPtsTime = av_gettime(); + + /* Get delay using the frame pts and the pts from last frame. */ + double delay = vp->mPts - mFrameLastPts; + if(delay <= 0 || delay >= 1.0) + { + /* If incorrect delay, use previous one. */ + delay = mFrameLastDelay; + } + /* Save for next frame. */ + mFrameLastDelay = delay; + mFrameLastPts = vp->mPts; + + /* Update delay to sync to clock if not master source. */ + if(mMovie->mAVSyncType != AV_SYNC_VIDEO_MASTER) + { + double ref_clock = mMovie->getMasterClock(); + double diff = vp->mPts - ref_clock; + + /* Skip or repeat the frame. Take delay into account. */ + double sync_threshold = std::min(delay, AV_SYNC_THRESHOLD); + if(fabs(diff) < AV_NOSYNC_THRESHOLD) + { + if(diff <= -sync_threshold) + delay = 0; + else if(diff >= sync_threshold) + delay *= 2.0; + } + } + + mFrameTimer += delay; + /* Compute the REAL delay. */ + double actual_delay = mFrameTimer - (av_gettime() / 1000000.0); + if(!(actual_delay >= 0.010)) + { + /* We don't have time to handle this picture, just skip to the next one. */ + mPictQRead = (mPictQRead+1)%mPictQ.size(); + mPictQSize--; + goto retry; + } + schedRefresh((int)(actual_delay*1000.0 + 0.5)); + + /* Show the picture! */ + display(screen, renderer); + + /* Update queue for next picture. */ + mPictQRead = (mPictQRead+1)%mPictQ.size(); + mPictQSize--; + lock.unlock(); + mPictQCond.notify_all(); +} + +/* FF_UPDATE_EVENT handler, updates the picture's texture. It's called on the + * main thread where the renderer was created. + */ +void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer) +{ + Picture *vp = &mPictQ[mPictQWrite]; + bool fmt_updated = false; + + /* allocate or resize the buffer! */ + if(!vp->mImage || vp->mWidth != mCodecCtx->width || vp->mHeight != mCodecCtx->height) + { + fmt_updated = true; + if(vp->mImage) + SDL_DestroyTexture(vp->mImage); + vp->mImage = SDL_CreateTexture( + renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, + mCodecCtx->coded_width, mCodecCtx->coded_height + ); + if(!vp->mImage) + std::cerr<< "Failed to create YV12 texture!" <mWidth = mCodecCtx->width; + vp->mHeight = mCodecCtx->height; + + if(mFirstUpdate && vp->mWidth > 0 && vp->mHeight > 0) + { + /* For the first update, set the window size to the video size. */ + mFirstUpdate = false; + + int w = vp->mWidth; + int h = vp->mHeight; + if(mCodecCtx->sample_aspect_ratio.den != 0) + { + double aspect_ratio = av_q2d(mCodecCtx->sample_aspect_ratio); + if(aspect_ratio >= 1.0) + w = (int)(w*aspect_ratio + 0.5); + else if(aspect_ratio > 0.0) + h = (int)(h/aspect_ratio + 0.5); + } + SDL_SetWindowSize(screen, w, h); + } + } + + if(vp->mImage) + { + AVFrame *frame = mDecodedFrame; + void *pixels = nullptr; + int pitch = 0; + + if(mCodecCtx->pix_fmt == AV_PIX_FMT_YUV420P) + SDL_UpdateYUVTexture(vp->mImage, nullptr, + frame->data[0], frame->linesize[0], + frame->data[1], frame->linesize[1], + frame->data[2], frame->linesize[2] + ); + else if(SDL_LockTexture(vp->mImage, nullptr, &pixels, &pitch) != 0) + std::cerr<< "Failed to lock texture" <coded_width; + int coded_h = mCodecCtx->coded_height; + int w = mCodecCtx->width; + int h = mCodecCtx->height; + if(!mSwscaleCtx || fmt_updated) + { + sws_freeContext(mSwscaleCtx); + mSwscaleCtx = sws_getContext( + w, h, mCodecCtx->pix_fmt, + w, h, AV_PIX_FMT_YUV420P, 0, + nullptr, nullptr, nullptr + ); + } + + /* point pict at the queue */ + uint8_t *pict_data[3]; + pict_data[0] = reinterpret_cast(pixels); + pict_data[1] = pict_data[0] + coded_w*coded_h; + pict_data[2] = pict_data[1] + coded_w*coded_h/4; + + int pict_linesize[3]; + pict_linesize[0] = pitch; + pict_linesize[1] = pitch / 2; + pict_linesize[2] = pitch / 2; + + sws_scale(mSwscaleCtx, (const uint8_t**)frame->data, + frame->linesize, 0, h, pict_data, pict_linesize); + SDL_UnlockTexture(vp->mImage); + } + } + + std::unique_lock lock(mPictQMutex); + vp->mUpdated = true; + lock.unlock(); + mPictQCond.notify_one(); +} + +int VideoState::queuePicture(double pts) +{ + /* Wait until we have space for a new pic */ + std::unique_lock lock(mPictQMutex); + while(mPictQSize >= mPictQ.size() && !mMovie->mQuit.load()) + mPictQCond.wait(lock); + lock.unlock(); + + if(mMovie->mQuit.load()) + return -1; + + Picture *vp = &mPictQ[mPictQWrite]; + + /* We have to create/update the picture in the main thread */ + vp->mUpdated = false; + SDL_Event evt{}; + evt.user.type = FF_UPDATE_EVENT; + evt.user.data1 = this; + SDL_PushEvent(&evt); + + /* Wait until the picture is updated. */ + lock.lock(); + while(!vp->mUpdated && !mMovie->mQuit.load()) + mPictQCond.wait(lock); + if(mMovie->mQuit.load()) + return -1; + vp->mPts = pts; + + mPictQWrite = (mPictQWrite+1)%mPictQ.size(); + mPictQSize++; + lock.unlock(); + + return 0; +} + +double VideoState::synchronize(double pts) +{ + double frame_delay; + + if(pts == 0.0) /* if we aren't given a pts, set it to the clock */ + pts = mClock; + else /* if we have pts, set video clock to it */ + mClock = pts; + + /* update the video clock */ + frame_delay = av_q2d(mCodecCtx->time_base); + /* if we are repeating a frame, adjust clock accordingly */ + frame_delay += mDecodedFrame->repeat_pict * (frame_delay * 0.5); + mClock += frame_delay; + return pts; +} + +int VideoState::handler() +{ + mDecodedFrame = av_frame_alloc(); + while(!mMovie->mQuit) + { + while(!mMovie->mQuit) + { + AVPacket packet{}; + if(mQueue.peek(&packet, mMovie->mQuit) <= 0) + goto finish; + + int ret = avcodec_send_packet(mCodecCtx, &packet); + if(ret != AVERROR(EAGAIN)) + { + if(ret < 0) + std::cerr<< "Failed to send encoded packet: 0x"<time_base) * av_frame_get_best_effort_timestamp(mDecodedFrame) + ); + if(queuePicture(pts) < 0) + break; + av_frame_unref(mDecodedFrame); + } +finish: + mEOS = true; + av_frame_free(&mDecodedFrame); + + std::unique_lock lock(mPictQMutex); + if(mMovie->mQuit) + { + mPictQRead = 0; + mPictQWrite = 0; + mPictQSize = 0; + } + while(!mFinalUpdate) + mPictQCond.wait(lock); + + return 0; +} + + +int MovieState::decode_interrupt_cb(void *ctx) +{ + return reinterpret_cast(ctx)->mQuit; +} + +bool MovieState::prepare() +{ + mFormatCtx = avformat_alloc_context(); + mFormatCtx->interrupt_callback.callback = decode_interrupt_cb; + mFormatCtx->interrupt_callback.opaque = this; + if(avio_open2(&mFormatCtx->pb, mFilename.c_str(), AVIO_FLAG_READ, + &mFormatCtx->interrupt_callback, nullptr)) + { + std::cerr<< "Failed to open "<= mFormatCtx->nb_streams) + return -1; + + /* Get a pointer to the codec context for the stream, and open the + * associated codec. + */ + AVCodecContext *avctx = avcodec_alloc_context3(nullptr); + if(!avctx) return -1; + + if(avcodec_parameters_to_context(avctx, mFormatCtx->streams[stream_index]->codecpar)) + { + avcodec_free_context(&avctx); + return -1; + } + + AVCodec *codec = avcodec_find_decoder(avctx->codec_id); + if(!codec || avcodec_open2(avctx, codec, nullptr) < 0) + { + std::cerr<< "Unsupported codec: "<codec_id) + << " (0x"<codec_id<codec_type) + { + case AVMEDIA_TYPE_AUDIO: + mAudioStream = stream_index; + mAudio.mStream = mFormatCtx->streams[stream_index]; + mAudio.mCodecCtx = avctx; + + /* Averaging filter for audio sync */ + mAudio.mDiff.AvgCoeff = exp(log(0.01) / AUDIO_DIFF_AVG_NB); + /* Correct audio only if larger error than this */ + mAudio.mDiff.Threshold = 0.050/* 50 ms */; + + mAudioThread = std::thread(std::mem_fn(&AudioState::handler), &mAudio); + break; + + case AVMEDIA_TYPE_VIDEO: + mVideoStream = stream_index; + mVideo.mStream = mFormatCtx->streams[stream_index]; + mVideo.mCodecCtx = avctx; + + mVideo.mCurrentPtsTime = av_gettime(); + mVideo.mFrameTimer = (double)mVideo.mCurrentPtsTime / 1000000.0; + mVideo.mFrameLastDelay = 40e-3; + + mVideoThread = std::thread(std::mem_fn(&VideoState::handler), &mVideo); + break; + + default: + avcodec_free_context(&avctx); + break; + } + + return 0; +} + +int MovieState::parse_handler() +{ + int video_index = -1; + int audio_index = -1; + + mVideoStream = -1; + mAudioStream = -1; + + /* Dump information about file onto standard error */ + av_dump_format(mFormatCtx, 0, mFilename.c_str(), 0); + + /* Find the first video and audio streams */ + for(unsigned int i = 0;i < mFormatCtx->nb_streams;i++) + { + if(mFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + video_index = i; + else if(mFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + audio_index = i; + } + /* Start the external clock in 50ms, to give the audio and video + * components time to start without needing to skip ahead. + */ + mExternalClockBase = av_gettime() + 50000; + if(audio_index >= 0) + streamComponentOpen(audio_index); + if(video_index >= 0) + streamComponentOpen(video_index); + + if(mVideoStream < 0 && mAudioStream < 0) + { + std::cerr<< mFilename<<": could not open codecs" <= MAX_QUEUE_SIZE) + { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } + + AVPacket packet; + if(av_read_frame(mFormatCtx, &packet) < 0) + break; + + /* Copy the packet in the queue it's meant for. */ + if(packet.stream_index == mVideoStream) + mVideo.mQueue.put(&packet); + else if(packet.stream_index == mAudioStream) + mAudio.mQueue.put(&packet); + av_packet_unref(&packet); + } + mVideo.mQueue.finish(); + mAudio.mQueue.finish(); + + /* all done - wait for it */ + if(mVideoThread.joinable()) + mVideoThread.join(); + if(mAudioThread.joinable()) + mAudioThread.join(); + + mVideo.mEOS = true; + std::unique_lock lock(mVideo.mPictQMutex); + while(!mVideo.mFinalUpdate) + mVideo.mPictQCond.wait(lock); + lock.unlock(); + + SDL_Event evt{}; + evt.user.type = FF_MOVIE_DONE_EVENT; + SDL_PushEvent(&evt); + + return 0; +} + +} // namespace + + +int main(int argc, char *argv[]) +{ + std::unique_ptr movState; + + if(argc < 2) + { + std::cerr<< "Usage: "<] " < ALCdevice* + { + ALCdevice *dev = NULL; + if(argc > 3 && strcmp(argv[1], "-device") == 0) + { + dev = alcOpenDevice(argv[2]); + if(dev) + { + fileidx = 3; + return dev; + } + std::cerr<< "Failed to open \""<(new MovieState(argv[fileidx++])); + if(!movState->prepare()) movState = nullptr; + } + if(!movState) + { + std::cerr<< "Could not start a video" <setTitle(screen); + + /* Default to going to the next movie at the end of one. */ + enum class EomAction { + Next, Quit + } eom_action = EomAction::Next; + SDL_Event event; + while(SDL_WaitEvent(&event) == 1) + { + switch(event.type) + { + case SDL_KEYDOWN: + switch(event.key.keysym.sym) + { + case SDLK_ESCAPE: + movState->mQuit = true; + eom_action = EomAction::Quit; + break; + + case SDLK_n: + movState->mQuit = true; + eom_action = EomAction::Next; + break; + + default: + break; + } + break; + + case SDL_WINDOWEVENT: + switch(event.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, nullptr); + break; + + default: + break; + } + break; + + case SDL_QUIT: + movState->mQuit = true; + eom_action = EomAction::Quit; + break; + + case FF_UPDATE_EVENT: + reinterpret_cast(event.user.data1)->updatePicture( + screen, renderer + ); + break; + + case FF_REFRESH_EVENT: + reinterpret_cast(event.user.data1)->refreshTimer( + screen, renderer + ); + break; + + case FF_MOVIE_DONE_EVENT: + if(eom_action != EomAction::Quit) + { + movState = nullptr; + while(fileidx < argc && !movState) + { + movState = std::unique_ptr(new MovieState(argv[fileidx++])); + if(!movState->prepare()) movState = nullptr; + } + if(movState) + { + movState->setTitle(screen); + break; + } + } + + /* Nothing more to play. Shut everything down and quit. */ + movState = nullptr; + + alcMakeContextCurrent(nullptr); + alcDestroyContext(context); + alcCloseDevice(device); + + SDL_DestroyRenderer(renderer); + renderer = nullptr; + SDL_DestroyWindow(screen); + screen = nullptr; + + SDL_Quit(); + exit(0); + + default: + break; + } + } + + std::cerr<< "SDL_WaitEvent error - "< Date: Sun, 5 Mar 2017 04:50:27 -0800 Subject: Make the voice's source pointer atomic --- Alc/ALc.c | 2 +- Alc/ALu.c | 12 ++++++------ OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 16 +++++++++------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 59475e48..42e1cea0 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1721,7 +1721,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) for(pos = 0;pos < context->VoiceCount;pos++) { ALvoice *voice = context->Voices[pos]; - ALsource *source = voice->Source; + ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); if(source && source->OffsetType != AL_NONE) { WriteLock(&source->queue_lock); diff --git a/Alc/ALu.c b/Alc/ALu.c index 0a1b919a..e14c2013 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1277,8 +1277,8 @@ static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - if((source=(*voice)->Source) != NULL) - CalcSourceParams(*voice, source, ctx, force); + source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); + if(source) CalcSourceParams(*voice, source, ctx, force); } } IncrementRef(&ctx->UpdateCount); @@ -1419,13 +1419,13 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) voice_end = voice + ctx->VoiceCount; for(;voice != voice_end;++voice) { - source = (*voice)->Source; + source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); if(source && ATOMIC_LOAD(&(*voice)->Playing, almemory_order_relaxed) && (*voice)->Step > 0) { if(!MixSource(*voice, source, device, SamplesToDo)) { - (*voice)->Source = NULL; + ATOMIC_STORE(&(*voice)->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release); } } @@ -1592,8 +1592,8 @@ void aluHandleDisconnect(ALCdevice *device) voice_end = voice + Context->VoiceCount; while(voice != voice_end) { - ALsource *source = (*voice)->Source; - (*voice)->Source = NULL; + ALsource *source = ATOMIC_EXCHANGE(ALsource*, &(*voice)->Source, NULL, + almemory_order_acq_rel); ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release); if(source) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index fc1756e5..52fe731e 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -80,7 +80,7 @@ struct ALsourceProps { typedef struct ALvoice { struct ALsourceProps *Props; - struct ALsource *Source; + ATOMIC(struct ALsource*) Source; ATOMIC(bool) Playing; /* Current buffer queue item being played. */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 14329bc2..df0e7136 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -132,7 +132,7 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * ALvoice **voice_end = voice + context->VoiceCount; while(voice != voice_end) { - if((*voice)->Source == source) + if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source) return *voice; ++voice; } @@ -1639,7 +1639,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) ALCdevice_Lock(device); if((voice=GetSourceVoice(Source, context)) != NULL) { - voice->Source = NULL; + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); } ALCdevice_Unlock(device); @@ -2950,7 +2950,7 @@ void UpdateAllSourceProps(ALCcontext *context) for(pos = 0;pos < context->VoiceCount;pos++) { ALvoice *voice = context->Voices[pos]; - ALsource *source = voice->Source; + ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); if(source != NULL && source->NeedsUpdate && IsPlayingOrPausedSeq(source)) { source->NeedsUpdate = AL_FALSE; @@ -3028,7 +3028,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) assert(voice == NULL); for(i = 0;i < Context->VoiceCount;i++) { - if(Context->Voices[i]->Source == NULL) + if(ATOMIC_LOAD(&Context->Voices[i]->Source, almemory_order_acquire) == NULL) { voice = Context->Voices[i]; break; @@ -3069,7 +3069,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } } - voice->Source = Source; + ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); } else if(state == AL_PAUSED) @@ -3088,7 +3088,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) do_stop: if((voice=GetSourceVoice(Source, Context)) != NULL) { - voice->Source = NULL; + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); @@ -3102,7 +3102,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { if((voice=GetSourceVoice(Source, Context)) != NULL) { - voice->Source = NULL; + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); @@ -3257,6 +3257,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); do { + Current = NULL; + readPos = readPosFrac = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); voice = GetSourceVoice(Source, context); -- cgit v1.2.3 From 441180a08a86d940fdebd9c12f8fb5e1e4703026 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 15:15:08 +0100 Subject: Install dependencies on TravisCI to enable more features Install Ubuntu development packages for PulseAudio, PortAudio, ALSA and JACK to enable the building of most Linux backends on TravisCI. Intall Ubuntu development packages for Qt5 to enable `alsoft-config`. --- .travis.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.travis.yml b/.travis.yml index f87cfb1b..915431b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,5 +2,19 @@ os: - linux - osx dist: trusty +sudo: required language: c +install: + - > + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + # Install pulseaudio, portaudio, ALSA, JACK dependencies for + # corresponding backends. + # Install Qt5 dependency for alsoft-config. + sudo apt-get install -qq \ + libpulse-dev \ + portaudio19-dev \ + libasound2-dev \ + libjack-dev \ + qtbase5-dev + fi script: cmake . && make -j2 -- cgit v1.2.3 From 2a08871fba72997bd8353019977b2b1b41d23e3f Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 17:55:06 +0100 Subject: Delete Xamarin.Common.targets on AppVeyor This is a workaround for a Xamarin build script bug specific to AppVeyor. For more details see: http://help.appveyor.com/discussions/problems/4569 --- appveyor.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 4010f2ea..80908b8c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,11 @@ environment: - GEN: "Visual Studio 14 2015 Win64" CFG: Release +install: + # Remove the VS Xamarin targets to reduce AppVeyor specific noise in build + # logs. See also http://help.appveyor.com/discussions/problems/4569 + - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" + build_script: - cd build - cmake .. -G"%GEN%" -- cgit v1.2.3 From adf6fee6d102f64bd2c74710a518b5f4ccbb7be3 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 19:48:03 +0100 Subject: Explicit declare test matrix for TravisCI --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 915431b2..b0dff015 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ -os: - - linux - - osx -dist: trusty -sudo: required language: c +matrix: + include: + - os: linux + dist: trusty + - os: osx +sudo: required install: - > if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then -- cgit v1.2.3 From 1d208c49b51a25f617026b7444f03f1cd4599ee6 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 20:35:02 +0100 Subject: Add Android cross-compile to TravisCI test matrix The test entry adds the ability to test the OpenSLES backend. --- .travis.yml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b0dff015..bc8e6fbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,15 @@ matrix: include: - os: linux dist: trusty + - os: linux + dist: trusty + env: + - BUILD_ANDROID=true - os: osx sudo: required install: - > - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then # Install pulseaudio, portaudio, ALSA, JACK dependencies for # corresponding backends. # Install Qt5 dependency for alsoft-config. @@ -18,4 +22,25 @@ install: libjack-dev \ qtbase5-dev fi -script: cmake . && make -j2 + - > + if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then + curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r14-linux-x86_64.zip + unzip -q ~/android-ndk.zip -d ~ + sed -i -e 's/VERSION 3.6.0/VERSION 3.2/' ~/android-ndk-r14/build/cmake/android.toolchain.cmake + fi +script: + - > + if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then + cmake . + fi + - > + if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then + cmake \ + -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r14/build/cmake/android.toolchain.cmake \ + . + fi + - > + if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + cmake . + fi + - make -j2 -- cgit v1.2.3 From a2d0bf8d3ab24fc9e1456dc48f975d404e122869 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Sun, 5 Mar 2017 17:23:31 +0100 Subject: Configure CMake to require available backends on CI services Configure CMake to require the installed backend libraries. This should help to find build system regressions. On TravisCI with Linux this requires the ALSA, PulseAudio, PortAudio, OSS and JACK backend. On TravisCI with Android cross compile Linux this requires the OpenSL backend. On TravisCI with MacOSX this requires the CoreAudio backend. ON AppVeyor with Windows this requires the WinMM, DSound and MMDevAPI backend. --- .travis.yml | 13 +++++++++++-- appveyor.yml | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index bc8e6fbc..4483a9ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,16 +31,25 @@ install: script: - > if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then - cmake . + cmake \ + -DALSOFT_REQUIRE_ALSA=ON \ + -DALSOFT_REQUIRE_OSS=ON \ + -DALSOFT_REQUIRE_PORTAUDIO=ON \ + -DALSOFT_REQUIRE_PULSEAUDIO=ON \ + -DALSOFT_REQUIRE_JACK=ON \ + . fi - > if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then cmake \ -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r14/build/cmake/android.toolchain.cmake \ + -DALSOFT_REQUIRE_OPENSL=ON \ . fi - > if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - cmake . + cmake \ + -DALSOFT_REQUIRE_COREAUDIO=ON \ + . fi - make -j2 diff --git a/appveyor.yml b/appveyor.yml index 80908b8c..0d60cf61 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,6 @@ install: build_script: - cd build - - cmake .. -G"%GEN%" + - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_MMDEVAPI=ON .. - cmake --build . --config %CFG% --clean-first -- cgit v1.2.3 From 25de358c9ab823ad7a31e10cbc28fafc6e9923dc Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Mon, 6 Mar 2017 10:32:24 +0100 Subject: Unpack only required files from Android NDK --- .travis.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4483a9ab..1247c2af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,14 @@ install: - > if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r14-linux-x86_64.zip - unzip -q ~/android-ndk.zip -d ~ + unzip -q ~/android-ndk.zip -d ~ \ + 'android-ndk-r14/build/cmake/*' \ + 'android-ndk-r14/platforms/android-9/arch-arm/*' \ + 'android-ndk-r14/source.properties' \ + 'android-ndk-r14/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \ + 'android-ndk-r14/sysroot/*' \ + 'android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ + 'android-ndk-r14/toolchains/llvm/prebuilt/linux-x86_64/*' sed -i -e 's/VERSION 3.6.0/VERSION 3.2/' ~/android-ndk-r14/build/cmake/android.toolchain.cmake fi script: -- cgit v1.2.3 From 6a067d9f7eda65fd8ca5ebafa812745d5a03d907 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Mon, 6 Mar 2017 11:21:03 +0100 Subject: Use TravisCI cache to store stripped Android NDK toolchain --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1247c2af..44702c88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,9 @@ matrix: - BUILD_ANDROID=true - os: osx sudo: required +cache: + directories: + - $HOME/android-ndk-r14 install: - > if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then -- cgit v1.2.3 From 099b0a1f7cfc8ca12b8c4f993026f69aea5fab99 Mon Sep 17 00:00:00 2001 From: Marcel Metz Date: Mon, 6 Mar 2017 11:24:57 +0100 Subject: Only download and strip Android NDK when not cached --- .travis.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44702c88..c24cd95b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,16 +27,18 @@ install: fi - > if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then - curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r14-linux-x86_64.zip - unzip -q ~/android-ndk.zip -d ~ \ - 'android-ndk-r14/build/cmake/*' \ - 'android-ndk-r14/platforms/android-9/arch-arm/*' \ - 'android-ndk-r14/source.properties' \ - 'android-ndk-r14/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \ - 'android-ndk-r14/sysroot/*' \ - 'android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ - 'android-ndk-r14/toolchains/llvm/prebuilt/linux-x86_64/*' - sed -i -e 's/VERSION 3.6.0/VERSION 3.2/' ~/android-ndk-r14/build/cmake/android.toolchain.cmake + if [[ ! -d ~/android-ndk-r14 || -z "$(ls -A ~/android-ndk-r14)" ]]; then + curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r14-linux-x86_64.zip + unzip -q ~/android-ndk.zip -d ~ \ + 'android-ndk-r14/build/cmake/*' \ + 'android-ndk-r14/platforms/android-9/arch-arm/*' \ + 'android-ndk-r14/source.properties' \ + 'android-ndk-r14/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \ + 'android-ndk-r14/sysroot/*' \ + 'android-ndk-r14/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \ + 'android-ndk-r14/toolchains/llvm/prebuilt/linux-x86_64/*' + sed -i -e 's/VERSION 3.6.0/VERSION 3.2/' ~/android-ndk-r14/build/cmake/android.toolchain.cmake + fi fi script: - > -- cgit v1.2.3 From 1b3100ab9ac24a345b16a03fbad2c3cc2167ce79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 Mar 2017 22:47:29 -0800 Subject: Remove an unused function --- OpenAL32/Include/alSource.h | 6 ------ OpenAL32/alSource.c | 1 - 2 files changed, 7 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 52fe731e..c33d6d1a 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -228,12 +228,6 @@ void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); -inline ALboolean IsPlayingOrPaused(const ALsource *source) -{ - ALenum state = ATOMIC_LOAD(&source->state, almemory_order_relaxed); - return state == AL_PLAYING || state == AL_PAUSED; -} - ALvoid ReleaseALSources(ALCcontext *Context); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index df0e7136..799ad855 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -46,7 +46,6 @@ extern inline void LockSourcesWrite(ALCcontext *context); extern inline void UnlockSourcesWrite(ALCcontext *context); extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); -extern inline ALboolean IsPlayingOrPaused(const ALsource *source); static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); -- cgit v1.2.3 From bc0096365e66b8114a54bb533e818deb794c7601 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 6 Mar 2017 13:16:14 -0800 Subject: Don't modify the source state in the mixer --- Alc/mixer.c | 1 - OpenAL32/alSource.c | 32 +++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index b332030e..393d9210 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -681,7 +681,6 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei voice->Moving = AL_TRUE; /* Update source info */ - ATOMIC_STORE(&Source->state, State, almemory_order_relaxed); ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 799ad855..024d7918 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -144,6 +144,19 @@ static inline bool IsPlayingOrPausedSeq(const ALsource *source) return state == AL_PLAYING || state == AL_PAUSED; } +static ALenum GetSourceState(ALsource *source, ALvoice *voice) +{ + if(!voice) + { + ALenum state = AL_PLAYING; + if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &source->state, &state, AL_STOPPED, + almemory_order_acq_rel, almemory_order_acquire)) + return AL_STOPPED; + return state; + } + return ATOMIC_LOAD(&source->state, almemory_order_acquire); +} + static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) { return IsPlayingOrPausedSeq(source) && @@ -686,11 +699,14 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } WriteLock(&Source->queue_lock); - if(IsPlayingOrPausedSeq(Source)) { - WriteUnlock(&Source->queue_lock); - UnlockBuffersRead(device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); + if(state == AL_PLAYING || state == AL_PAUSED) + { + WriteUnlock(&Source->queue_lock); + UnlockBuffersRead(device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + } } if(buffer != NULL) @@ -1245,7 +1261,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_SOURCE_STATE: - *values = ATOMIC_LOAD_SEQ(&Source->state); + *values = GetSourceState(Source, GetSourceVoice(Source, Context)); return AL_TRUE; case AL_BYTE_LENGTH_SOFT: @@ -2950,7 +2966,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source != NULL && source->NeedsUpdate && IsPlayingOrPausedSeq(source)) + if(source != NULL && source->NeedsUpdate) { source->NeedsUpdate = AL_FALSE; UpdateSourceProps(source, num_sends); @@ -2994,7 +3010,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) goto do_stop; voice = GetSourceVoice(Source, Context); - switch(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel)) + switch(GetSourceState(Source, voice)) { case AL_PLAYING: assert(voice != NULL); @@ -3012,6 +3028,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) */ voice->Moving = AL_FALSE; ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); goto done; default: @@ -3070,6 +3087,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); } else if(state == AL_PAUSED) { -- cgit v1.2.3 From 190120dfd7ae53e284944fa4971efcf999cc321e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 6 Mar 2017 22:58:04 -0800 Subject: Store the channel count and sample size in the voice --- Alc/mixer.c | 4 ++-- OpenAL32/Include/alSource.h | 11 +++++++---- OpenAL32/alSource.c | 15 ++++----------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 393d9210..1c503a92 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -389,8 +389,8 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); - NumChannels = Source->NumChannels; - SampleSize = Source->SampleSize; + NumChannels = voice->NumChannels; + SampleSize = voice->SampleSize; increment = voice->Step; IrSize = (Device->Hrtf.Handle ? Device->Hrtf.Handle->irSize : 0); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index c33d6d1a..2525f107 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -94,6 +94,13 @@ typedef struct ALvoice { ATOMIC(ALuint) position; ATOMIC(ALuint) position_fraction; + /** + * Number of channels and bytes-per-sample for the attached source's + * buffer(s). + */ + ALsizei NumChannels; + ALsizei SampleSize; + /** Current target parameters used for mixing. */ ALint Step; @@ -197,10 +204,6 @@ typedef struct ALsource { ATOMIC(ALboolean) looping; - /** Current buffer sample info. */ - ALsizei NumChannels; - ALsizei SampleSize; - ALenum NeedsUpdate; ATOMIC(struct ALsourceProps*) Update; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 024d7918..ca4f3811 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -719,11 +719,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p /* Source is now Static */ Source->SourceType = AL_STATIC; - - ReadLock(&buffer->lock); - Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - Source->SampleSize = BytesFromFmt(buffer->FmtType); - ReadUnlock(&buffer->lock); } else { @@ -2582,12 +2577,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu IncrementRef(&buffer->ref); if(BufferFmt == NULL) - { BufferFmt = buffer; - - source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - source->SampleSize = BytesFromFmt(buffer->FmtType); - } else if(BufferFmt->Frequency != buffer->Frequency || BufferFmt->OriginalChannels != buffer->OriginalChannels || BufferFmt->OriginalType != buffer->OriginalType) @@ -2990,6 +2980,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; + ALbuffer *buffer = NULL; ALsizei i; /* Check that there is a queue containing at least one valid, non zero @@ -2997,7 +2988,6 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) BufferList = ATOMIC_LOAD_SEQ(&Source->queue); while(BufferList) { - ALbuffer *buffer; if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) break; BufferList = BufferList->next; @@ -3064,6 +3054,9 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if(Source->OffsetType != AL_NONE) ApplyOffset(Source, voice); + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + /* Clear previous samples. */ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); -- cgit v1.2.3 From b64da108a9d1885ae70eaf733a388666ddb9ac2d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Mar 2017 04:50:09 -0800 Subject: Check that a source is actually playing before setting paused Also slightly refactor setting playing state when the device is disconnected or there's no buffers to play. --- OpenAL32/alSource.c | 63 +++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index ca4f3811..57053083 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2330,6 +2330,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) } AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { + ALCdevice *device; ALCcontext *context; ALsource *source; ALsizei i; @@ -2346,16 +2347,30 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); + /* If the device is disconnected, go right to stopped. */ + if(!device->Connected) + { + for(i = 0;i < n;i++) + { + source = LookupSource(context, sources[i]); + ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->new_state = AL_NONE; + } + ALCdevice_Unlock(device); + goto done; + } + while(n > context->MaxVoices-context->VoiceCount) { ALsizei newcount = context->MaxVoices << 1; if(context->MaxVoices >= newcount) { - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } - AllocateVoices(context, newcount, context->Device->NumAuxSends); + AllocateVoices(context, newcount, device->NumAuxSends); } if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) @@ -2374,7 +2389,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) SetSourceState(source, context, AL_PLAYING); } } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2993,11 +3008,18 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) BufferList = BufferList->next; } - /* If there's nothing to play, or the device is disconnected, go right - * to stopped. - */ - if(!BufferList || !device->Connected) - goto do_stop; + /* If there's nothing to play, go right to stopped. */ + if(!BufferList) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); + Source->OffsetType = AL_NONE; + Source->Offset = 0.0; + goto done; + } voice = GetSourceVoice(Source, Context); switch(GetSourceState(Source, voice)) @@ -3084,31 +3106,16 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } else if(state == AL_PAUSED) { - ALenum playing = AL_PLAYING; if((voice=GetSourceVoice(Source, Context)) != NULL) { ATOMIC_STORE(&voice->Playing, false, almemory_order_release); while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); } - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Source->state, &playing, AL_PAUSED); - } - else if(state == AL_STOPPED) - { - do_stop: - if((voice=GetSourceVoice(Source, Context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - althrd_yield(); - } - if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; + if(GetSourceState(Source, voice) == AL_PLAYING) + ATOMIC_STORE(&Source->state, AL_PAUSED, almemory_order_release); } - else if(state == AL_INITIAL) + else /*if(state == AL_STOPPED || state == AL_INITIAL)*/ { if((voice=GetSourceVoice(Source, Context)) != NULL) { @@ -3118,7 +3125,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) althrd_yield(); } if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); + ATOMIC_STORE(&Source->state, state, almemory_order_relaxed); Source->OffsetType = AL_NONE; Source->Offset = 0.0; } -- cgit v1.2.3 From b1b3a369ef4ffdfa78abbb14e7e3b6d842cd4104 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 7 Mar 2017 09:38:33 -0800 Subject: Remove an unnecessary variable --- OpenAL32/alSource.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 57053083..e81fd853 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2987,7 +2987,6 @@ void UpdateAllSourceProps(ALCcontext *context) ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALCdevice *device = Context->Device; - ALuint refcount; ALvoice *voice; WriteLock(&Source->queue_lock); @@ -3109,7 +3108,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) if((voice=GetSourceVoice(Source, Context)) != NULL) { ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); } if(GetSourceState(Source, voice) == AL_PLAYING) @@ -3121,7 +3120,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); } if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) -- cgit v1.2.3 From 5ffb0842ac5022b1e5d34973ed6f512b5f0d7434 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Mar 2017 03:38:28 -0800 Subject: Remove unnecessary atomic members --- Alc/ALu.c | 195 ++++++++++++++++--------------------- OpenAL32/Include/alAuxEffectSlot.h | 8 +- OpenAL32/Include/alListener.h | 34 +++---- OpenAL32/Include/alSource.h | 82 ++++++++-------- OpenAL32/alAuxEffectSlot.c | 25 +++-- OpenAL32/alListener.c | 48 ++++----- OpenAL32/alSource.c | 79 ++++++++------- 7 files changed, 221 insertions(+), 250 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e14c2013..04b9c89d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -245,13 +245,13 @@ static ALboolean CalcListenerParams(ALCcontext *Context) if(!props) return AL_FALSE; /* AT then UP */ - N[0] = ATOMIC_LOAD(&props->Forward[0], almemory_order_relaxed); - N[1] = ATOMIC_LOAD(&props->Forward[1], almemory_order_relaxed); - N[2] = ATOMIC_LOAD(&props->Forward[2], almemory_order_relaxed); + N[0] = props->Forward[0]; + N[1] = props->Forward[1]; + N[2] = props->Forward[2]; aluNormalize(N); - V[0] = ATOMIC_LOAD(&props->Up[0], almemory_order_relaxed); - V[1] = ATOMIC_LOAD(&props->Up[1], almemory_order_relaxed); - V[2] = ATOMIC_LOAD(&props->Up[2], almemory_order_relaxed); + V[0] = props->Up[0]; + V[1] = props->Up[1]; + V[2] = props->Up[2]; aluNormalize(V); /* Build and normalize right-vector */ aluCrossproduct(N, V, U); @@ -264,27 +264,23 @@ static ALboolean CalcListenerParams(ALCcontext *Context) 0.0, 0.0, 0.0, 1.0 ); - P[0] = ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed); - P[1] = ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed); - P[2] = ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed); + P[0] = props->Position[0]; + P[1] = props->Position[1]; + P[2] = props->Position[2]; aluMatrixfFloat3(P, 1.0, &Listener->Params.Matrix); aluMatrixfSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); - aluVectorSet(&vel, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed), - ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed), - ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed), - 0.0f); + aluVectorSet(&vel, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); Listener->Params.Velocity = aluMatrixfVector(&Listener->Params.Matrix, &vel); - Listener->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed) * Context->GainBoost; - Listener->Params.MetersPerUnit = ATOMIC_LOAD(&props->MetersPerUnit, almemory_order_relaxed); + Listener->Params.Gain = props->Gain * Context->GainBoost; + Listener->Params.MetersPerUnit = props->MetersPerUnit; - Listener->Params.DopplerFactor = ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed); - Listener->Params.SpeedOfSound = ATOMIC_LOAD(&props->SpeedOfSound, almemory_order_relaxed) * - ATOMIC_LOAD(&props->DopplerVelocity, almemory_order_relaxed); + Listener->Params.DopplerFactor = props->DopplerFactor; + Listener->Params.SpeedOfSound = props->SpeedOfSound * props->DopplerVelocity; - Listener->Params.SourceDistanceModel = ATOMIC_LOAD(&props->SourceDistanceModel, almemory_order_relaxed); - Listener->Params.DistanceModel = ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed); + Listener->Params.SourceDistanceModel = props->SourceDistanceModel; + Listener->Params.DistanceModel = props->DistanceModel; ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &Listener->FreeList, props); return AL_TRUE; @@ -298,9 +294,9 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); if(!props) return AL_FALSE; - slot->Params.Gain = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); - slot->Params.AuxSendAuto = ATOMIC_LOAD(&props->AuxSendAuto, almemory_order_relaxed); - slot->Params.EffectType = ATOMIC_LOAD(&props->Type, almemory_order_relaxed); + slot->Params.Gain = props->Gain; + slot->Params.AuxSendAuto = props->AuxSendAuto; + slot->Params.EffectType = props->Type; if(IsReverbEffect(slot->Params.EffectType)) { slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; @@ -317,8 +313,8 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) /* Swap effect states. No need to play with the ref counts since they keep * the same number of refs. */ - state = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Params.EffectState, - almemory_order_relaxed); + state = props->State; + props->State = slot->Params.EffectState; slot->Params.EffectState = state; V(state,update)(device, slot, &props->Props); @@ -396,22 +392,22 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * ListenerGain = Listener->Params.Gain; /* Get source properties */ - SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); - MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed); - MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed); - Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed); - Relative = ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed); - DirectChannels = ATOMIC_LOAD(&props->DirectChannels, almemory_order_relaxed); + SourceVolume = props->Gain; + MinVolume = props->MinGain; + MaxVolume = props->MaxGain; + Pitch = props->Pitch; + Relative = props->HeadRelative; + DirectChannels = props->DirectChannels; /* Convert counter-clockwise to clockwise. */ - StereoMap[0].angle = -ATOMIC_LOAD(&props->StereoPan[0], almemory_order_relaxed); - StereoMap[1].angle = -ATOMIC_LOAD(&props->StereoPan[1], almemory_order_relaxed); + StereoMap[0].angle = -props->StereoPan[0]; + StereoMap[1].angle = -props->StereoPan[1]; voice->Direct.Buffer = Device->Dry.Buffer; voice->Direct.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { - SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); + SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) @@ -437,17 +433,17 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); - DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain *= props->Direct.Gain * ListenerGain; DryGain = minf(DryGain, GAIN_MIX_MAX); - DryGainHF = ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); - DryGainLF = ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); + DryGainHF = props->Direct.GainHF; + DryGainLF = props->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); - WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] *= props->Send[i].Gain * ListenerGain; WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); - WetGainHF[i] = ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); - WetGainLF[i] = ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); + WetGainHF[i] = props->Send[i].GainHF; + WetGainLF[i] = props->Send[i].GainLF; } switch(ALBuffer->FmtChannels) @@ -507,13 +503,13 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * ALfloat scale; /* AT then UP */ - N[0] = ATOMIC_LOAD(&props->Orientation[0][0], almemory_order_relaxed); - N[1] = ATOMIC_LOAD(&props->Orientation[0][1], almemory_order_relaxed); - N[2] = ATOMIC_LOAD(&props->Orientation[0][2], almemory_order_relaxed); + N[0] = props->Orientation[0][0]; + N[1] = props->Orientation[0][1]; + N[2] = props->Orientation[0][2]; aluNormalize(N); - V[0] = ATOMIC_LOAD(&props->Orientation[1][0], almemory_order_relaxed); - V[1] = ATOMIC_LOAD(&props->Orientation[1][1], almemory_order_relaxed); - V[2] = ATOMIC_LOAD(&props->Orientation[1][2], almemory_order_relaxed); + V[0] = props->Orientation[1][0]; + V[1] = props->Orientation[1][1]; + V[2] = props->Orientation[1][2]; aluNormalize(V); if(!Relative) { @@ -704,8 +700,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } { - HFScale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / Frequency; - LFScale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / Frequency; + HFScale = props->Direct.HFReference / Frequency; + LFScale = props->Direct.LFReference / Frequency; DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ DryGainLF = maxf(DryGainLF, 0.0625f); for(c = 0;c < num_channels;c++) @@ -725,8 +721,8 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } for(i = 0;i < NumSends;i++) { - HFScale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / Frequency; - LFScale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / Frequency; + HFScale = props->Send[i].HFReference / Frequency; + LFScale = props->Send[i].LFReference / Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); for(c = 0;c < num_channels;c++) @@ -790,40 +786,30 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro MetersPerUnit = Listener->Params.MetersPerUnit; /* Get source properties */ - SourceVolume = ATOMIC_LOAD(&props->Gain, almemory_order_relaxed); - MinVolume = ATOMIC_LOAD(&props->MinGain, almemory_order_relaxed); - MaxVolume = ATOMIC_LOAD(&props->MaxGain, almemory_order_relaxed); - Pitch = ATOMIC_LOAD(&props->Pitch, almemory_order_relaxed); - aluVectorSet(&Position, ATOMIC_LOAD(&props->Position[0], almemory_order_relaxed), - ATOMIC_LOAD(&props->Position[1], almemory_order_relaxed), - ATOMIC_LOAD(&props->Position[2], almemory_order_relaxed), - 1.0f); - aluVectorSet(&Direction, ATOMIC_LOAD(&props->Direction[0], almemory_order_relaxed), - ATOMIC_LOAD(&props->Direction[1], almemory_order_relaxed), - ATOMIC_LOAD(&props->Direction[2], almemory_order_relaxed), - 0.0f); - aluVectorSet(&Velocity, ATOMIC_LOAD(&props->Velocity[0], almemory_order_relaxed), - ATOMIC_LOAD(&props->Velocity[1], almemory_order_relaxed), - ATOMIC_LOAD(&props->Velocity[2], almemory_order_relaxed), - 0.0f); - MinDist = ATOMIC_LOAD(&props->RefDistance, almemory_order_relaxed); - MaxDist = ATOMIC_LOAD(&props->MaxDistance, almemory_order_relaxed); - Rolloff = ATOMIC_LOAD(&props->RollOffFactor, almemory_order_relaxed); - DopplerFactor *= ATOMIC_LOAD(&props->DopplerFactor, almemory_order_relaxed); - InnerAngle = ATOMIC_LOAD(&props->InnerAngle, almemory_order_relaxed); - OuterAngle = ATOMIC_LOAD(&props->OuterAngle, almemory_order_relaxed); - AirAbsorptionFactor = ATOMIC_LOAD(&props->AirAbsorptionFactor, almemory_order_relaxed); - DryGainHFAuto = ATOMIC_LOAD(&props->DryGainHFAuto, almemory_order_relaxed); - WetGainAuto = ATOMIC_LOAD(&props->WetGainAuto, almemory_order_relaxed); - WetGainHFAuto = ATOMIC_LOAD(&props->WetGainHFAuto, almemory_order_relaxed); - RoomRolloffBase = ATOMIC_LOAD(&props->RoomRolloffFactor, almemory_order_relaxed); + SourceVolume = props->Gain; + MinVolume = props->MinGain; + MaxVolume = props->MaxGain; + Pitch = props->Pitch; + aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); + aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); + aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); + MinDist = props->RefDistance; + MaxDist = props->MaxDistance; + Rolloff = props->RollOffFactor; + DopplerFactor *= props->DopplerFactor; + InnerAngle = props->InnerAngle; + OuterAngle = props->OuterAngle; + AirAbsorptionFactor = props->AirAbsorptionFactor; + DryGainHFAuto = props->DryGainHFAuto; + WetGainAuto = props->WetGainAuto; + WetGainHFAuto = props->WetGainHFAuto; + RoomRolloffBase = props->RoomRolloffFactor; voice->Direct.Buffer = Device->Dry.Buffer; voice->Direct.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) { - SendSlots[i] = ATOMIC_LOAD(&props->Send[i].Slot, almemory_order_relaxed); - + SendSlots[i] = props->Send[i].Slot; if(!SendSlots[i] && i == 0) SendSlots[i] = Device->DefaultSlot; if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) @@ -862,7 +848,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } /* Transform source to listener space (convert to head relative) */ - if(ATOMIC_LOAD(&props->HeadRelative, almemory_order_relaxed) == AL_FALSE) + if(props->HeadRelative == AL_FALSE) { const aluMatrixf *Matrix = &Listener->Params.Matrix; /* Transform source vectors */ @@ -893,8 +879,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro for(i = 0;i < NumSends;i++) RoomAttenuation[i] = 1.0f; switch(Listener->Params.SourceDistanceModel ? - ATOMIC_LOAD(&props->DistanceModel, almemory_order_relaxed) : - Listener->Params.DistanceModel) + props->DistanceModel : Listener->Params.DistanceModel) { case InverseDistanceClamped: ClampedDist = clampf(ClampedDist, MinDist, MaxDist); @@ -1003,17 +988,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(Angle < OuterAngle) { scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); - ConeVolume = lerp( - 1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), scale - ); - ConeHF = lerp( - 1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), scale - ); + ConeVolume = lerp(1.0f, props->OuterGain, scale); + ConeHF = lerp(1.0f, props->OuterGainHF, scale); } else { - ConeVolume = ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed); - ConeHF = ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed); + ConeVolume = props->OuterGain; + ConeHF = props->OuterGainHF; } DryGain *= ConeVolume; if(DryGainHFAuto) @@ -1027,17 +1008,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro (InnerAngle/360.0f); if(WetGainAuto) { - ConeVolume = lerp( - 1.0f, ATOMIC_LOAD(&props->OuterGain, almemory_order_relaxed), scale - ); + ConeVolume = lerp(1.0f, props->OuterGain, scale); for(i = 0;i < NumSends;i++) WetGain[i] *= ConeVolume; } if(WetGainHFAuto) { - ConeHF = lerp( - 1.0f, ATOMIC_LOAD(&props->OuterGainHF, almemory_order_relaxed), scale - ); + ConeHF = lerp(1.0f, props->OuterGainHF, scale); for(i = 0;i < NumSends;i++) WetGainHF[i] *= ConeHF; } @@ -1045,17 +1022,17 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Apply gain and frequency filters */ DryGain = clampf(DryGain, MinVolume, MaxVolume); - DryGain *= ATOMIC_LOAD(&props->Direct.Gain, almemory_order_relaxed) * ListenerGain; + DryGain *= props->Direct.Gain * ListenerGain; DryGain = minf(DryGain, GAIN_MIX_MAX); - DryGainHF *= ATOMIC_LOAD(&props->Direct.GainHF, almemory_order_relaxed); - DryGainLF *= ATOMIC_LOAD(&props->Direct.GainLF, almemory_order_relaxed); + DryGainHF *= props->Direct.GainHF; + DryGainLF *= props->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); - WetGain[i] *= ATOMIC_LOAD(&props->Send[i].Gain, almemory_order_relaxed) * ListenerGain; + WetGain[i] *= props->Send[i].Gain * ListenerGain; WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); - WetGainHF[i] *= ATOMIC_LOAD(&props->Send[i].GainHF, almemory_order_relaxed); - WetGainLF[i] *= ATOMIC_LOAD(&props->Send[i].GainLF, almemory_order_relaxed); + WetGainHF[i] *= props->Send[i].GainHF; + WetGainLF[i] *= props->Send[i].GainLF; } /* Calculate velocity-based doppler effect */ @@ -1093,9 +1070,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro * real outputs. */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; - ALfloat ev = 0.0f, az = 0.0f; - ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed); ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat radius = props->Radius; + ALfloat ev = 0.0f, az = 0.0f; ALfloat spread = 0.0f; voice->Direct.Buffer = Device->RealOut.Buffer; @@ -1144,8 +1121,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro { /* Non-HRTF rendering. */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; - ALfloat radius = ATOMIC_LOAD(&props->Radius, almemory_order_relaxed); ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat radius = props->Radius; ALfloat spread = 0.0f; /* Get the localized direction, and compute panned gains. */ @@ -1188,8 +1165,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } { - HFScale = ATOMIC_LOAD(&props->Direct.HFReference, almemory_order_relaxed) / Frequency; - LFScale = ATOMIC_LOAD(&props->Direct.LFReference, almemory_order_relaxed) / Frequency; + HFScale = props->Direct.HFReference / Frequency; + LFScale = props->Direct.LFReference / Frequency; DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ DryGainLF = maxf(DryGainLF, 0.0625f); voice->Direct.Params[0].FilterType = AF_None; @@ -1206,8 +1183,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } for(i = 0;i < NumSends;i++) { - HFScale = ATOMIC_LOAD(&props->Send[i].HFReference, almemory_order_relaxed) / Frequency; - LFScale = ATOMIC_LOAD(&props->Send[i].LFReference, almemory_order_relaxed) / Frequency; + HFScale = props->Send[i].HFReference / Frequency; + LFScale = props->Send[i].LFReference / Frequency; WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); voice->Send[i].Params[0].FilterType = AF_None; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 40ff1393..3c24f80c 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -75,13 +75,13 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = struct ALeffectslotProps { - ATOMIC(ALfloat) Gain; - ATOMIC(ALboolean) AuxSendAuto; + ALfloat Gain; + ALboolean AuxSendAuto; - ATOMIC(ALenum) Type; + ALenum Type; ALeffectProps Props; - ATOMIC(ALeffectState*) State; + ALeffectState *State; ATOMIC(struct ALeffectslotProps*) next; }; diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h index b89a00e7..9a7f9d49 100644 --- a/OpenAL32/Include/alListener.h +++ b/OpenAL32/Include/alListener.h @@ -9,29 +9,29 @@ extern "C" { #endif struct ALlistenerProps { - ATOMIC(ALfloat) Position[3]; - ATOMIC(ALfloat) Velocity[3]; - ATOMIC(ALfloat) Forward[3]; - ATOMIC(ALfloat) Up[3]; - ATOMIC(ALfloat) Gain; - ATOMIC(ALfloat) MetersPerUnit; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Forward[3]; + ALfloat Up[3]; + ALfloat Gain; + ALfloat MetersPerUnit; - ATOMIC(ALfloat) DopplerFactor; - ATOMIC(ALfloat) DopplerVelocity; - ATOMIC(ALfloat) SpeedOfSound; - ATOMIC(ALboolean) SourceDistanceModel; - ATOMIC(enum DistanceModel) DistanceModel; + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat SpeedOfSound; + ALboolean SourceDistanceModel; + enum DistanceModel DistanceModel; ATOMIC(struct ALlistenerProps*) next; }; typedef struct ALlistener { - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; - volatile ALfloat Forward[3]; - volatile ALfloat Up[3]; - volatile ALfloat Gain; - volatile ALfloat MetersPerUnit; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Forward[3]; + ALfloat Up[3]; + ALfloat Gain; + ALfloat MetersPerUnit; /* Pointer to the most recent property values that are awaiting an update. */ diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 2525f107..12b4587b 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -27,52 +27,52 @@ typedef struct ALbufferlistitem { struct ALsourceProps { ATOMIC(struct ALsourceProps*) next; - ATOMIC(ALfloat) Pitch; - ATOMIC(ALfloat) Gain; - ATOMIC(ALfloat) OuterGain; - ATOMIC(ALfloat) MinGain; - ATOMIC(ALfloat) MaxGain; - ATOMIC(ALfloat) InnerAngle; - ATOMIC(ALfloat) OuterAngle; - ATOMIC(ALfloat) RefDistance; - ATOMIC(ALfloat) MaxDistance; - ATOMIC(ALfloat) RollOffFactor; - ATOMIC(ALfloat) Position[3]; - ATOMIC(ALfloat) Velocity[3]; - ATOMIC(ALfloat) Direction[3]; - ATOMIC(ALfloat) Orientation[2][3]; - ATOMIC(ALboolean) HeadRelative; - ATOMIC(enum DistanceModel) DistanceModel; - ATOMIC(ALboolean) DirectChannels; - - ATOMIC(ALboolean) DryGainHFAuto; - ATOMIC(ALboolean) WetGainAuto; - ATOMIC(ALboolean) WetGainHFAuto; - ATOMIC(ALfloat) OuterGainHF; - - ATOMIC(ALfloat) AirAbsorptionFactor; - ATOMIC(ALfloat) RoomRolloffFactor; - ATOMIC(ALfloat) DopplerFactor; - - ATOMIC(ALfloat) StereoPan[2]; - - ATOMIC(ALfloat) Radius; + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RollOffFactor; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Direction[3]; + ALfloat Orientation[2][3]; + ALboolean HeadRelative; + enum DistanceModel DistanceModel; + ALboolean DirectChannels; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + ALfloat StereoPan[2]; + + ALfloat Radius; /** Direct filter and auxiliary send info. */ struct { - ATOMIC(ALfloat) Gain; - ATOMIC(ALfloat) GainHF; - ATOMIC(ALfloat) HFReference; - ATOMIC(ALfloat) GainLF; - ATOMIC(ALfloat) LFReference; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; } Direct; struct { - ATOMIC(struct ALeffectslot*) Slot; - ATOMIC(ALfloat) Gain; - ATOMIC(ALfloat) GainHF; - ATOMIC(ALfloat) HFReference; - ATOMIC(ALfloat) GainLF; - ATOMIC(ALfloat) LFReference; + struct ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; } Send[]; }; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index e6b4ff68..37316549 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -530,8 +530,9 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e props = ATOMIC_LOAD_SEQ(&EffectSlot->FreeList); while(props) { - State = ATOMIC_EXCHANGE(ALeffectState*, &props->State, NULL, almemory_order_relaxed); - if(State) ALeffectState_DecRef(State); + if(props->State) + ALeffectState_DecRef(props->State); + props->State = NULL; props = ATOMIC_LOAD(&props->next, almemory_order_relaxed); } @@ -602,24 +603,20 @@ ALenum InitEffectSlot(ALeffectslot *slot) void DeinitEffectSlot(ALeffectslot *slot) { struct ALeffectslotProps *props; - ALeffectState *state; size_t count = 0; props = ATOMIC_LOAD_SEQ(&slot->Update); if(props) { - state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); - if(state) ALeffectState_DecRef(state); + if(props->State) ALeffectState_DecRef(props->State); TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props); al_free(props); } props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed); while(props) { - struct ALeffectslotProps *next; - state = ATOMIC_LOAD(&props->State, almemory_order_relaxed); - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - if(state) ALeffectState_DecRef(state); + struct ALeffectslotProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + if(props->State) ALeffectState_DecRef(props->State); al_free(props); props = next; ++count; @@ -651,17 +648,17 @@ void UpdateEffectSlotProps(ALeffectslot *slot) } /* Copy in current property values. */ - ATOMIC_STORE(&props->Gain, slot->Gain, almemory_order_relaxed); - ATOMIC_STORE(&props->AuxSendAuto, slot->AuxSendAuto, almemory_order_relaxed); + props->Gain = slot->Gain; + props->AuxSendAuto = slot->AuxSendAuto; - ATOMIC_STORE(&props->Type, slot->Effect.Type, almemory_order_relaxed); + props->Type = slot->Effect.Type; props->Props = slot->Effect.Props; /* Swap out any stale effect state object there may be in the container, to * delete it. */ ALeffectState_IncRef(slot->Effect.State); - oldstate = ATOMIC_EXCHANGE(ALeffectState*, &props->State, slot->Effect.State, - almemory_order_relaxed); + oldstate = props->State; + props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props, diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 9c237e99..e3d71435 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -474,30 +474,30 @@ void UpdateListenerProps(ALCcontext *context) } /* Copy in current property values. */ - ATOMIC_STORE(&props->Position[0], listener->Position[0], almemory_order_relaxed); - ATOMIC_STORE(&props->Position[1], listener->Position[1], almemory_order_relaxed); - ATOMIC_STORE(&props->Position[2], listener->Position[2], almemory_order_relaxed); - - ATOMIC_STORE(&props->Velocity[0], listener->Velocity[0], almemory_order_relaxed); - ATOMIC_STORE(&props->Velocity[1], listener->Velocity[1], almemory_order_relaxed); - ATOMIC_STORE(&props->Velocity[2], listener->Velocity[2], almemory_order_relaxed); - - ATOMIC_STORE(&props->Forward[0], listener->Forward[0], almemory_order_relaxed); - ATOMIC_STORE(&props->Forward[1], listener->Forward[1], almemory_order_relaxed); - ATOMIC_STORE(&props->Forward[2], listener->Forward[2], almemory_order_relaxed); - ATOMIC_STORE(&props->Up[0], listener->Up[0], almemory_order_relaxed); - ATOMIC_STORE(&props->Up[1], listener->Up[1], almemory_order_relaxed); - ATOMIC_STORE(&props->Up[2], listener->Up[2], almemory_order_relaxed); - - ATOMIC_STORE(&props->Gain, listener->Gain, almemory_order_relaxed); - ATOMIC_STORE(&props->MetersPerUnit, listener->MetersPerUnit, almemory_order_relaxed); - - ATOMIC_STORE(&props->DopplerFactor, context->DopplerFactor, almemory_order_relaxed); - ATOMIC_STORE(&props->DopplerVelocity, context->DopplerVelocity, almemory_order_relaxed); - ATOMIC_STORE(&props->SpeedOfSound, context->SpeedOfSound, almemory_order_relaxed); - - ATOMIC_STORE(&props->SourceDistanceModel, context->SourceDistanceModel, almemory_order_relaxed); - ATOMIC_STORE(&props->DistanceModel, context->DistanceModel, almemory_order_relaxed); + props->Position[0] = listener->Position[0]; + props->Position[1] = listener->Position[1]; + props->Position[2] = listener->Position[2]; + + props->Velocity[0] = listener->Velocity[0]; + props->Velocity[1] = listener->Velocity[1]; + props->Velocity[2] = listener->Velocity[2]; + + props->Forward[0] = listener->Forward[0]; + props->Forward[1] = listener->Forward[1]; + props->Forward[2] = listener->Forward[2]; + props->Up[0] = listener->Up[0]; + props->Up[1] = listener->Up[1]; + props->Up[2] = listener->Up[2]; + + props->Gain = listener->Gain; + props->MetersPerUnit = listener->MetersPerUnit; + + props->DopplerFactor = context->DopplerFactor; + props->DopplerVelocity = context->DopplerVelocity; + props->SpeedOfSound = context->SpeedOfSound; + + props->SourceDistanceModel = context->SourceDistanceModel; + props->DistanceModel = context->DistanceModel;; /* Set the new container for updating internal parameters. */ props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e81fd853..c4c0bfb1 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2892,63 +2892,60 @@ static void UpdateSourceProps(ALsource *source, ALsizei num_sends) } /* Copy in current property values. */ - ATOMIC_STORE(&props->Pitch, source->Pitch, almemory_order_relaxed); - ATOMIC_STORE(&props->Gain, source->Gain, almemory_order_relaxed); - ATOMIC_STORE(&props->OuterGain, source->OuterGain, almemory_order_relaxed); - ATOMIC_STORE(&props->MinGain, source->MinGain, almemory_order_relaxed); - ATOMIC_STORE(&props->MaxGain, source->MaxGain, almemory_order_relaxed); - ATOMIC_STORE(&props->InnerAngle, source->InnerAngle, almemory_order_relaxed); - ATOMIC_STORE(&props->OuterAngle, source->OuterAngle, almemory_order_relaxed); - ATOMIC_STORE(&props->RefDistance, source->RefDistance, almemory_order_relaxed); - ATOMIC_STORE(&props->MaxDistance, source->MaxDistance, almemory_order_relaxed); - ATOMIC_STORE(&props->RollOffFactor, source->RollOffFactor, almemory_order_relaxed); + props->Pitch = source->Pitch; + props->Gain = source->Gain; + props->OuterGain = source->OuterGain; + props->MinGain = source->MinGain; + props->MaxGain = source->MaxGain; + props->InnerAngle = source->InnerAngle; + props->OuterAngle = source->OuterAngle; + props->RefDistance = source->RefDistance; + props->MaxDistance = source->MaxDistance; + props->RollOffFactor = source->RollOffFactor; for(i = 0;i < 3;i++) - ATOMIC_STORE(&props->Position[i], source->Position[i], almemory_order_relaxed); + props->Position[i] = source->Position[i]; for(i = 0;i < 3;i++) - ATOMIC_STORE(&props->Velocity[i], source->Velocity[i], almemory_order_relaxed); + props->Velocity[i] = source->Velocity[i]; for(i = 0;i < 3;i++) - ATOMIC_STORE(&props->Direction[i], source->Direction[i], almemory_order_relaxed); + props->Direction[i] = source->Direction[i]; for(i = 0;i < 2;i++) { ALsizei j; for(j = 0;j < 3;j++) - ATOMIC_STORE(&props->Orientation[i][j], source->Orientation[i][j], - almemory_order_relaxed); + props->Orientation[i][j] = source->Orientation[i][j]; } - ATOMIC_STORE(&props->HeadRelative, source->HeadRelative, almemory_order_relaxed); - ATOMIC_STORE(&props->DistanceModel, source->DistanceModel, almemory_order_relaxed); - ATOMIC_STORE(&props->DirectChannels, source->DirectChannels, almemory_order_relaxed); + props->HeadRelative = source->HeadRelative; + props->DistanceModel = source->DistanceModel; + props->DirectChannels = source->DirectChannels; - ATOMIC_STORE(&props->DryGainHFAuto, source->DryGainHFAuto, almemory_order_relaxed); - ATOMIC_STORE(&props->WetGainAuto, source->WetGainAuto, almemory_order_relaxed); - ATOMIC_STORE(&props->WetGainHFAuto, source->WetGainHFAuto, almemory_order_relaxed); - ATOMIC_STORE(&props->OuterGainHF, source->OuterGainHF, almemory_order_relaxed); + props->DryGainHFAuto = source->DryGainHFAuto; + props->WetGainAuto = source->WetGainAuto; + props->WetGainHFAuto = source->WetGainHFAuto; + props->OuterGainHF = source->OuterGainHF; - ATOMIC_STORE(&props->AirAbsorptionFactor, source->AirAbsorptionFactor, almemory_order_relaxed); - ATOMIC_STORE(&props->RoomRolloffFactor, source->RoomRolloffFactor, almemory_order_relaxed); - ATOMIC_STORE(&props->DopplerFactor, source->DopplerFactor, almemory_order_relaxed); + props->AirAbsorptionFactor = source->AirAbsorptionFactor; + props->RoomRolloffFactor = source->RoomRolloffFactor; + props->DopplerFactor = source->DopplerFactor; - ATOMIC_STORE(&props->StereoPan[0], source->StereoPan[0], almemory_order_relaxed); - ATOMIC_STORE(&props->StereoPan[1], source->StereoPan[1], almemory_order_relaxed); + props->StereoPan[0] = source->StereoPan[0]; + props->StereoPan[1] = source->StereoPan[1]; - ATOMIC_STORE(&props->Radius, source->Radius, almemory_order_relaxed); + props->Radius = source->Radius; - ATOMIC_STORE(&props->Direct.Gain, source->Direct.Gain, almemory_order_relaxed); - ATOMIC_STORE(&props->Direct.GainHF, source->Direct.GainHF, almemory_order_relaxed); - ATOMIC_STORE(&props->Direct.HFReference, source->Direct.HFReference, almemory_order_relaxed); - ATOMIC_STORE(&props->Direct.GainLF, source->Direct.GainLF, almemory_order_relaxed); - ATOMIC_STORE(&props->Direct.LFReference, source->Direct.LFReference, almemory_order_relaxed); + props->Direct.Gain = source->Direct.Gain; + props->Direct.GainHF = source->Direct.GainHF; + props->Direct.HFReference = source->Direct.HFReference; + props->Direct.GainLF = source->Direct.GainLF; + props->Direct.LFReference = source->Direct.LFReference; for(i = 0;i < num_sends;i++) { - ATOMIC_STORE(&props->Send[i].Slot, source->Send[i].Slot, almemory_order_relaxed); - ATOMIC_STORE(&props->Send[i].Gain, source->Send[i].Gain, almemory_order_relaxed); - ATOMIC_STORE(&props->Send[i].GainHF, source->Send[i].GainHF, almemory_order_relaxed); - ATOMIC_STORE(&props->Send[i].HFReference, source->Send[i].HFReference, - almemory_order_relaxed); - ATOMIC_STORE(&props->Send[i].GainLF, source->Send[i].GainLF, almemory_order_relaxed); - ATOMIC_STORE(&props->Send[i].LFReference, source->Send[i].LFReference, - almemory_order_relaxed); + props->Send[i].Slot = source->Send[i].Slot; + props->Send[i].Gain = source->Send[i].Gain; + props->Send[i].GainHF = source->Send[i].GainHF; + props->Send[i].HFReference = source->Send[i].HFReference; + props->Send[i].GainLF = source->Send[i].GainLF; + props->Send[i].LFReference = source->Send[i].LFReference; } /* Set the new container for updating internal parameters. */ -- cgit v1.2.3 From ae22d742dc665fb5a75a24c9af24945a5722d8ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 9 Mar 2017 07:15:06 -0800 Subject: Remove an unnecessary variable --- Alc/ALc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 42e1cea0..882a8cb0 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1704,13 +1704,12 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) if(ATOMIC_EXCHANGE_SEQ(ALenum, &context->DeferUpdates, AL_FALSE)) { ALsizei pos; - uint updates; /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_TRUE); - while(((updates=ReadRef(&context->UpdateCount))&1) != 0) + while((ATOMIC_LOAD(&context->UpdateCount, almemory_order_acquire)&1) != 0) althrd_yield(); UpdateListenerProps(context); -- cgit v1.2.3 From 9454d3e776792ed5762d72f28f6785b4b2d1606c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 9 Mar 2017 07:23:12 -0800 Subject: Move ALvoice declaration to alu.h --- OpenAL32/Include/alSource.h | 54 ------------------------------------------- OpenAL32/Include/alu.h | 56 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 12b4587b..1dd835c4 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -77,60 +77,6 @@ struct ALsourceProps { }; -typedef struct ALvoice { - struct ALsourceProps *Props; - - ATOMIC(struct ALsource*) Source; - ATOMIC(bool) Playing; - - /* Current buffer queue item being played. */ - ATOMIC(ALbufferlistitem*) current_buffer; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue, and the fractional (fixed-point) offset to the next - * sample. - */ - ATOMIC(ALuint) position; - ATOMIC(ALuint) position_fraction; - - /** - * Number of channels and bytes-per-sample for the attached source's - * buffer(s). - */ - ALsizei NumChannels; - ALsizei SampleSize; - - /** Current target parameters used for mixing. */ - ALint Step; - - /* If not 'moving', gain/coefficients are set directly without fading. */ - ALboolean Moving; - - ALboolean IsHrtf; - - ALuint Offset; /* Number of output samples mixed since starting. */ - - alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; - - InterpState ResampleState; - - struct { - DirectParams Params[MAX_INPUT_CHANNELS]; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei Channels; - } Direct; - - struct { - SendParams Params[MAX_INPUT_CHANNELS]; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei Channels; - } Send[]; -} ALvoice; - - typedef struct ALsource { /** Source properties. */ ALfloat Pitch; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index b6f0e769..03f0090d 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -35,9 +35,9 @@ extern "C" { struct ALsource; struct ALsourceProps; +struct ALbufferlistitem; struct ALvoice; struct ALeffectslot; -struct ALbuffer; /* The number of distinct scale and phase intervals within the filter table. */ @@ -123,6 +123,7 @@ typedef struct MixHrtfParams { } Steps; } MixHrtfParams; + typedef struct DirectParams { enum ActiveFilters FilterType; ALfilterState LowPass; @@ -151,6 +152,59 @@ typedef struct SendParams { } Gains; } SendParams; +typedef struct ALvoice { + struct ALsourceProps *Props; + + ATOMIC(struct ALsource*) Source; + ATOMIC(bool) Playing; + + /* Current buffer queue item being played. */ + ATOMIC(struct ALbufferlistitem*) current_buffer; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue, and the fractional (fixed-point) offset to the next + * sample. + */ + ATOMIC(ALuint) position; + ATOMIC(ALuint) position_fraction; + + /** + * Number of channels and bytes-per-sample for the attached source's + * buffer(s). + */ + ALsizei NumChannels; + ALsizei SampleSize; + + /** Current target parameters used for mixing. */ + ALint Step; + + /* If not 'moving', gain/coefficients are set directly without fading. */ + ALboolean Moving; + + ALboolean IsHrtf; + + ALuint Offset; /* Number of output samples mixed since starting. */ + + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; + + InterpState ResampleState; + + struct { + DirectParams Params[MAX_INPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei Channels; + } Direct; + + struct { + SendParams Params[MAX_INPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei Channels; + } Send[]; +} ALvoice; + typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, -- cgit v1.2.3 From d9b1995e95ac3d838566500f1e5496ae71d832e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 9 Mar 2017 15:41:20 -0800 Subject: Add an NFC filter implementation --- Alc/nfcfilter.c | 422 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/nfcfilter.h | 37 +++++ CMakeLists.txt | 1 + 3 files changed, 460 insertions(+) create mode 100644 Alc/nfcfilter.c create mode 100644 Alc/nfcfilter.h diff --git a/Alc/nfcfilter.c b/Alc/nfcfilter.c new file mode 100644 index 00000000..c27ea705 --- /dev/null +++ b/Alc/nfcfilter.c @@ -0,0 +1,422 @@ + +#include "config.h" + +#include "nfcfilter.h" + +#include "alu.h" + + +/* Near-field control filters are the basis for handling the near-field effect. + * The near-field effect is a bass-boost present in the directional components + * of a recorded signal, created as a result of the wavefront curvature (itself + * a function of sound distance). Proper reproduction dictates this be + * compensated for using a bass-cut given the playback speaker distance, to + * avoid excessive bass in the playback. + * + * For real-time rendered audio, emulating the near-field effect based on the + * sound source's distance, and subsequently compensating for it at output + * based on the speaker distances, can create a more realistic perception of + * sound distance beyond a simple 1/r attenuation. + * + * These filters do just that. Each one applies a low-shelf filter, created as + * the combination of a bass-boost for a given sound source distance (near- + * field emulation) along with a bass-cut for a given control/speaker distance + * (near-field compensation). + * + * Note that it is necessary to apply a cut along with the boost, since the + * boost alone is unstable in higher-order ambisonics as it causes an infinite + * DC gain (even first-order ambisonics requires there to be no DC offset for + * the boost to work). Consequently, ambisonics requires a control parameter to + * be used to avoid an unstable boost-only filter. NFC-HOA defines this control + * as a reference delay, calculated with: + * + * reference_delay = control_distance / speed_of_sound + * + * This means w0 (for input) or w1 (for output) should be set to: + * + * wN = 1 / (reference_delay * sample_rate) + * + * when dealing with NFC-HOA content. For FOA input content, which does not + * specify a reference_delay variable, w0 should be set to 0 to apply only + * near-field compensation for output. It's important that w1 be a finite, + * positive, non-0 value or else the bass-boost will become unstable again. + * Also, w0 should not be too large compared to w1, to avoid excessively loud + * low frequencies. + */ + +static const float B[4][3] = { + { }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ +}; + +void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1) +{ + float b_00, g_0; + float r; + + memset(nfc, 0, sizeof(*nfc)); + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* NOTE: Slight adjustment from the literature to raise the center + * frequency a bit (0.5 -> 1.0). + */ + + /* Calculate bass-boost coefficients. */ + r = 1.0f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[1] = (2.0f * b_00) / g_0; + + /* Calculate bass-cut coefficients. */ + r = 1.0f * w1; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[1+1] = (2.0f * b_00) / g_0; +} + +void NfcFilterAdjust1(NfcFilter *nfc, const float w0) +{ + float b_00, g_0; + float r; + + r = 1.0f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] = nfc->g * g_0; + nfc->coeffs[1] = (2.0f * b_00) / g_0; +} + +void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->coeffs[0]; + const float a0 = nfc->coeffs[1]; + const float a1 = nfc->coeffs[2]; + float z1 = nfc->history[0]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a1*z1); + out = y + (a0*z1); + z1 += y; + + dst[i] = out; + } + nfc->history[0] = z1; +} + + +void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float r; + + memset(nfc, 0, sizeof(*nfc)); + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 1.0f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + /* Calculate bass-cut coefficients. */ + r = 1.0f * w1; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2+2] = (4.0f * b_11) / g_1; +} + +void NfcFilterAdjust2(NfcFilter *nfc, const float w0) +{ + float b_10, b_11, g_1; + float r; + + r = 1.0f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] = nfc->g * g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; +} + +void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->coeffs[0]; + const float a00 = nfc->coeffs[1]; + const float a01 = nfc->coeffs[2]; + const float a10 = nfc->coeffs[3]; + const float a11 = nfc->coeffs[4]; + float z1 = nfc->history[0]; + float z2 = nfc->history[1]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a10*z1) - (a11*z2); + out = y + (a00*z1) + (a01*z2); + z2 += z1; + z1 += y; + + dst[i] = out; + } + nfc->history[0] = z1; + nfc->history[1] = z2; +} + + +void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + memset(nfc, 0, sizeof(*nfc)); + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 1.0f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[2+1] = (2.0f * b_00) / g_0; + + /* Calculate bass-cut coefficients. */ + r = 1.0f * w1; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[3+2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0; +} + +void NfcFilterAdjust3(NfcFilter *nfc, const float w0) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + r = 1.0f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] = nfc->g * g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[2+1] = (2.0f * b_00) / g_0; +} + +void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->coeffs[0]; + const float a00 = nfc->coeffs[1]; + const float a01 = nfc->coeffs[2]; + const float a02 = nfc->coeffs[3]; + const float a10 = nfc->coeffs[4]; + const float a11 = nfc->coeffs[5]; + const float a12 = nfc->coeffs[6]; + float z1 = nfc->history[0]; + float z2 = nfc->history[1]; + float z3 = nfc->history[2]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a10*z1) - (a11*z2); + out = y + (a00*z1) + (a01*z2); + z2 += z1; + z1 += y; + + y = out - (a12*z3); + out = y + (a02*z3); + z3 += y; + + dst[i] = out; + } + nfc->history[0] = z1; + nfc->history[1] = z2; + nfc->history[2] = z3; +} + + +#if 0 /* Original methods the above are derived from. */ +static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) +{ + static const float B[4][5] = { + { }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + { 4.2076f, 11.4877f, 5.7924f, 9.1401f } + }; + float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); + float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); + ALsizei i; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* NOTE: Slight adjustment from the literature to raise the center + * frequency a bit (0.5 -> 1.0). + */ + r = 1.0f * w0; + for(i = 0; i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->b[i] = b_10; + nfc->b[i + 1] = b_11; + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->b[i] = b_00; + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } + + r = 1.0f * w1; + for(i = 0;i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; + } + + for(i = 0; i < MAX_AMBI_ORDER; i++) + nfc->history[i] = 0.0f; +} + +static void NfcFilterAdjust(NfcFilter *nfc, const float distance) +{ + int i; + + nfc->coeffs[0] = nfc->g; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float b_10 = nfc->b[i] / distance; + float b_11 = nfc->b[i+1] / (distance * distance); + float g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < nfc->order) + { + float b_00 = nfc->b[i] / distance; + float g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } +} + +static float NfcFilterUpdate(const float in, NfcFilter *nfc) +{ + int i; + float out = in * nfc->coeffs[0]; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - + (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; + out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); + + nfc->history[i+1] += nfc->history[i]; + nfc->history[i] += y; + } + if(i < nfc->order) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; + + out = y + (nfc->coeffs[i+1] * nfc->history[i]); + nfc->history[i] += y; + } + + return out; +} +#endif diff --git a/Alc/nfcfilter.h b/Alc/nfcfilter.h new file mode 100644 index 00000000..199849fb --- /dev/null +++ b/Alc/nfcfilter.h @@ -0,0 +1,37 @@ +#ifndef NFCFILTER_H +#define NFCFILTER_H + +#include "alMain.h" + +typedef struct NfcFilter { + float g; + float coeffs[MAX_AMBI_ORDER*2 + 1]; + float history[MAX_AMBI_ORDER]; +} NfcFilter; + +/* NOTE: + * w0 = speed_of_sound / (source_distance * sample_rate); + * w1 = speed_of_sound / (control_distance * sample_rate); + * + * Generally speaking, the control distance should be approximately the average + * speaker distance, or based on the reference delay if outputing NFC-HOA. It + * must not be negative, 0, or infinite. The source distance should not be too + * small relative to the control distance. + */ + +/* Near-field control filter for first-order ambisonic channels (1-3). */ +void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1); +void NfcFilterAdjust1(NfcFilter *nfc, const float w0); +void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +/* Near-field control filter for second-order ambisonic channels (4-8). */ +void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1); +void NfcFilterAdjust2(NfcFilter *nfc, const float w0); +void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +/* Near-field control filter for third-order ambisonic channels (9-15). */ +void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1); +void NfcFilterAdjust3(NfcFilter *nfc, const float w0); +void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +#endif /* NFCFILTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index ed17743c..b778907c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -722,6 +722,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/uhjfilter.c Alc/ambdec.c Alc/bformatdec.c + Alc/nfcfilter.c Alc/panning.c Alc/mixer.c Alc/mixer_c.c -- cgit v1.2.3 From 583d431947be540a33843d68feb5f1456671c298 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 10 Mar 2017 04:35:32 -0800 Subject: Implement NFC filters for Ambisonic rendering NFC filters currently only work when rendering to ambisonic buffers, which includes HQ rendering and ambisonic output. There are two new config options: 'decoder/nfc' (default on) enables or disables use of NFC filters globally, and 'decoder/nfc-ref-delay' (default 0) specifies the reference delay parameter for NFC-HOA rendering with ambisonic output (a value of 0 disables NFC). Currently, NFC filters rely on having an appropriate value set for AL_METERS_PER_UNIT to get the correct scaling. HQ rendering uses the averaged speaker distances as a control/reference, and currently doesn't correct for individual speaker distances (if the speakers are all equidistant, this is fine, otherwise per-speaker correction should be done as well). --- Alc/ALc.c | 20 ++++++ Alc/ALu.c | 64 ++++++++++++++--- Alc/mixer.c | 55 +++++++++++++-- Alc/panning.c | 172 ++++++++++++++++++++++++++++++---------------- OpenAL32/Include/alMain.h | 7 ++ OpenAL32/Include/alu.h | 9 ++- OpenAL32/alSource.c | 12 ++++ 7 files changed, 262 insertions(+), 77 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 882a8cb0..beec0c32 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2310,6 +2310,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } AllocateVoices(context, context->MaxVoices, old_sends); + for(pos = 0;pos < context->VoiceCount;pos++) + { + ALvoice *voice = context->Voices[pos]; + if(!voice->Source) continue; + + if(device->AvgSpeakerDist > 0.0f) + { + /* Reinitialize the NFC filters for new parameters. */ + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(i = 0;i < voice->NumChannels;i++) + { + NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1); + NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1); + NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1); + } + } + } UnlockUIntMapRead(&context->SourceMap); UpdateListenerProps(context); @@ -3755,6 +3773,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; + device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); @@ -4271,6 +4290,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; + device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); diff --git a/Alc/ALu.c b/Alc/ALu.c index 04b9c89d..90ca8ab1 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -496,6 +496,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * break; } + voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC); if(isbformat) { ALfloat N[3], V[3], U[3]; @@ -535,6 +536,17 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * for(c = 0;c < num_channels;c++) ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, voice->Direct.Params[c].Gains.Target); + if(Device->AvgSpeakerDist > 0.0f) + { + /* NOTE: The NFCtrlFilters were created with a w0 of 0, which is + * what we want for FOA input. So there's nothing to adjust. + */ + voice->Direct.ChannelsPerOrder[0] = 1; + voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); + voice->Direct.ChannelsPerOrder[2] = 0; + voice->Direct.ChannelsPerOrder[3] = 0; + voice->Flags |= VOICE_HAS_NFC; + } for(i = 0;i < NumSends;i++) { @@ -553,8 +565,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } - - voice->IsHrtf = AL_FALSE; } else { @@ -592,8 +602,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } - - voice->IsHrtf = AL_FALSE; } else if(Device->Render_Mode == HrtfRender) { @@ -647,7 +655,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } } - voice->IsHrtf = AL_TRUE; + voice->Flags |= VOICE_IS_HRTF; } else { @@ -694,8 +702,6 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } - - voice->IsHrtf = AL_FALSE; } } @@ -1064,6 +1070,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); BsincPrepare(voice->Step, &voice->ResampleState.bsinc); + voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC); if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render to the @@ -1115,7 +1122,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } - voice->IsHrtf = AL_TRUE; + voice->Flags |= VOICE_IS_HRTF; } else { @@ -1128,10 +1135,49 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro /* Get the localized direction, and compute panned gains. */ if(Distance > FLT_EPSILON) { + if(Device->AvgSpeakerDist > 0.0f && MetersPerUnit > 0.0f) + { + ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / + (Distance*MetersPerUnit * (ALfloat)Device->Frequency); + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + /* Clamp w0 for really close distances, to prevent excessive + * bass. + */ + w0 = minf(w0, w1*4.0f); + + NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); + NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); + NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + dir[0] = -SourceToListener.v[0]; dir[1] = -SourceToListener.v[1]; dir[2] = -SourceToListener.v[2] * ZScale; } + else if(Device->AvgSpeakerDist > 0.0f) + { + /* If the source distance is 0, set w0 to w1 to act as a pass- + * through. We still want to pass the signal through the filters so + * they keep an appropriate history, in case the source moves away + * from the listener. + */ + ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + + NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); + NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); + NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + if(radius > Distance) spread = F_TAU - Distance/radius*F_PI; else if(Distance > FLT_EPSILON) @@ -1160,8 +1206,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } - - voice->IsHrtf = AL_FALSE; } { diff --git a/Alc/mixer.c b/Alc/mixer.c index 1c503a92..961c8f31 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -545,15 +545,60 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei &parms->LowPass, &parms->HighPass, Device->FilteredData, ResampledData, DstBufferSize, parms->FilterType ); - if(!voice->IsHrtf) + if(!(voice->Flags&VOICE_IS_HRTF)) { if(!Counter) memcpy(parms->Gains.Current, parms->Gains.Target, sizeof(parms->Gains.Current)); - MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); + if(!(voice->Flags&VOICE_HAS_NFC)) + MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + else + { + ALfloat *nfcsamples = Device->NFCtrlData; + ALsizei chanoffset = 0; + MixSamples(samples, + voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[0]; + if(voice->Direct.ChannelsPerOrder[1] > 0) + { + NfcFilterUpdate1(&parms->NFCtrlFilter[0], nfcsamples, samples, + DstBufferSize); + MixSamples(nfcsamples, + voice->Direct.ChannelsPerOrder[1], voice->Direct.Buffer+chanoffset, + parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, + Counter, OutPos, DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[1]; + } + if(voice->Direct.ChannelsPerOrder[2] > 0) + { + NfcFilterUpdate2(&parms->NFCtrlFilter[1], nfcsamples, samples, + DstBufferSize); + MixSamples(nfcsamples, + voice->Direct.ChannelsPerOrder[2], voice->Direct.Buffer+chanoffset, + parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, + Counter, OutPos, DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[2]; + } + if(voice->Direct.ChannelsPerOrder[3] > 0) + { + NfcFilterUpdate3(&parms->NFCtrlFilter[2], nfcsamples, samples, + DstBufferSize); + MixSamples(nfcsamples, + voice->Direct.ChannelsPerOrder[3], voice->Direct.Buffer+chanoffset, + parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, + Counter, OutPos, DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[3]; + } + } } else { diff --git a/Alc/panning.c b/Alc/panning.c index c4d3e43f..6315328a 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -487,6 +487,88 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, }; +static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, bool periphonic) +{ + const char *devname = al_string_get_cstr(device->DeviceName); + ALsizei i; + + if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) + { + /* NFC is only used when AvgSpeakerDist is greater than 0, and + * METERS_PER_UNIT is also greater than 0. In addition, NFC can only be + * used when rendering to an ambisonic buffer. + */ + device->AvgSpeakerDist = ctrl_dist; + + device->Dry.NumChannelsPerOrder[0] = 1; + if(periphonic) + for(i = 1;i < order+1;i++) + device->Dry.NumChannelsPerOrder[i] = (i+1)*(i+1) - i*i; + else + for(i = 1;i < order+1;i++) + device->Dry.NumChannelsPerOrder[i] = (i*2+1) - ((i-1)*2+1); + for(;i < MAX_AMBI_ORDER+1;i++) + device->Dry.NumChannelsPerOrder[i] = 0; + } +} + +static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) +{ + const char *devname = al_string_get_cstr(device->DeviceName); + ALfloat maxdist = 0.0f; + ALsizei total = 0; + ALsizei i; + + for(i = 0;i < conf->NumSpeakers;i++) + maxdist = maxf(maxdist, conf->Speakers[i].Distance); + + if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) + { + ALfloat srate = (ALfloat)device->Frequency; + for(i = 0;i < conf->NumSpeakers;i++) + { + ALsizei chan = speakermap[i]; + ALfloat delay; + + /* Distance compensation only delays in steps of the sample rate. + * This is a bit less accurate since the delay time falls to the + * nearest sample time, but it's far simpler as it doesn't have to + * deal with phase offsets. This means at 48khz, for instance, the + * distance delay will be in steps of about 7 millimeters. + */ + delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * + srate + 0.5f); + if(delay >= (ALfloat)MAX_DELAY_LENGTH) + ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", + al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + + device->ChannelDelay[chan].Length = (ALsizei)clampf( + delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) + ); + device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; + TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, + al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + device->ChannelDelay[chan].Gain + ); + + /* Round up to the next 4th sample, so each channel buffer starts + * 16-byte aligned. + */ + total += RoundUp(device->ChannelDelay[chan].Length, 4); + } + } + + if(total > 0) + { + device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat)); + for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) + { + size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); + device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; + } + } +} + static void InitPanning(ALCdevice *device) { const ChannelMap *chanmap = NULL; @@ -546,10 +628,12 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { + const char *devname = al_string_get_cstr(device->DeviceName); const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : /*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale; + ALfloat nfc_delay = 0.0f; count = (device->FmtChans == DevFmtAmbi3) ? 16 : (device->FmtChans == DevFmtAmbi2) ? 9 : @@ -585,6 +669,16 @@ static void InitPanning(ALCdevice *device) ambiup_reset(device->AmbiUp, device); } + + if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay)) + { + nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); + InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, + (device->FmtChans == DevFmtAmbi3) ? 3 : + (device->FmtChans == DevFmtAmbi2) ? 2 : 1, + true + ); + } } else { @@ -612,63 +706,6 @@ static void InitPanning(ALCdevice *device) device->RealOut.NumChannels = 0; } -static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) -{ - const char *devname = al_string_get_cstr(device->DeviceName); - ALfloat maxdist = 0.0f; - ALsizei total = 0; - ALsizei i; - - for(i = 0;i < conf->NumSpeakers;i++) - maxdist = maxf(maxdist, conf->Speakers[i].Distance); - - if(GetConfigValueBool(devname, "decoder", "distance-comp", 1) && maxdist > 0.0f) - { - ALfloat srate = (ALfloat)device->Frequency; - for(i = 0;i < conf->NumSpeakers;i++) - { - ALsizei chan = speakermap[i]; - ALfloat delay; - - /* Distance compensation only delays in steps of the sample rate. - * This is a bit less accurate since the delay time falls to the - * nearest sample time, but it's far simpler as it doesn't have to - * deal with phase offsets. This means at 48khz, for instance, the - * distance delay will be in steps of about 7 millimeters. - */ - delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC * - srate + 0.5f); - if(delay >= (ALfloat)MAX_DELAY_LENGTH) - ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); - - device->ChannelDelay[chan].Length = (ALsizei)clampf( - delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) - ); - device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; - TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, - device->ChannelDelay[chan].Gain - ); - - /* Round up to the next 4th sample, so each channel buffer starts - * 16-byte aligned. - */ - total += RoundUp(device->ChannelDelay[chan].Length, 4); - } - } - - if(total > 0) - { - device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat)); - for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) - { - size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); - device->ChannelDelay[i].Buffer = device->ChannelDelay[i-1].Buffer + len; - } - } -} - static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; @@ -756,8 +793,9 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - size_t count; - size_t i; + ALfloat avg_dist; + ALsizei count; + ALsizei i; if((conf->ChanMask&AMBI_PERIPHONIC_MASK)) { @@ -825,6 +863,15 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + avg_dist = 0.0f; + for(i = 0;i < conf->NumSpeakers;i++) + avg_dist += conf->Speakers[i].Distance; + avg_dist /= (ALfloat)conf->NumSpeakers; + InitNearFieldCtrl(device, avg_dist, + (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, + !!(conf->ChanMask&AMBI_PERIPHONIC_MASK) + ); + InitDistanceComp(device, conf, speakermap); } @@ -879,8 +926,8 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) { { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, }; const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA; - size_t count = hoa_mode ? 9 : 4; - size_t i; + ALsizei count = hoa_mode ? 9 : 4; + ALsizei i; static_assert(9 <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); @@ -960,7 +1007,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + device->Dry.NumChannelsPerOrder[i] = 0; + device->AvgSpeakerDist = 0.0f; memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index cc30dcef..e4c5b94a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -726,6 +726,7 @@ struct ALCdevice_struct alignas(16) ALfloat SourceData[BUFFERSIZE]; alignas(16) ALfloat ResampledData[BUFFERSIZE]; alignas(16) ALfloat FilteredData[BUFFERSIZE]; + alignas(16) ALfloat NFCtrlData[BUFFERSIZE]; /* The "dry" path corresponds to the main output. */ struct { @@ -738,6 +739,7 @@ struct ALCdevice_struct ALfloat (*Buffer)[BUFFERSIZE]; ALsizei NumChannels; + ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; } Dry; /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ @@ -760,6 +762,11 @@ struct ALCdevice_struct ALsizei NumChannels; } RealOut; + /* The average speaker distance as determined by the ambdec configuration + * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. + */ + ALfloat AvgSpeakerDist; + /* Delay buffers used to compensate for speaker distances. */ DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 03f0090d..6c374ebc 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -17,6 +17,7 @@ #include "hrtf.h" #include "align.h" +#include "nfcfilter.h" #include "math_defs.h" @@ -129,6 +130,8 @@ typedef struct DirectParams { ALfilterState LowPass; ALfilterState HighPass; + NfcFilter NFCtrlFilter[MAX_AMBI_ORDER]; + struct { HrtfParams Current; HrtfParams Target; @@ -152,6 +155,9 @@ typedef struct SendParams { } Gains; } SendParams; +#define VOICE_IS_HRTF (1<<0) +#define VOICE_HAS_NFC (1<<1) + typedef struct ALvoice { struct ALsourceProps *Props; @@ -182,7 +188,7 @@ typedef struct ALvoice { /* If not 'moving', gain/coefficients are set directly without fading. */ ALboolean Moving; - ALboolean IsHrtf; + ALuint Flags; ALuint Offset; /* Number of output samples mixed since starting. */ @@ -195,6 +201,7 @@ typedef struct ALvoice { ALfloat (*Buffer)[BUFFERSIZE]; ALsizei Channels; + ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1]; } Direct; struct { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c4c0bfb1..55a4aae1 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3084,6 +3084,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Step = 0; voice->Moving = AL_FALSE; + voice->Flags = 0; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { ALsizei j; @@ -3095,6 +3096,17 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f; } } + if(device->AvgSpeakerDist > 0.0f) + { + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(i = 0;i < voice->NumChannels;i++) + { + NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1); + NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1); + NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1); + } + } ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); -- cgit v1.2.3 From b878769ee0ea36fc5f0b855edc9017166570186f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 10 Mar 2017 04:59:22 -0800 Subject: Fix building without C11 --- Alc/ALc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index beec0c32..da56fa65 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2313,7 +2313,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(pos = 0;pos < context->VoiceCount;pos++) { ALvoice *voice = context->Voices[pos]; - if(!voice->Source) continue; + if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == NULL) + continue; if(device->AvgSpeakerDist > 0.0f) { -- cgit v1.2.3 From 51cb969446baad21d688a26e01b01c383c63c660 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 10 Mar 2017 05:05:25 -0800 Subject: Fix building on MSVC --- Alc/nfcfilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/nfcfilter.c b/Alc/nfcfilter.c index c27ea705..21957975 100644 --- a/Alc/nfcfilter.c +++ b/Alc/nfcfilter.c @@ -45,7 +45,7 @@ */ static const float B[4][3] = { - { }, + { 0.0f }, { 1.0f }, { 3.0f, 3.0f }, { 3.6778f, 6.4595f, 2.3222f }, -- cgit v1.2.3 From 6b4b00e4625139157996bcf2161ec8688a4b11e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 10 Mar 2017 10:47:43 -0800 Subject: Dynamically allocate the device's HRTF state --- Alc/ALc.c | 79 +++++++++++++++++++++++++---------------------- Alc/ALu.c | 17 +++++----- Alc/mixer.c | 2 +- Alc/panning.c | 55 +++++++++++++++++---------------- OpenAL32/Include/alMain.h | 27 ++++++++-------- 5 files changed, 94 insertions(+), 86 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index da56fa65..ce04aa17 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2071,7 +2071,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) /************************************************************************* * Update device format request if HRTF is requested */ - device->Hrtf.Status = ALC_HRTF_DISABLED_SOFT; + device->HrtfStatus = ALC_HRTF_DISABLED_SOFT; if(device->Type != Loopback) { const char *hrtf; @@ -2087,31 +2087,31 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { - if(VECTOR_SIZE(device->Hrtf.List) == 0) + if(VECTOR_SIZE(device->HrtfList) == 0) { - VECTOR_DEINIT(device->Hrtf.List); - device->Hrtf.List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); } - if(VECTOR_SIZE(device->Hrtf.List) > 0) + if(VECTOR_SIZE(device->HrtfList) > 0) { device->FmtChans = DevFmtStereo; - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf.List)) - device->Frequency = VECTOR_ELEM(device->Hrtf.List, hrtf_id).hrtf->sampleRate; + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) + device->Frequency = VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf->sampleRate; else - device->Frequency = VECTOR_ELEM(device->Hrtf.List, 0).hrtf->sampleRate; + device->Frequency = VECTOR_ELEM(device->HrtfList, 0).hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; } else { hrtf_userreq = Hrtf_Default; hrtf_appreq = Hrtf_Disable; - device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } } else if(hrtf_appreq == Hrtf_Enable) { - size_t i = VECTOR_SIZE(device->Hrtf.List); + size_t i = VECTOR_SIZE(device->HrtfList); /* Loopback device. We don't need to match to a specific HRTF entry * here. If the requested ID matches, we'll pick that later, if not, * we'll try to auto-select one anyway. Just make sure one exists @@ -2119,24 +2119,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ if(device->FmtChans == DevFmtStereo) { - if(VECTOR_SIZE(device->Hrtf.List) == 0) + if(VECTOR_SIZE(device->HrtfList) == 0) { - VECTOR_DEINIT(device->Hrtf.List); - device->Hrtf.List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); } - for(i = 0;i < VECTOR_SIZE(device->Hrtf.List);i++) + for(i = 0;i < VECTOR_SIZE(device->HrtfList);i++) { - const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf.List, i).hrtf; + const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, i).hrtf; if(hrtf->sampleRate == device->Frequency) break; } } - if(i == VECTOR_SIZE(device->Hrtf.List)) + if(i == VECTOR_SIZE(device->HrtfList)) { ERR("Requested format not HRTF compatible: %s, %uhz\n", DevFmtChannelsString(device->FmtChans), device->Frequency); hrtf_appreq = Hrtf_Disable; - device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } @@ -2398,8 +2398,10 @@ static ALCvoid FreeDevice(ALCdevice *device) } ResetUIntMap(&device->FilterMap); - AL_STRING_DEINIT(device->Hrtf.Name); - FreeHrtfList(&device->Hrtf.List); + AL_STRING_DEINIT(device->HrtfName); + FreeHrtfList(&device->HrtfList); + al_free(device->Hrtf); + device->Hrtf = NULL; al_free(device->Bs2b); device->Bs2b = NULL; @@ -2964,7 +2966,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { almtx_lock(&Device->BackendLock); - value = (Device->Hrtf.Handle ? al_string_get_cstr(Device->Hrtf.Name) : ""); + value = (Device->HrtfHandle ? al_string_get_cstr(Device->HrtfName) : ""); almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } @@ -3133,10 +3135,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = device->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); + values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->Hrtf.Status; + values[i++] = device->HrtfStatus; almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -3234,18 +3236,18 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_HRTF_SOFT: - values[0] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); + values[0] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); return 1; case ALC_HRTF_STATUS_SOFT: - values[0] = device->Hrtf.Status; + values[0] = device->HrtfStatus; return 1; case ALC_NUM_HRTF_SPECIFIERS_SOFT: almtx_lock(&device->BackendLock); - FreeHrtfList(&device->Hrtf.List); - device->Hrtf.List = EnumerateHrtf(device->DeviceName); - values[0] = (ALCint)VECTOR_SIZE(device->Hrtf.List); + FreeHrtfList(&device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); + values[0] = (ALCint)VECTOR_SIZE(device->HrtfList); almtx_unlock(&device->BackendLock); return 1; @@ -3336,10 +3338,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = device->NumAuxSends; values[i++] = ALC_HRTF_SOFT; - values[i++] = (device->Hrtf.Handle ? ALC_TRUE : ALC_FALSE); + values[i++] = (device->HrtfHandle ? ALC_TRUE : ALC_FALSE); values[i++] = ALC_HRTF_STATUS_SOFT; - values[i++] = device->Hrtf.Status; + values[i++] = device->HrtfStatus; clock = V0(device->Backend,getClockLatency)(); values[i++] = ALC_DEVICE_CLOCK_SOFT; @@ -3764,8 +3766,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Flags = 0; device->Bs2b = NULL; device->Uhj_Encoder = NULL; - VECTOR_INIT(device->Hrtf.List); - AL_STRING_INIT(device->Hrtf.Name); + device->Hrtf = NULL; + VECTOR_INIT(device->HrtfList); + AL_STRING_INIT(device->HrtfName); device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; @@ -4070,8 +4073,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Connected = ALC_TRUE; device->Type = Capture; - VECTOR_INIT(device->Hrtf.List); - AL_STRING_INIT(device->Hrtf.Name); + device->Hrtf = NULL; + VECTOR_INIT(device->HrtfList); + AL_STRING_INIT(device->HrtfName); AL_STRING_INIT(device->DeviceName); device->Dry.Buffer = NULL; @@ -4279,8 +4283,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); device->Flags = 0; - VECTOR_INIT(device->Hrtf.List); - AL_STRING_INIT(device->Hrtf.Name); + device->Hrtf = NULL; + VECTOR_INIT(device->HrtfList); + AL_STRING_INIT(device->HrtfName); device->Bs2b = NULL; device->Uhj_Encoder = NULL; device->Render_Mode = NormalRender; @@ -4501,8 +4506,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum else switch(paramName) { case ALC_HRTF_SPECIFIER_SOFT: - if(index >= 0 && (size_t)index < VECTOR_SIZE(device->Hrtf.List)) - str = al_string_get_cstr(VECTOR_ELEM(device->Hrtf.List, index).name); + if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) + str = al_string_get_cstr(VECTOR_ELEM(device->HrtfList, index).name); else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/ALu.c b/Alc/ALu.c index 90ca8ab1..91f90efc 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -633,7 +633,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } /* Get the static HRIR coefficients and delays for this channel. */ - GetHrtfCoeffs(Device->Hrtf.Handle, + GetHrtfCoeffs(Device->HrtfHandle, chans[c].elevation, chans[c].angle, 0.0f, DryGain, voice->Direct.Params[c].Hrtf.Target.Coeffs, voice->Direct.Params[c].Hrtf.Target.Delay @@ -1104,7 +1104,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro spread = asinf(radius / Distance) * 2.0f; /* Get the HRIR coefficients and delays. */ - GetHrtfCoeffs(Device->Hrtf.Handle, ev, az, spread, DryGain, + GetHrtfCoeffs(Device->HrtfHandle, ev, az, spread, DryGain, voice->Direct.Params[0].Hrtf.Target.Coeffs, voice->Direct.Params[0].Hrtf.Target.Delay); @@ -1482,10 +1482,10 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->SamplesDone %= device->Frequency; IncrementRef(&device->MixCount); - if(device->Hrtf.Handle) + if(device->HrtfHandle) { HrtfDirectMixerFunc HrtfMix; - ALsizei irsize; + DirectHrtfState *state; int lidx, ridx; if(device->AmbiUp) @@ -1499,16 +1499,15 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) assert(lidx != -1 && ridx != -1); HrtfMix = SelectHrtfMixer(); - irsize = device->Hrtf.IrSize; + state = device->Hrtf; for(c = 0;c < device->Dry.NumChannels;c++) { HrtfMix(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer[c], device->Hrtf.Offset, irsize, - device->Hrtf.Coeffs[c], device->Hrtf.Values[c], - SamplesToDo + device->Dry.Buffer[c], state->Offset, state->IrSize, + state->Coeffs[c], state->Values[c], SamplesToDo ); } - device->Hrtf.Offset += SamplesToDo; + state->Offset += SamplesToDo; } else if(device->AmbiDecoder) { diff --git a/Alc/mixer.c b/Alc/mixer.c index 961c8f31..a189e5e3 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -393,7 +393,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SampleSize = voice->SampleSize; increment = voice->Step; - IrSize = (Device->Hrtf.Handle ? Device->Hrtf.Handle->irSize : 0); + IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : ResampleSamples); diff --git a/Alc/panning.c b/Alc/panning.c index 6315328a..728001c2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -929,7 +929,7 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) ALsizei count = hoa_mode ? 9 : 4; ALsizei i; - static_assert(9 <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); + static_assert(9 <= COUNTOF(device->Hrtf->Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); for(i = 0;i < count;i++) @@ -962,14 +962,14 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); - memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs)); - device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle, - device->Hrtf.Coeffs, device->Dry.NumChannels, + memset(device->Hrtf->Coeffs, 0, sizeof(device->Hrtf->Coeffs)); + device->Hrtf->IrSize = BuildBFormatHrtf(device->HrtfHandle, + device->Hrtf->Coeffs, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints) ); /* Round up to the nearest multiple of 8 */ - device->Hrtf.IrSize = (device->Hrtf.IrSize+7)&~7; + device->Hrtf->IrSize = (device->Hrtf->IrSize+7)&~7; } static void InitUhjPanning(ALCdevice *device) @@ -1000,8 +1000,10 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf int bs2blevel; size_t i; - device->Hrtf.Handle = NULL; - al_string_clear(&device->Hrtf.Name); + al_free(device->Hrtf); + device->Hrtf = NULL; + device->HrtfHandle = NULL; + al_string_clear(&device->HrtfName); device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); @@ -1025,7 +1027,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf AmbDecConf conf, *pconf = NULL; if(hrtf_appreq == Hrtf_Enable) - device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; ambdec_init(&conf); @@ -1123,48 +1125,48 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf (hrtf_appreq == Hrtf_Enable); if(!usehrtf) goto no_hrtf; - device->Hrtf.Status = ALC_HRTF_ENABLED_SOFT; + device->HrtfStatus = ALC_HRTF_ENABLED_SOFT; if(headphones && hrtf_appreq != Hrtf_Disable) - device->Hrtf.Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + device->HrtfStatus = ALC_HRTF_HEADPHONES_DETECTED_SOFT; } else { if(hrtf_userreq != Hrtf_Enable) { if(hrtf_appreq == Hrtf_Enable) - device->Hrtf.Status = ALC_HRTF_DENIED_SOFT; + device->HrtfStatus = ALC_HRTF_DENIED_SOFT; goto no_hrtf; } - device->Hrtf.Status = ALC_HRTF_REQUIRED_SOFT; + device->HrtfStatus = ALC_HRTF_REQUIRED_SOFT; } - if(VECTOR_SIZE(device->Hrtf.List) == 0) + if(VECTOR_SIZE(device->HrtfList) == 0) { - VECTOR_DEINIT(device->Hrtf.List); - device->Hrtf.List = EnumerateHrtf(device->DeviceName); + VECTOR_DEINIT(device->HrtfList); + device->HrtfList = EnumerateHrtf(device->DeviceName); } - if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf.List)) + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, hrtf_id); + const HrtfEntry *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); if(entry->hrtf->sampleRate == device->Frequency) { - device->Hrtf.Handle = entry->hrtf; - al_string_copy(&device->Hrtf.Name, entry->name); + device->HrtfHandle = entry->hrtf; + al_string_copy(&device->HrtfName, entry->name); } } - for(i = 0;!device->Hrtf.Handle && i < VECTOR_SIZE(device->Hrtf.List);i++) + for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) { - const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, i); + const HrtfEntry *entry = &VECTOR_ELEM(device->HrtfList, i); if(entry->hrtf->sampleRate == device->Frequency) { - device->Hrtf.Handle = entry->hrtf; - al_string_copy(&device->Hrtf.Name, entry->name); + device->HrtfHandle = entry->hrtf; + al_string_copy(&device->HrtfName, entry->name); } } - if(device->Hrtf.Handle) + if(device->HrtfHandle) { bool hoa_mode; @@ -1194,15 +1196,16 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->AmbiUp = ambiup_alloc(); hoa_mode = true; } + device->Hrtf = al_calloc(16, sizeof(device->Hrtf[0])); TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), - al_string_get_cstr(device->Hrtf.Name) + al_string_get_cstr(device->HrtfName) ); InitHrtfPanning(device, hoa_mode); return; } - device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; no_hrtf: TRACE("HRTF disabled\n"); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e4c5b94a..b2e1bfcf 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -622,6 +622,14 @@ typedef struct HrtfParams { ALsizei Delay[2]; } HrtfParams; +typedef struct DirectHrtfState { + /* HRTF filter state for dry buffer content */ + alignas(16) ALfloat Values[9][HRIR_LENGTH][2]; + alignas(16) ALfloat Coeffs[9][HRIR_LENGTH][2]; + ALsizei Offset; + ALsizei IrSize; +} DirectHrtfState; + typedef struct HrtfEntry { al_string name; @@ -687,19 +695,12 @@ struct ALCdevice_struct // Map of Filters for this device UIntMap FilterMap; - /* HRTF filter tables */ - struct { - vector_HrtfEntry List; - al_string Name; - ALCenum Status; - const struct Hrtf *Handle; - - /* HRTF filter state for dry buffer content */ - alignas(16) ALfloat Values[9][HRIR_LENGTH][2]; - alignas(16) ALfloat Coeffs[9][HRIR_LENGTH][2]; - ALsizei Offset; - ALsizei IrSize; - } Hrtf; + /* HRTF state and info */ + DirectHrtfState *Hrtf; + al_string HrtfName; + const struct Hrtf *HrtfHandle; + vector_HrtfEntry HrtfList; + ALCenum HrtfStatus; /* UHJ encoder state */ struct Uhj2Encoder *Uhj_Encoder; -- cgit v1.2.3 From 98e8f941b773df0b591e7c6c6c0e3b5096a9b4f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 11 Mar 2017 06:20:04 -0800 Subject: Allocate as many channels for DirectHrtfState as needed --- Alc/ALu.c | 2 +- Alc/hrtf.c | 6 +++--- Alc/hrtf.h | 2 +- Alc/panning.c | 9 +++++---- OpenAL32/Include/alMain.h | 6 ++++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 91f90efc..aff87895 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1504,7 +1504,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { HrtfMix(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer[c], state->Offset, state->IrSize, - state->Coeffs[c], state->Values[c], SamplesToDo + state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo ); } state->Offset += SamplesToDo; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d79168e1..e1c1d7b3 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -136,7 +136,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount) +ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount) { /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -206,7 +206,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] { ALsizei k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][0] += temps[b][k++] * AmbiMatrix[c][b][i]; + state->Chan[i].Coeffs[j][0] += temps[b][k++] * AmbiMatrix[c][b][i]; } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -235,7 +235,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH] { ALuint k = 0; for(j = delay;j < HRIR_LENGTH;++j) - coeffs[i][j][1] += temps[b][k++] * AmbiMatrix[c][b][i]; + state->Chan[i].Coeffs[j][1] += temps[b][k++] * AmbiMatrix[c][b][i]; } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 83cc64d1..7552452b 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -44,6 +44,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * returned coefficients are ordered and scaled according to the matrices. * Returns the maximum impulse-response length of the generated coefficients. */ -ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount); +ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 728001c2..0ff58c3a 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -927,11 +927,14 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) }; const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA; ALsizei count = hoa_mode ? 9 : 4; + size_t sizeof_hrtfstate; ALsizei i; - static_assert(9 <= COUNTOF(device->Hrtf->Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small"); static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); + sizeof_hrtfstate = offsetof(DirectHrtfState, Chan[count]); + device->Hrtf = al_calloc(16, sizeof_hrtfstate); + for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; @@ -962,9 +965,8 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); - memset(device->Hrtf->Coeffs, 0, sizeof(device->Hrtf->Coeffs)); device->Hrtf->IrSize = BuildBFormatHrtf(device->HrtfHandle, - device->Hrtf->Coeffs, device->Dry.NumChannels, + device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints) ); @@ -1196,7 +1198,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->AmbiUp = ambiup_alloc(); hoa_mode = true; } - device->Hrtf = al_calloc(16, sizeof(device->Hrtf[0])); TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b2e1bfcf..04fb7239 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -624,10 +624,12 @@ typedef struct HrtfParams { typedef struct DirectHrtfState { /* HRTF filter state for dry buffer content */ - alignas(16) ALfloat Values[9][HRIR_LENGTH][2]; - alignas(16) ALfloat Coeffs[9][HRIR_LENGTH][2]; ALsizei Offset; ALsizei IrSize; + struct { + alignas(16) ALfloat Values[HRIR_LENGTH][2]; + alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; + } Chan[]; } DirectHrtfState; typedef struct HrtfEntry { -- cgit v1.2.3 From feffe1e81a155ded0bcdb519a1a126fd8e908baa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 11 Mar 2017 06:26:05 -0800 Subject: Make the voice's 'moving' state a bitflag --- Alc/mixer.c | 4 ++-- OpenAL32/Include/alu.h | 9 ++++----- OpenAL32/alSource.c | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index a189e5e3..d8adb697 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -398,7 +398,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : ResampleSamples); - Counter = voice->Moving ? SamplesToDo : 0; + Counter = (voice->Flags&VOICE_IS_MOVING) ? SamplesToDo : 0; OutPos = 0; do { ALsizei SrcBufferSize, DstBufferSize; @@ -723,7 +723,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } } while(State == AL_PLAYING && OutPos < SamplesToDo); - voice->Moving = AL_TRUE; + voice->Flags |= VOICE_IS_MOVING; /* Update source info */ ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6c374ebc..8888bdc0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -155,8 +155,10 @@ typedef struct SendParams { } Gains; } SendParams; -#define VOICE_IS_HRTF (1<<0) -#define VOICE_HAS_NFC (1<<1) +/* If not 'moving', gain targets are used directly without fading. */ +#define VOICE_IS_MOVING (1<<0) +#define VOICE_IS_HRTF (1<<1) +#define VOICE_HAS_NFC (1<<2) typedef struct ALvoice { struct ALsourceProps *Props; @@ -185,9 +187,6 @@ typedef struct ALvoice { /** Current target parameters used for mixing. */ ALint Step; - /* If not 'moving', gain/coefficients are set directly without fading. */ - ALboolean Moving; - ALuint Flags; ALuint Offset; /* Number of output samples mixed since starting. */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 55a4aae1..a36231b5 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3034,7 +3034,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) * volume last specified; there's no reason to fade from where * it stopped at. */ - voice->Moving = AL_FALSE; + voice->Flags &= ~VOICE_IS_MOVING; ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); goto done; @@ -3083,7 +3083,6 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) */ voice->Step = 0; - voice->Moving = AL_FALSE; voice->Flags = 0; for(i = 0;i < MAX_INPUT_CHANNELS;i++) { -- cgit v1.2.3 From 96aaab93662be289d3b2c5312ae50502afa8d221 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 11 Mar 2017 18:04:06 -0800 Subject: Rework HRTF coefficient fading This improves fading between HRIRs as sources pan around. In particular, it improves the issue with individual coefficients having various rounding errors in the stepping values, as well as issues with interpolating delay values. It does this by doing two mixing passes for each source. First using the last coefficients that fade to silence, and then again using the new coefficients that fade from silence. When added together, it creates a linear fade from one to the other. Additionally, the gain is applied separately so the individual coefficients don't step with rounding errors. Although this does increase CPU cost since it's doing two mixes per source, each mix is a bit cheaper now since the stepping is simplified to a single gain value, and the overall quality is improved. --- Alc/ALu.c | 10 ++++-- Alc/hrtf.c | 38 ++++++--------------- Alc/hrtf.h | 2 +- Alc/mixer.c | 87 ++++++++++++++++++++++++++++------------------- Alc/mixer_c.c | 19 +---------- Alc/mixer_defs.h | 18 +++++----- Alc/mixer_inc.c | 81 +++++++------------------------------------ Alc/mixer_neon.c | 37 +------------------- Alc/mixer_sse.c | 67 +----------------------------------- OpenAL32/Include/alMain.h | 1 + OpenAL32/Include/alu.h | 19 +++++------ 11 files changed, 105 insertions(+), 274 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index aff87895..55f0c09a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -634,10 +634,11 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * /* Get the static HRIR coefficients and delays for this channel. */ GetHrtfCoeffs(Device->HrtfHandle, - chans[c].elevation, chans[c].angle, 0.0f, DryGain, + chans[c].elevation, chans[c].angle, 0.0f, voice->Direct.Params[c].Hrtf.Target.Coeffs, voice->Direct.Params[c].Hrtf.Target.Delay ); + voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; /* Normal panning for auxiliary sends. */ CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); @@ -1104,9 +1105,10 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro spread = asinf(radius / Distance) * 2.0f; /* Get the HRIR coefficients and delays. */ - GetHrtfCoeffs(Device->HrtfHandle, ev, az, spread, DryGain, + GetHrtfCoeffs(Device->HrtfHandle, ev, az, spread, voice->Direct.Params[0].Hrtf.Target.Coeffs, voice->Direct.Params[0].Hrtf.Target.Delay); + voice->Direct.Params[0].Hrtf.Target.Gain = DryGain; CalcDirectionCoeffs(dir, spread, coeffs); @@ -1502,9 +1504,11 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) state = device->Hrtf; for(c = 0;c < device->Dry.NumChannels;c++) { + typedef ALfloat ALfloat2[2]; HrtfMix(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer[c], state->Offset, state->IrSize, - state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo + SAFE_CONST(ALfloat2*,state->Chan[c].Coeffs), + state->Chan[c].Values, SamplesToDo ); } state->Offset += SamplesToDo; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index e1c1d7b3..91895cb9 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -77,10 +77,9 @@ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az) } /* Calculates static HRIR coefficients and delays for the given polar elevation - * and azimuth in radians. The coefficients are normalized and attenuated by - * the specified gain. + * and azimuth in radians. The coefficients are normalized. */ -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALsizei *delays) +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays) { ALsizei evidx, azidx, lidx, ridx; ALsizei azcount, evoffset; @@ -102,36 +101,21 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ridx = evoffset + ((azcount-azidx) % azcount); /* Calculate the HRIR delays. */ - delays[0] = fastf2i(Hrtf->delays[lidx]*dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2i(Hrtf->delays[ridx]*dirfact + 0.5f) << HRTFDELAY_BITS; + delays[0] = fastf2i(Hrtf->delays[lidx]*dirfact + 0.5f); + delays[1] = fastf2i(Hrtf->delays[ridx]*dirfact + 0.5f); /* Calculate the sample offsets for the HRIR indices. */ lidx *= Hrtf->irSize; ridx *= Hrtf->irSize; - /* Calculate the normalized and attenuated HRIR coefficients. Zero the - * coefficients if gain is too low. - */ - if(gain > 0.0001f) - { - gain /= 32767.0f; - - i = 0; - coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact)*gain; - coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact)*gain; - for(i = 1;i < Hrtf->irSize;i++) - { - coeffs[i][0] = Hrtf->coeffs[lidx+i]*gain * dirfact; - coeffs[i][1] = Hrtf->coeffs[ridx+i]*gain * dirfact; - } - } - else + /* Calculate the normalized and attenuated HRIR coefficients. */ + i = 0; + coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact) * (1.0f/32767.0f); + coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact) * (1.0f/32767.0f); + for(i = 1;i < Hrtf->irSize;i++) { - for(i = 0;i < Hrtf->irSize;i++) - { - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - } + coeffs[i][0] = Hrtf->coeffs[lidx+i]*(1.0f/32767.0f) * dirfact; + coeffs[i][1] = Hrtf->coeffs[ridx+i]*(1.0f/32767.0f) * dirfact; } } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 7552452b..7391131f 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -36,7 +36,7 @@ void FreeHrtfs(void); vector_HrtfEntry EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_HrtfEntry *list); -void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALsizei *delays); +void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays); /** * Produces HRTF filter coefficients for decoding B-Format, given a set of diff --git a/Alc/mixer.c b/Alc/mixer.c index d8adb697..67e74396 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -380,7 +380,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALint64 DataSize64; ALsizei Counter; ALsizei IrSize; - ALsizei chan, j; + ALsizei chan; ALsizei send; /* Get source info */ @@ -605,46 +605,63 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei MixHrtfParams hrtfparams; int lidx, ridx; + lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(Device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + if(!Counter) { - parms->Hrtf.Current = parms->Hrtf.Target; - for(j = 0;j < HRIR_LENGTH;j++) - { - hrtfparams.Steps.Coeffs[j][0] = 0.0f; - hrtfparams.Steps.Coeffs[j][1] = 0.0f; - } - hrtfparams.Steps.Delay[0] = 0; - hrtfparams.Steps.Delay[1] = 0; + parms->Hrtf.Old = parms->Hrtf.Target; + hrtfparams.Current = &parms->Hrtf.Target; + hrtfparams.Gain = parms->Hrtf.Target.Gain; + hrtfparams.GainStep = 0.0f; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf.State, DstBufferSize + ); } else { - ALfloat delta = 1.0f / (ALfloat)Counter; - ALfloat coeffdiff; - ALint delaydiff; - for(j = 0;j < IrSize;j++) - { - coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; - hrtfparams.Steps.Coeffs[j][0] = coeffdiff * delta; - coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1]; - hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta; - } - delaydiff = parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]; - hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta); - delaydiff = parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]; - hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta); - } - hrtfparams.Target = &parms->Hrtf.Target; - hrtfparams.Current = &parms->Hrtf.Current; - - lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(Device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); + HrtfState backupstate = parms->Hrtf.State; + ALfloat gain; + + /* The old coefficients need to fade to silence + * completely since they'll be replaced after the mix. + * So it needs to fade out over DstBufferSize instead + * of Counter. + */ + hrtfparams.Current = &parms->Hrtf.Old; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = -hrtfparams.Gain / + (ALfloat)DstBufferSize; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &backupstate, DstBufferSize + ); - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, DstBufferSize - ); + /* The new coefficients need to fade in completely + * since they're replacing the old ones. To keep the + * source gain fading consistent, interpolate between + * the old and new target gain given how much of the + * fade time this mix handles. + */ + gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + minf(1.0f, (ALfloat)Counter / (ALfloat)DstBufferSize)); + hrtfparams.Current = &parms->Hrtf.Target; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / (ALfloat)DstBufferSize; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf.State, DstBufferSize + ); + /* Update the old parameters with the result. */ + parms->Hrtf.Old = parms->Hrtf.Target; + if(Counter > DstBufferSize) + parms->Hrtf.Old.Gain = hrtfparams.Gain; + } } } diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index a3d79a46..bb945e88 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -132,26 +132,9 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const } -static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - ALsizei c; - for(c = 0;c < IrSize;c++) - { - const ALsizei 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(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { ALsizei c; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index b76c9aee..d4a49b53 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -21,12 +21,12 @@ const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restr /* C mixers */ void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, @@ -37,12 +37,12 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, /* SSE mixers */ void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, @@ -86,12 +86,12 @@ const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *res /* Neon mixers */ void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const struct MixHrtfParams *hrtfparams, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize); void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index 8215743e..b42b0fd3 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -12,84 +12,27 @@ #define MAX_UPDATE_SAMPLES 128 -static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei irSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right); static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei irSize, - ALfloat (*restrict Coeffs)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right); void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) { - ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; + const ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; ALsizei Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; - ALfloat out[MAX_UPDATE_SAMPLES][2]; + ALfloat gainstep = hrtfparams->GainStep; + ALfloat gain = hrtfparams->Gain; ALfloat left, right; - ALsizei minsize; ALsizei pos, i; - pos = 0; - if(Counter == 0) - goto skip_stepping; - - minsize = minu(BufferSize, Counter); - while(pos < minsize) - { - ALsizei todo = mini(minsize-pos, MAX_UPDATE_SAMPLES); - - for(i = 0;i < todo;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos++]; - left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], - (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], - (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - - Delay[0] += hrtfparams->Steps.Delay[0]; - Delay[1] += hrtfparams->Steps.Delay[1]; - - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->Steps.Coeffs, left, right); - out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]; - out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]; - } - - for(i = 0;i < todo;i++) - LeftOut[OutPos+i] += out[i][0]; - for(i = 0;i < todo;i++) - RightOut[OutPos+i] += out[i][1]; - OutPos += todo; - } - - if(pos == Counter) - { - *hrtfparams->Current = *hrtfparams->Target; - Delay[0] = hrtfparams->Target->Delay[0]; - Delay[1] = hrtfparams->Target->Delay[1]; - } - else - { - hrtfparams->Current->Delay[0] = Delay[0]; - hrtfparams->Current->Delay[1] = Delay[1]; - } - -skip_stepping: - Delay[0] >>= HRTFDELAY_BITS; - Delay[1] >>= HRTFDELAY_BITS; - while(pos < BufferSize) + for(pos = 0;pos < BufferSize;) { + ALfloat out[MAX_UPDATE_SAMPLES][2]; ALsizei todo = mini(BufferSize-pos, MAX_UPDATE_SAMPLES); for(i = 0;i < todo;i++) @@ -103,8 +46,9 @@ skip_stepping: Offset++; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]; - out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]; + out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]*gain; + out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]*gain; + gain += gainstep; } for(i = 0;i < todo;i++) @@ -113,11 +57,12 @@ skip_stepping: RightOut[OutPos+i] += out[i][1]; OutPos += todo; } + hrtfparams->Gain = gain; } void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize) { ALfloat out[MAX_UPDATE_SAMPLES][2]; diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 727c5c55..390a1dd2 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -190,44 +190,9 @@ const ALfloat *Resample_bsinc32_Neon(const InterpState *state, } -static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - ALsizei c; - float32x4_t leftright4; - { - float32x2_t leftright2 = vdup_n_f32(0.0); - leftright2 = vset_lane_f32(left, leftright2, 0); - leftright2 = vset_lane_f32(right, leftright2, 1); - leftright4 = vcombine_f32(leftright2, leftright2); - } - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); - CoeffStep = ASSUME_ALIGNED(CoeffStep, 16); - for(c = 0;c < IrSize;c += 2) - { - const ALsizei o0 = (Offset+c)&HRIR_MASK; - const ALsizei o1 = (o0+1)&HRIR_MASK; - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), - vld1_f32((float32_t*)&Values[o1][0])); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); - float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - coefs = vaddq_f32(coefs, deltas); - - vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); - vst1q_f32(&Coeffs[c][0], coefs); - } -} - static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { ALsizei c; diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 7870a6d8..37ce953f 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -69,74 +69,9 @@ const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *res } -static inline void ApplyCoeffsStep(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - const __m128 lrlr = _mm_setr_ps(left, right, left, right); - __m128 coeffs, deltas, imp0, imp1; - __m128 vals = _mm_setzero_ps(); - ALsizei i; - - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); - CoeffStep = ASSUME_ALIGNED(CoeffStep, 16); - if((Offset&1)) - { - const ALsizei o0 = Offset&HRIR_MASK; - const ALsizei 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_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 ALsizei 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 ALsizei 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); - } - } -} - static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], + const ALfloat (*restrict Coeffs)[2], ALfloat left, ALfloat right) { const __m128 lrlr = _mm_setr_ps(left, right, left, right); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 04fb7239..7663e58d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -620,6 +620,7 @@ typedef struct HrtfState { typedef struct HrtfParams { alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; ALsizei Delay[2]; + ALfloat Gain; } HrtfParams; typedef struct DirectHrtfState { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8888bdc0..72f33be2 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -116,12 +116,9 @@ enum ActiveFilters { typedef struct MixHrtfParams { - const HrtfParams *Target; - HrtfParams *Current; - struct { - alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - ALsizei Delay[2]; - } Steps; + const HrtfParams *Current; + ALfloat Gain; + ALfloat GainStep; } MixHrtfParams; @@ -133,7 +130,7 @@ typedef struct DirectParams { NfcFilter NFCtrlFilter[MAX_AMBI_ORDER]; struct { - HrtfParams Current; + HrtfParams Old; HrtfParams Target; HrtfState State; } Hrtf; @@ -225,13 +222,13 @@ typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize); typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Counter, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const MixHrtfParams *hrtfparams, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize); + const ALfloat (*restrict Coeffs)[2], + ALfloat (*restrict Values)[2], ALsizei BufferSize); #define GAIN_MIX_MAX (16.0f) /* +24dB */ -- cgit v1.2.3 From 7b4645f5f8d0269f47517a506297bfb7694ec990 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 06:58:27 -0700 Subject: Store the HRIR coeff pointer and delays directly in MixHrtfParams --- Alc/ALu.c | 1 - Alc/mixer.c | 14 ++++++++++---- Alc/mixer_inc.c | 4 ++-- OpenAL32/Include/alMain.h | 7 ++++--- OpenAL32/Include/alu.h | 3 ++- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 55f0c09a..5148d141 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1504,7 +1504,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) state = device->Hrtf; for(c = 0;c < device->Dry.NumChannels;c++) { - typedef ALfloat ALfloat2[2]; HrtfMix(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer[c], state->Offset, state->IrSize, SAFE_CONST(ALfloat2*,state->Chan[c].Coeffs), diff --git a/Alc/mixer.c b/Alc/mixer.c index 67e74396..fd2eba01 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -612,7 +612,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if(!Counter) { parms->Hrtf.Old = parms->Hrtf.Target; - hrtfparams.Current = &parms->Hrtf.Target; + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = parms->Hrtf.Target.Gain; hrtfparams.GainStep = 0.0f; MixHrtfSamples( @@ -631,7 +633,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei * So it needs to fade out over DstBufferSize instead * of Counter. */ - hrtfparams.Current = &parms->Hrtf.Old; + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; hrtfparams.Gain = parms->Hrtf.Old.Gain; hrtfparams.GainStep = -hrtfparams.Gain / (ALfloat)DstBufferSize; @@ -648,8 +652,10 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei * fade time this mix handles. */ gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - minf(1.0f, (ALfloat)Counter / (ALfloat)DstBufferSize)); - hrtfparams.Current = &parms->Hrtf.Target; + minf(1.0f, (ALfloat)Counter/DstBufferSize)); + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / (ALfloat)DstBufferSize; MixHrtfSamples( diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index b42b0fd3..ee3286e9 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -23,8 +23,8 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize) { - const ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs; - ALsizei Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] }; + const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); + const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; ALfloat gainstep = hrtfparams->GainStep; ALfloat gain = hrtfparams->Gain; ALfloat left, right; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7663e58d..ac89adf8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -1024,10 +1024,11 @@ void FillCPUCaps(ALuint capfilter); vector_al_string SearchDataFiles(const char *match, const char *subdir); -/* Small hack to use a pointer-to-array type as a normal argument type. - * Shouldn't be used directly. */ +/* Small hack to use a pointer-to-array types as a normal argument type. + * Shouldn't be used directly. + */ typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; - +typedef ALfloat ALfloat2[2]; #ifdef __cplusplus } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 72f33be2..48520b41 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -116,7 +116,8 @@ enum ActiveFilters { typedef struct MixHrtfParams { - const HrtfParams *Current; + const ALfloat (*Coeffs)[2]; + ALsizei Delay[2]; ALfloat Gain; ALfloat GainStep; } MixHrtfParams; -- cgit v1.2.3 From f276e83c8d136b12d5f61c323d340aee47ff88d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 08:18:36 -0700 Subject: Document the nfc config option and expose it in alsoft-config --- alsoftrc.sample | 9 +++++++++ utils/alsoft-config/mainwindow.cpp | 6 ++++++ utils/alsoft-config/mainwindow.ui | 31 ++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 1068e311..26ef9153 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -238,6 +238,15 @@ hq-mode = false # specified in the decoder configuration file. distance-comp = true +## nfc: +# Enables near-field control filters. This simulates and compensates for low- +# frequency effects caused by the curvature of nearby sound-waves, which +# creates a more realistic perception of sound distance. Note that the effect +# may be stronger or weaker than intended if the application doesn't use or +# specify an appropriate unit scale, or if incorrect speaker distances are set +# in the decoder configuration file. Requires hq-mode to be enabled. +nfc = true + ## quad: # Decoder configuration file for Quadrophonic channel output. See # docs/ambdec.txt for a description of the file format. diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 93641e85..caa2d5d4 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -331,6 +331,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderNFEffectsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); @@ -665,6 +666,8 @@ void MainWindow::loadConfig(const QString &fname) ui->decoderHQModeCheckBox->setChecked(hqmode); bool distcomp = settings.value("decoder/distance-comp", true).toBool(); ui->decoderDistCompCheckBox->setChecked(distcomp); + bool nfeffects = settings.value("decoder/nfc", true).toBool(); + ui->decoderNFEffectsCheckBox->setChecked(nfeffects); ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); @@ -894,6 +897,9 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("decoder/distance-comp", ui->decoderDistCompCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") ); + settings.setValue("decoder/nfc", + ui->decoderNFEffectsCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 806b0ce0..a077e8a5 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -621,7 +621,7 @@ configuration file. -10 - 100 + 120 551 161 @@ -789,6 +789,35 @@ configuration file. + + + + 10 + 80 + 181 + 21 + + + + Simulates and compensates for low-frequency effects +caused by the curvature of nearby sound-waves, which +creates a more realistic perception of sound distance. +Note that the effect may be stronger or weaker than +intended if the application doesn't use or specify an +appropriate unit scale, or if incorrect speaker distances +are set in the decoder configuration file. Requires High +Quality Mode to be enabled. + + + Qt::RightToLeft + + + Near-Field Effects: + + + true + + -- cgit v1.2.3 From 097ed84a871dbf467342740de6eea1c8f53f898e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 13:24:16 -0700 Subject: Handle the nfc-ref-delay config option --- alsoftrc.sample | 10 +++++ utils/alsoft-config/mainwindow.cpp | 34 +++++++++++++++ utils/alsoft-config/mainwindow.h | 4 ++ utils/alsoft-config/mainwindow.ui | 84 +++++++++++++++++++++++++++++++++++++- 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 26ef9153..fcdd4027 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -247,6 +247,16 @@ distance-comp = true # in the decoder configuration file. Requires hq-mode to be enabled. nfc = true +## nfc-ref-delay +# Specifies the reference delay value for ambisonic output. When channels is +# set to one of the ambi* formats, this option enables NFC-HOA output with the +# specified Reference Delay parameter. The specified value can then be shared +# with an appropriate NFC-HOA decoder to reproduce correct near-field effects. +# Keep in mind that despite being designed for higher-order ambisonics, this +# applies to first-order output all the same. When left unset, normal output +# is created with no near-field simulation. +nfc-ref-delay = + ## quad: # Decoder configuration file for Quadrophonic channel output. See # docs/ambdec.txt for a description of the file format. diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index caa2d5d4..e06c9e17 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -293,6 +293,9 @@ MainWindow::MainWindow(QWidget *parent) : mPeriodCountValidator = new QIntValidator(2, 16, this); ui->periodCountEdit->setValidator(mPeriodCountValidator); + mRefDelayValidator = new QDoubleValidator(0.0, 1000.0, 3, this); + ui->decoderNFRefDelayEdit->setValidator(mRefDelayValidator); + mSourceCountValidator = new QIntValidator(0, 4096, this); ui->srcCountLineEdit->setValidator(mSourceCountValidator); mEffectSlotValidator = new QIntValidator(0, 64, this); @@ -332,6 +335,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderNFEffectsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderNFRefDelaySlider, SIGNAL(valueChanged(int)), this, SLOT(updateRefDelayEdit(int))); + connect(ui->decoderNFRefDelayEdit, SIGNAL(editingFinished()), this, SLOT(updateRefDelaySlider())); connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); @@ -425,6 +430,7 @@ MainWindow::~MainWindow() delete ui; delete mPeriodSizeValidator; delete mPeriodCountValidator; + delete mRefDelayValidator; delete mSourceCountValidator; delete mEffectSlotValidator; delete mSourceSendValidator; @@ -668,6 +674,13 @@ void MainWindow::loadConfig(const QString &fname) ui->decoderDistCompCheckBox->setChecked(distcomp); bool nfeffects = settings.value("decoder/nfc", true).toBool(); ui->decoderNFEffectsCheckBox->setChecked(nfeffects); + double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); + ui->decoderNFRefDelayEdit->clear(); + if(refdelay > 0.0) + { + ui->decoderNFRefDelayEdit->insert(QString::number(refdelay)); + updateRefDelaySlider(); + } ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); @@ -900,6 +913,7 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("decoder/nfc", ui->decoderNFEffectsCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") ); + settings.setValue("decoder/nfc-ref-delay", ui->decoderNFRefDelayEdit->text()); settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); @@ -1115,6 +1129,26 @@ void MainWindow::updatePeriodCountSlider() } +void MainWindow::updateRefDelayEdit(int delay) +{ + ui->decoderNFRefDelayEdit->clear(); + if(delay > 0) + { + QString str = QString::asprintf("%0.03f", delay/1000.0); + ui->decoderNFRefDelayEdit->insert(str); + } + enableApplyButton(); +} + +void MainWindow::updateRefDelaySlider() +{ + double pos = ui->decoderNFRefDelayEdit->text().toDouble(); + if(pos > 1.0) pos = 1.0; + ui->decoderNFRefDelaySlider->setSliderPosition((int)(pos*1000.0)); + enableApplyButton(); +} + + void MainWindow::selectQuadDecoderFile() { selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} void MainWindow::select51DecoderFile() diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 8b763845..766c138c 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -35,6 +35,9 @@ private slots: void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); + void updateRefDelayEdit(int delay); + void updateRefDelaySlider(); + void selectQuadDecoderFile(); void select51DecoderFile(); void select61DecoderFile(); @@ -63,6 +66,7 @@ private: QValidator *mPeriodSizeValidator; QValidator *mPeriodCountValidator; + QValidator *mRefDelayValidator; QValidator *mSourceCountValidator; QValidator *mEffectSlotValidator; QValidator *mSourceSendValidator; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index a077e8a5..3a5a3190 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -621,7 +621,7 @@ configuration file. -10 - 120 + 160 551 161 @@ -818,6 +818,88 @@ Quality Mode to be enabled. true + + + + -10 + 110 + 551 + 21 + + + + The reference delay value for ambisonic output. When +Channels is set to one of the Ambisonic formats, this +option enables NFC-HOA output with the specified +Reference Delay parameter. The specified value can then +be shared with an appropriate NFC-HOA decoder to +reproduce correct near-field effects. Keep in mind that +despite being designed for higher-order ambisonics, this +applies to first-order output all the same. When left unset, +normal output is created with no near-field simulation. + + + + + 20 + 0 + 161 + 21 + + + + Near-Field Reference Delay: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 190 + 0 + 251 + 20 + + + + 1000 + + + Qt::Horizontal + + + + + + 450 + 0 + 51 + 21 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + off + + + + + + 510 + 0 + 31 + 21 + + + + sec. + + + -- cgit v1.2.3 From 948ce36fa9a384d8139346228afa43f099c17000 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 14:42:02 -0700 Subject: Increase _XOPEN_SOURCE to 600 for Solaris --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b778907c..fc41e949 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,12 +129,12 @@ if(NOT WIN32) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_DEFAULT) IF(NOT HAVE_POSIX_MEMALIGN_DEFAULT) SET(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500") + SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600") CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN_POSIX) IF(NOT HAVE_POSIX_MEMALIGN_POSIX) SET(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) ELSE() - ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500) + ADD_DEFINITIONS(-D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600) ENDIF() ENDIF() UNSET(OLD_REQUIRED_FLAGS) -- cgit v1.2.3 From d9e2a0cbf04e8e2feab6597a5fc5c74bd5026a34 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 15:27:50 -0700 Subject: Use QString's arg method to format the float value --- utils/alsoft-config/mainwindow.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index e06c9e17..4510781e 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -1133,10 +1133,9 @@ void MainWindow::updateRefDelayEdit(int delay) { ui->decoderNFRefDelayEdit->clear(); if(delay > 0) - { - QString str = QString::asprintf("%0.03f", delay/1000.0); - ui->decoderNFRefDelayEdit->insert(str); - } + ui->decoderNFRefDelayEdit->insert( + QString("%1").arg(delay/1000.0, 0, 'f', 3) + ); enableApplyButton(); } -- cgit v1.2.3 From dc17f287fe685f8f211dd8a7b14f46d2c719f1de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 16:10:49 -0700 Subject: Use a spinbox for the nfc-ref-delay value --- utils/alsoft-config/mainwindow.cpp | 38 +++++------------------------ utils/alsoft-config/mainwindow.h | 4 ---- utils/alsoft-config/mainwindow.ui | 49 ++++++++++---------------------------- 3 files changed, 19 insertions(+), 72 deletions(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4510781e..c2e36fb4 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -293,9 +293,6 @@ MainWindow::MainWindow(QWidget *parent) : mPeriodCountValidator = new QIntValidator(2, 16, this); ui->periodCountEdit->setValidator(mPeriodCountValidator); - mRefDelayValidator = new QDoubleValidator(0.0, 1000.0, 3, this); - ui->decoderNFRefDelayEdit->setValidator(mRefDelayValidator); - mSourceCountValidator = new QIntValidator(0, 4096, this); ui->srcCountLineEdit->setValidator(mSourceCountValidator); mEffectSlotValidator = new QIntValidator(0, 64, this); @@ -335,8 +332,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderNFEffectsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); - connect(ui->decoderNFRefDelaySlider, SIGNAL(valueChanged(int)), this, SLOT(updateRefDelayEdit(int))); - connect(ui->decoderNFRefDelayEdit, SIGNAL(editingFinished()), this, SLOT(updateRefDelaySlider())); + connect(ui->decoderNFRefDelaySpinBox, SIGNAL(valueChanged(double)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); @@ -430,7 +426,6 @@ MainWindow::~MainWindow() delete ui; delete mPeriodSizeValidator; delete mPeriodCountValidator; - delete mRefDelayValidator; delete mSourceCountValidator; delete mEffectSlotValidator; delete mSourceSendValidator; @@ -675,12 +670,7 @@ void MainWindow::loadConfig(const QString &fname) bool nfeffects = settings.value("decoder/nfc", true).toBool(); ui->decoderNFEffectsCheckBox->setChecked(nfeffects); double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); - ui->decoderNFRefDelayEdit->clear(); - if(refdelay > 0.0) - { - ui->decoderNFRefDelayEdit->insert(QString::number(refdelay)); - updateRefDelaySlider(); - } + ui->decoderNFRefDelaySpinBox->setValue(refdelay); ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); @@ -913,7 +903,10 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("decoder/nfc", ui->decoderNFEffectsCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") ); - settings.setValue("decoder/nfc-ref-delay", ui->decoderNFRefDelayEdit->text()); + double refdelay = ui->decoderNFRefDelaySpinBox->value(); + settings.setValue("decoder/nfc-ref-delay", + (refdelay > 0.0) ? QString::number(refdelay) : QString() + ); settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); @@ -1129,25 +1122,6 @@ void MainWindow::updatePeriodCountSlider() } -void MainWindow::updateRefDelayEdit(int delay) -{ - ui->decoderNFRefDelayEdit->clear(); - if(delay > 0) - ui->decoderNFRefDelayEdit->insert( - QString("%1").arg(delay/1000.0, 0, 'f', 3) - ); - enableApplyButton(); -} - -void MainWindow::updateRefDelaySlider() -{ - double pos = ui->decoderNFRefDelayEdit->text().toDouble(); - if(pos > 1.0) pos = 1.0; - ui->decoderNFRefDelaySlider->setSliderPosition((int)(pos*1000.0)); - enableApplyButton(); -} - - void MainWindow::selectQuadDecoderFile() { selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} void MainWindow::select51DecoderFile() diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index 766c138c..8b763845 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -35,9 +35,6 @@ private slots: void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); - void updateRefDelayEdit(int delay); - void updateRefDelaySlider(); - void selectQuadDecoderFile(); void select51DecoderFile(); void select61DecoderFile(); @@ -66,7 +63,6 @@ private: QValidator *mPeriodSizeValidator; QValidator *mPeriodCountValidator; - QValidator *mRefDelayValidator; QValidator *mSourceCountValidator; QValidator *mEffectSlotValidator; QValidator *mSourceSendValidator; diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 3a5a3190..b186e744 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -823,7 +823,7 @@ Quality Mode to be enabled. -10 110 - 551 + 281 21 @@ -843,7 +843,7 @@ normal output is created with no near-field simulation. 20 0 - 161 + 151 21 @@ -854,49 +854,26 @@ normal output is created with no near-field simulation. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - 190 - 0 - 251 - 20 - - - - 1000 - - - Qt::Horizontal - - - + - 450 + 180 0 - 51 + 91 21 - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + sec - - off + + 4 - - - - - 510 - 0 - 31 - 21 - + + 1000.000000000000000 - - sec. + + 0.010000000000000 -- cgit v1.2.3 From 1e7c0b4646042eaaf19d726b74a2d04a0c3d2288 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 16:25:13 -0700 Subject: Fix the height of some GUI widgets --- utils/alsoft-config/mainwindow.ui | 48 +++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index b186e744..a527cfd5 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -31,7 +31,7 @@ 470 405 81 - 25 + 21 @@ -52,9 +52,6 @@ 401 - - 0 - Playback @@ -65,7 +62,7 @@ 110 50 78 - 22 + 21 @@ -114,7 +111,7 @@ float and converted to the output sample type as needed. 110 20 78 - 22 + 21 @@ -132,7 +129,7 @@ to stereo output. 380 20 91 - 29 + 21 @@ -226,7 +223,7 @@ to stereo output. 380 50 78 - 22 + 21 @@ -302,7 +299,7 @@ mixed and being heard. 80 20 160 - 23 + 21 @@ -339,7 +336,7 @@ mixed and being heard. 20 20 51 - 22 + 21 @@ -366,7 +363,7 @@ frames needed for each mixing update. 60 20 160 - 23 + 21 @@ -419,7 +416,7 @@ frames needed for each mixing update. 0 20 51 - 22 + 21 @@ -434,7 +431,7 @@ frames needed for each mixing update. 130 130 131 - 22 + 21 @@ -482,7 +479,7 @@ receiver. 390 130 131 - 22 + 21 @@ -949,7 +946,7 @@ normal output is created with no near-field simulation. 420 20 81 - 25 + 21 @@ -990,7 +987,7 @@ listed above. 420 50 81 - 25 + 21 @@ -1026,7 +1023,7 @@ listed above. 130 50 161 - 22 + 21 @@ -1074,7 +1071,7 @@ application or system to determine if it should be used. 130 20 161 - 22 + 21 @@ -1143,9 +1140,6 @@ application or system to determine if it should be used. 361 - - 0 - @@ -1334,7 +1328,7 @@ processing requests. Must be a power of 2. 10 30 301 - 23 + 21 @@ -1667,7 +1661,7 @@ during updates. 190 20 51 - 22 + 21 @@ -1720,7 +1714,7 @@ the CPU can handle. 190 50 51 - 22 + 21 @@ -1758,7 +1752,7 @@ may help when apps use more than the system can handle. 190 80 51 - 22 + 21 @@ -2113,7 +2107,7 @@ added by the ALC_EXT_DEDICATED extension. 160 20 123 - 29 + 21 @@ -2263,7 +2257,7 @@ added by the ALC_EXT_DEDICATED extension. 370 405 91 - 25 + 21 -- cgit v1.2.3 From cdf63b553f90a5a4b3af9902f9d94f089c8cf2e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Mar 2017 19:27:51 -0700 Subject: Avoid doing sequential load for the source state --- OpenAL32/alSource.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a36231b5..c4cdf16e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -138,9 +138,9 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * return NULL; } -static inline bool IsPlayingOrPausedSeq(const ALsource *source) +static inline bool IsPlayingOrPaused(ALsource *source) { - ALenum state = ATOMIC_LOAD_SEQ(&source->state); + ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire); return state == AL_PLAYING || state == AL_PAUSED; } @@ -157,10 +157,10 @@ static ALenum GetSourceState(ALsource *source, ALvoice *voice) return ATOMIC_LOAD(&source->state, almemory_order_acquire); } -static inline bool SourceShouldUpdate(const ALsource *source, const ALCcontext *context) +static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) { - return IsPlayingOrPausedSeq(source) && - !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire); + return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPaused(source); } static ALint FloatValsByProp(ALenum prop) @@ -543,8 +543,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && - IsPlayingOrPausedSeq(Source)) + if(SourceShouldUpdate(Source, Context)) { ALvoice *voice; @@ -750,8 +749,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && - IsPlayingOrPausedSeq(Source)) + if(SourceShouldUpdate(Source, Context)) { ALvoice *voice; @@ -874,7 +872,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } UnlockFiltersRead(device); - if(slot != Source->Send[values[1]].Slot && IsPlayingOrPausedSeq(Source)) + if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); -- cgit v1.2.3 From 6d565ff1fd7934087945437304f1ea36550b3510 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 14 Mar 2017 08:37:50 -0700 Subject: Remove a couple unneeded typedefs --- Alc/ALc.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ce04aa17..7c29134d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -117,18 +117,11 @@ static struct BackendInfo CaptureBackend; /************************************************ * Functions, enums, and errors ************************************************/ -typedef struct ALCfunction { +#define DECL(x) { #x, (ALCvoid*)(x) } +static const struct { const ALCchar *funcName; ALCvoid *address; -} ALCfunction; - -typedef struct ALCenums { - const ALCchar *enumName; - ALCenum value; -} ALCenums; - -#define DECL(x) { #x, (ALCvoid*)(x) } -static const ALCfunction alcFunctions[] = { +} alcFunctions[] = { DECL(alcCreateContext), DECL(alcMakeContextCurrent), DECL(alcProcessContext), @@ -294,13 +287,14 @@ static const ALCfunction alcFunctions[] = { DECL(alBufferSamplesSOFT), DECL(alGetBufferSamplesSOFT), DECL(alIsBufferFormatSupportedSOFT), - - { NULL, NULL } }; #undef DECL #define DECL(x) { #x, (x) } -static const ALCenums enumeration[] = { +static const struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { DECL(ALC_INVALID), DECL(ALC_FALSE), DECL(ALC_TRUE), @@ -698,8 +692,6 @@ static const ALCenums enumeration[] = { DECL(AL_EQUALIZER_HIGH_CUTOFF), DECL(AL_DEDICATED_GAIN), - - { NULL, (ALCenum)0 } }; #undef DECL @@ -3458,10 +3450,15 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar } else { - ALsizei i = 0; - while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName, funcName) != 0) - i++; - ptr = alcFunctions[i].address; + size_t i = 0; + for(i = 0;i < COUNTOF(alcFunctions);i++) + { + if(strcmp(alcFunctions[i].funcName, funcName) == 0) + { + ptr = alcFunctions[i].address; + break; + } + } } return ptr; @@ -3484,10 +3481,15 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e } else { - ALsizei i = 0; - while(enumeration[i].enumName && strcmp(enumeration[i].enumName, enumName) != 0) - i++; - val = enumeration[i].value; + size_t i = 0; + for(i = 0;i < COUNTOF(alcEnumerations);i++) + { + if(strcmp(alcEnumerations[i].enumName, enumName) == 0) + { + val = alcEnumerations[i].value; + break; + } + } } return val; -- cgit v1.2.3 From 32d521d79cf9baeb3cdbec69c8374ae5776d9052 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 14 Mar 2017 19:16:59 -0700 Subject: Check usability of MixHrtf_Neon before MixHrtf_SSE --- Alc/mixer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index fd2eba01..91c0623e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -93,14 +93,14 @@ RowMixerFunc SelectRowMixer(void) static inline HrtfMixerFunc SelectHrtfMixer(void) { -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_SSE; -#endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return MixHrtf_Neon; #endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_SSE; +#endif return MixHrtf_C; } -- cgit v1.2.3 From 8f5cab56080fedd5002a7141aa796d371340ab0a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 16 Mar 2017 11:25:28 -0700 Subject: Increase the filter slope to -12dB/octave --- Alc/ALu.c | 16 ++++++++-------- Alc/effects/echo.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 5148d141..7936c706 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -718,11 +718,11 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(DryGainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[c].LowPass, ALfilterType_HighShelf, - DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 0.75f) + DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 1.0f) ); ALfilterState_setParams( &voice->Direct.Params[c].HighPass, ALfilterType_LowShelf, - DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 0.75f) + DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 1.0f) ); } } @@ -739,11 +739,11 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * if(WetGainLF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[c].LowPass, ALfilterType_HighShelf, - WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) + WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 1.0f) ); ALfilterState_setParams( &voice->Send[i].Params[c].HighPass, ALfilterType_LowShelf, - WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) + WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 1.0f) ); } } @@ -1220,11 +1220,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(DryGainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, - DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 0.75f) + DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 1.0f) ); ALfilterState_setParams( &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, - DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 0.75f) + DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 1.0f) ); } for(i = 0;i < NumSends;i++) @@ -1238,11 +1238,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro if(WetGainLF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, - WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) + WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 1.0f) ); ALfilterState_setParams( &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, - WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) + WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 1.0f) ); } } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 07eba9eb..4293674f 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -129,7 +129,7 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co gain = minf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, gain, LOWPASSFREQREF/frequency, - calc_rcpQ_from_slope(gain, 0.75f)); + calc_rcpQ_from_slope(gain, 1.0f)); gain = Slot->Params.Gain; -- cgit v1.2.3 From a209edb5ee5231b9552138712dd57afce00bb556 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 16 Mar 2017 19:58:21 -0700 Subject: Fix NFC filter to set the correct center frequency --- Alc/nfcfilter.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Alc/nfcfilter.c b/Alc/nfcfilter.c index 21957975..758863c9 100644 --- a/Alc/nfcfilter.c +++ b/Alc/nfcfilter.c @@ -62,12 +62,8 @@ void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1) nfc->g = 1.0f; nfc->coeffs[0] = 1.0f; - /* NOTE: Slight adjustment from the literature to raise the center - * frequency a bit (0.5 -> 1.0). - */ - /* Calculate bass-boost coefficients. */ - r = 1.0f * w0; + r = 0.5f * w0; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; @@ -75,7 +71,7 @@ void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[1] = (2.0f * b_00) / g_0; /* Calculate bass-cut coefficients. */ - r = 1.0f * w1; + r = 0.5f * w1; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; @@ -89,7 +85,7 @@ void NfcFilterAdjust1(NfcFilter *nfc, const float w0) float b_00, g_0; float r; - r = 1.0f * w0; + r = 0.5f * w0; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; @@ -131,7 +127,7 @@ void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[0] = 1.0f; /* Calculate bass-boost coefficients. */ - r = 1.0f * w0; + r = 0.5f * w0; b_10 = B[2][0] * r; b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; @@ -141,7 +137,7 @@ void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[2] = (4.0f * b_11) / g_1; /* Calculate bass-cut coefficients. */ - r = 1.0f * w1; + r = 0.5f * w1; b_10 = B[2][0] * r; b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; @@ -157,7 +153,7 @@ void NfcFilterAdjust2(NfcFilter *nfc, const float w0) float b_10, b_11, g_1; float r; - r = 1.0f * w0; + r = 0.5f * w0; b_10 = B[2][0] * r; b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; @@ -207,7 +203,7 @@ void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[0] = 1.0f; /* Calculate bass-boost coefficients. */ - r = 1.0f * w0; + r = 0.5f * w0; b_10 = B[3][0] * r; b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; @@ -223,7 +219,7 @@ void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[2+1] = (2.0f * b_00) / g_0; /* Calculate bass-cut coefficients. */ - r = 1.0f * w1; + r = 0.5f * w1; b_10 = B[3][0] * r; b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; @@ -247,7 +243,7 @@ void NfcFilterAdjust3(NfcFilter *nfc, const float w0) float b_00, g_0; float r; - r = 1.0f * w0; + r = 0.5f * w0; b_10 = B[3][0] * r; b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; -- cgit v1.2.3 From 7bf7cda46750a3d44eca83a9b2d5b9c4debfd915 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 17 Mar 2017 15:45:39 -0700 Subject: Replace a couple ALuint with ALsizei --- Alc/ALc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7c29134d..e34cd75a 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1531,7 +1531,7 @@ void ALCdevice_Unlock(ALCdevice *device) */ void SetDefaultWFXChannelOrder(ALCdevice *device) { - ALuint i; + ALsizei i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->RealOut.ChannelName[i] = InvalidChannel; @@ -1630,7 +1630,7 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) */ void SetDefaultChannelOrder(ALCdevice *device) { - ALuint i; + ALsizei i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) device->RealOut.ChannelName[i] = InvalidChannel; -- cgit v1.2.3 From 66b86d43bedcd0d8944ccbd70c813ab126d3a82d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 18 Mar 2017 14:33:40 -0700 Subject: Fix alcGetInteger64vSOFT to handle ambisonic attributes --- Alc/ALc.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e34cd75a..7513d7b5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3095,9 +3095,6 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC { if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = ALC_BFORMAT3D_SOFT; - values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; values[i++] = device->AmbiLayout; @@ -3106,6 +3103,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_AMBISONIC_ORDER_SOFT; values[i++] = device->FmtChans-DevFmtAmbi1+1; + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = ALC_BFORMAT3D_SOFT; } else { @@ -3290,11 +3290,11 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, switch(pname) { case ALC_ATTRIBUTES_SIZE: - *values = 21; + *values = NumAttrsForDevice(device)+2; break; case ALC_ALL_ATTRIBUTES: - if(size < 21) + if(size < NumAttrsForDevice(device)+2) alcSetError(device, ALC_INVALID_VALUE); else { @@ -3313,8 +3313,25 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, } else { - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + { + values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; + values[i++] = device->AmbiLayout; + + values[i++] = ALC_AMBISONIC_SCALING_SOFT; + values[i++] = device->AmbiScale; + + values[i++] = ALC_AMBISONIC_ORDER_SOFT; + values[i++] = device->FmtChans-DevFmtAmbi1+1; + + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = ALC_BFORMAT3D_SOFT; + } + else + { + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + } values[i++] = ALC_FORMAT_TYPE_SOFT; values[i++] = device->FmtType; @@ -3360,12 +3377,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, break; case ALC_DEVICE_LATENCY_SOFT: - { - almtx_lock(&device->BackendLock); - clock = V0(device->Backend,getClockLatency)(); - almtx_unlock(&device->BackendLock); - *values = clock.Latency; - } + almtx_lock(&device->BackendLock); + clock = V0(device->Backend,getClockLatency)(); + almtx_unlock(&device->BackendLock); + *values = clock.Latency; break; case ALC_DEVICE_CLOCK_LATENCY_SOFT: @@ -3373,7 +3388,6 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, alcSetError(device, ALC_INVALID_VALUE); else { - ClockLatency clock; almtx_lock(&device->BackendLock); clock = V0(device->Backend,getClockLatency)(); almtx_unlock(&device->BackendLock); -- cgit v1.2.3 From 9e1aa50518e0abc6e8cfe811cedab32bb80a0fc5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 18 Mar 2017 20:24:19 -0700 Subject: Fix the lib name for the .pc file --- CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc41e949..bff76185 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1204,6 +1204,12 @@ IF(LIBTYPE STREQUAL "STATIC") SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS}) ENDIF() +IF(NOT WIN32) + SET(LIBNAME "openal") +ELSE() + SET(LIBNAME "OpenAL32") +ENDIF() + FIND_PACKAGE(Git) IF(GIT_FOUND AND EXISTS "${OpenAL_SOURCE_DIR}/.git") # Get the current working branch and its latest abbreviated commit hash @@ -1290,11 +1296,7 @@ ENDIF() SET_TARGET_PROPERTIES(OpenAL PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) -IF(NOT WIN32) - SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME "openal") -ELSE() - SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME "OpenAL32") -ENDIF() +SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME}) if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "") -- cgit v1.2.3 From ecfa1dcb6ffb79c74c0f6629f395c7619a6a3add Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Mar 2017 13:48:40 -0700 Subject: Don't defer source state or offset changes --- Alc/ALc.c | 35 +++------------------------------ OpenAL32/Include/alMain.h | 8 +------- OpenAL32/Include/alSource.h | 4 ---- OpenAL32/alSource.c | 48 ++++++++++++--------------------------------- OpenAL32/alState.c | 12 ++++++------ 5 files changed, 22 insertions(+), 85 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7513d7b5..f275871e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1679,9 +1679,9 @@ extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS * does *NOT* stop mixing, but rather prevents certain property changes from * taking effect. */ -void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type) +void ALCcontext_DeferUpdates(ALCcontext *context) { - ATOMIC_STORE_SEQ(&context->DeferUpdates, type); + ATOMIC_STORE_SEQ(&context->DeferUpdates, AL_TRUE); } /* ALCcontext_ProcessUpdates @@ -1690,13 +1690,9 @@ void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type) */ void ALCcontext_ProcessUpdates(ALCcontext *context) { - ALCdevice *device = context->Device; - ReadLock(&context->PropLock); if(ATOMIC_EXCHANGE_SEQ(ALenum, &context->DeferUpdates, AL_FALSE)) { - ALsizei pos; - /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. */ @@ -1706,31 +1702,6 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) UpdateListenerProps(context); UpdateAllEffectSlotProps(context); - - LockUIntMapRead(&context->SourceMap); - V0(device->Backend,lock)(); - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = context->Voices[pos]; - ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source && source->OffsetType != AL_NONE) - { - WriteLock(&source->queue_lock); - ApplyOffset(source, voice); - WriteUnlock(&source->queue_lock); - } - } - for(pos = 0;pos < context->SourceMap.size;pos++) - { - ALsource *source = context->SourceMap.values[pos]; - ALenum new_state = source->new_state; - source->new_state = AL_NONE; - if(new_state) - SetSourceState(source, context, new_state); - } - V0(device->Backend,unlock)(); - UnlockUIntMapRead(&context->SourceMap); - UpdateAllSourceProps(context); /* Now with all updates declared, let the mixer continue applying them @@ -2819,7 +2790,7 @@ ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) alcSetError(NULL, ALC_INVALID_CONTEXT); else { - ALCcontext_DeferUpdates(context, DeferAllowPlay); + ALCcontext_DeferUpdates(context); ALCcontext_DecRef(context); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ac89adf8..2182d3f0 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -879,15 +879,9 @@ void AppendCaptureDeviceList(const ALCchar *name); void ALCdevice_Lock(ALCdevice *device); void ALCdevice_Unlock(ALCdevice *device); -void ALCcontext_DeferUpdates(ALCcontext *context, ALenum type); +void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); -enum { - DeferOff = AL_FALSE, - DeferAll, - DeferAllowPlay -}; - typedef struct { #ifdef HAVE_FENV_H diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 1dd835c4..284d5cbe 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -142,7 +142,6 @@ typedef struct ALsource { /** Source state (initial, playing, paused, or stopped) */ ATOMIC(ALenum) state; - ALenum new_state; /** Source Buffer Queue head. */ RWLock queue_lock; @@ -174,9 +173,6 @@ inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) { return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } void UpdateAllSourceProps(ALCcontext *context); -ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); -ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); - ALvoid ReleaseALSources(ALCcontext *Context); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c4cdf16e..540821eb 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -54,6 +54,8 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); +static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); +static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); typedef enum SourceProp { srcPitch = AL_PITCH, @@ -543,7 +545,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(SourceShouldUpdate(Source, Context)) + if(IsPlayingOrPaused(Source)) { ALvoice *voice; @@ -749,7 +751,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(SourceShouldUpdate(Source, Context)) + if(IsPlayingOrPaused(Source)) { ALvoice *voice; @@ -2354,7 +2356,6 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { source = LookupSource(context, sources[i]); ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); - source->new_state = AL_NONE; } ALCdevice_Unlock(device); goto done; @@ -2371,21 +2372,10 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) AllocateVoices(context, newcount, device->NumAuxSends); } - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) - { - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - source->new_state = AL_PLAYING; - } - } - else + for(i = 0;i < n;i++) { - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PLAYING); - } + source = LookupSource(context, sources[i]); + SetSourceState(source, context, AL_PLAYING); } ALCdevice_Unlock(device); @@ -2417,21 +2407,10 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) } ALCdevice_Lock(context->Device); - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) - { - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - source->new_state = AL_PAUSED; - } - } - else + for(i = 0;i < n;i++) { - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PAUSED); - } + source = LookupSource(context, sources[i]); + SetSourceState(source, context, AL_PAUSED); } ALCdevice_Unlock(context->Device); @@ -2466,7 +2445,6 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - source->new_state = AL_NONE; SetSourceState(source, context, AL_STOPPED); } ALCdevice_Unlock(context->Device); @@ -2502,7 +2480,6 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - source->new_state = AL_NONE; SetSourceState(source, context, AL_INITIAL); } ALCdevice_Unlock(context->Device); @@ -2810,7 +2787,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->OffsetType = AL_NONE; Source->SourceType = AL_UNDETERMINED; ATOMIC_INIT(&Source->state, AL_INITIAL); - Source->new_state = AL_NONE; ATOMIC_INIT(&Source->queue, NULL); @@ -2979,7 +2955,7 @@ void UpdateAllSourceProps(ALCcontext *context) * * Sets the source's new play state given its current state. */ -ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) +static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALCdevice *device = Context->Device; ALvoice *voice; @@ -3372,7 +3348,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte * Apply the stored playback offset to the Source. This function will update * the number of buffers "played" given the stored offset. */ -ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) +static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) { ALbufferlistitem *BufferList; const ALbuffer *Buffer; diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index e633a86b..eddd2999 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -152,7 +152,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) value = AL_TRUE; break; @@ -198,7 +198,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) value = (ALdouble)AL_TRUE; break; @@ -243,7 +243,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) value = (ALfloat)AL_TRUE; break; @@ -288,7 +288,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) value = (ALint)AL_TRUE; break; @@ -333,7 +333,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; case AL_DEFERRED_UPDATES_SOFT: - if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) == DeferAll) + if(ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) value = (ALint64SOFT)AL_TRUE; break; @@ -671,7 +671,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) context = GetContextRef(); if(!context) return; - ALCcontext_DeferUpdates(context, DeferAll); + ALCcontext_DeferUpdates(context); ALCcontext_DecRef(context); } -- cgit v1.2.3 From e06cf07ab0722efc90fdc468dbdd0d90f8fe61af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 19 Mar 2017 16:49:23 -0700 Subject: Break up a function and move the code to where it's called --- OpenAL32/alSource.c | 345 +++++++++++++++++++++++++--------------------------- 1 file changed, 169 insertions(+), 176 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 540821eb..fef00e5a 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -54,7 +54,6 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); -static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); typedef enum SourceProp { @@ -2330,10 +2329,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) } AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { - ALCdevice *device; ALCcontext *context; + ALCdevice *device; ALsource *source; - ALsizei i; + ALvoice *voice; + ALsizei i, j; context = GetContextRef(); if(!context) return; @@ -2374,8 +2374,122 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { + ALbufferlistitem *BufferList; + ALbuffer *buffer = NULL; + source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PLAYING); + WriteLock(&source->queue_lock); + /* Check that there is a queue containing at least one valid, non zero + * length Buffer. + */ + BufferList = ATOMIC_LOAD_SEQ(&source->queue); + while(BufferList) + { + if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) + break; + BufferList = BufferList->next; + } + + /* If there's nothing to play, go right to stopped. */ + if(!BufferList) + { + /* NOTE: A source without any playable buffers should not have an + * ALvoice since it shouldn't be in a playing or paused state. So + * there's no need to look up its voice and clear the source. + */ + ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + goto finish_play; + } + + voice = GetSourceVoice(source, context); + switch(GetSourceState(source, voice)) + { + case AL_PLAYING: + assert(voice != NULL); + /* A source that's already playing is restarted from the beginning. */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + goto finish_play; + + case AL_PAUSED: + assert(voice != NULL); + /* A source that's paused simply resumes. Make sure it uses the + * volume last specified; there's no reason to fade from where + * it stopped at. + */ + voice->Flags &= ~VOICE_IS_MOVING; + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + goto finish_play; + + default: + break; + } + + source->NeedsUpdate = AL_FALSE; + UpdateSourceProps(source, device->NumAuxSends); + + /* Make sure this source isn't already active, and if not, look for an + * unused voice to put it in. + */ + assert(voice == NULL); + for(j = 0;j < context->VoiceCount;j++) + { + if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) + { + voice = context->Voices[j]; + break; + } + } + if(voice == NULL) + voice = context->Voices[context->VoiceCount++]; + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + ATOMIC_THREAD_FENCE(almemory_order_acquire); + + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); + if(source->OffsetType != AL_NONE) + ApplyOffset(source, voice); + + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + + /* Clear previous samples. */ + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + /* Clear the stepping value so the mixer knows not to mix this until + * the update gets applied. + */ + voice->Step = 0; + + voice->Flags = 0; + for(j = 0;j < voice->NumChannels;j++) + memset(&voice->Direct.Params[j].Hrtf.State, 0, + sizeof(voice->Direct.Params[j].Hrtf.State)); + if(device->AvgSpeakerDist > 0.0f) + { + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (device->AvgSpeakerDist * device->Frequency); + for(j = 0;j < voice->NumChannels;j++) + { + NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1); + NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1); + NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1); + } + } + + ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, true, almemory_order_release); + ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + finish_play: + WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2391,7 +2505,9 @@ AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2406,13 +2522,23 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_PAUSED); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(GetSourceState(source, voice) == AL_PLAYING) + ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release); + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2426,7 +2552,9 @@ AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2441,13 +2569,26 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_STOPPED); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2461,7 +2602,9 @@ AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) { ALCcontext *context; + ALCdevice *device; ALsource *source; + ALvoice *voice; ALsizei i; context = GetContextRef(); @@ -2476,13 +2619,26 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); } - ALCdevice_Lock(context->Device); + device = context->Device; + ALCdevice_Lock(device); for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - SetSourceState(source, context, AL_INITIAL); + WriteLock(&source->queue_lock); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } + if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; + WriteUnlock(&source->queue_lock); } - ALCdevice_Unlock(context->Device); + ALCdevice_Unlock(device); done: UnlockSourcesRead(context); @@ -2951,169 +3107,6 @@ void UpdateAllSourceProps(ALCcontext *context) } -/* SetSourceState - * - * Sets the source's new play state given its current state. - */ -static void SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) -{ - ALCdevice *device = Context->Device; - ALvoice *voice; - - WriteLock(&Source->queue_lock); - if(state == AL_PLAYING) - { - ALCdevice *device = Context->Device; - ALbufferlistitem *BufferList; - ALbuffer *buffer = NULL; - ALsizei i; - - /* Check that there is a queue containing at least one valid, non zero - * length Buffer. */ - BufferList = ATOMIC_LOAD_SEQ(&Source->queue); - while(BufferList) - { - if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) - break; - BufferList = BufferList->next; - } - - /* If there's nothing to play, go right to stopped. */ - if(!BufferList) - { - /* NOTE: A source without any playable buffers should not have an - * ALvoice since it shouldn't be in a playing or paused state. So - * there's no need to look up its voice and clear the source. - */ - ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - goto done; - } - - voice = GetSourceVoice(Source, Context); - switch(GetSourceState(Source, voice)) - { - case AL_PLAYING: - assert(voice != NULL); - /* A source that's already playing is restarted from the beginning. */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - goto done; - - case AL_PAUSED: - assert(voice != NULL); - /* A source that's paused simply resumes. Make sure it uses the - * volume last specified; there's no reason to fade from where - * it stopped at. - */ - voice->Flags &= ~VOICE_IS_MOVING; - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); - goto done; - - default: - break; - } - - Source->NeedsUpdate = AL_FALSE; - UpdateSourceProps(Source, device->NumAuxSends); - - /* Make sure this source isn't already active, and if not, look for an - * unused voice to put it in. - */ - assert(voice == NULL); - for(i = 0;i < Context->VoiceCount;i++) - { - if(ATOMIC_LOAD(&Context->Voices[i]->Source, almemory_order_acquire) == NULL) - { - voice = Context->Voices[i]; - break; - } - } - if(voice == NULL) - voice = Context->Voices[Context->VoiceCount++]; - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - ATOMIC_THREAD_FENCE(almemory_order_acquire); - - /* A source that's not playing or paused has any offset applied when it - * starts playing. - */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); - if(Source->OffsetType != AL_NONE) - ApplyOffset(Source, voice); - - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); - - /* Clear previous samples. */ - memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); - - /* Clear the stepping value so the mixer knows not to mix this until - * the update gets applied. - */ - voice->Step = 0; - - voice->Flags = 0; - for(i = 0;i < MAX_INPUT_CHANNELS;i++) - { - ALsizei j; - for(j = 0;j < HRTF_HISTORY_LENGTH;j++) - voice->Direct.Params[i].Hrtf.State.History[j] = 0.0f; - for(j = 0;j < HRIR_LENGTH;j++) - { - voice->Direct.Params[i].Hrtf.State.Values[j][0] = 0.0f; - voice->Direct.Params[i].Hrtf.State.Values[j][1] = 0.0f; - } - } - if(device->AvgSpeakerDist > 0.0f) - { - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); - for(i = 0;i < voice->NumChannels;i++) - { - NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1); - NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1); - NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1); - } - } - - ATOMIC_STORE(&voice->Source, Source, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&Source->state, AL_PLAYING, almemory_order_release); - } - else if(state == AL_PAUSED) - { - if((voice=GetSourceVoice(Source, Context)) != NULL) - { - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } - if(GetSourceState(Source, voice) == AL_PLAYING) - ATOMIC_STORE(&Source->state, AL_PAUSED, almemory_order_release); - } - else /*if(state == AL_STOPPED || state == AL_INITIAL)*/ - { - if((voice=GetSourceVoice(Source, Context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } - if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - ATOMIC_STORE(&Source->state, state, almemory_order_relaxed); - Source->OffsetType = AL_NONE; - Source->Offset = 0.0; - } -done: - WriteUnlock(&Source->queue_lock); -} - /* GetSourceSampleOffset * * Gets the current read offset for the given Source, in 32.32 fixed-point -- cgit v1.2.3 From d7d9ad806a60dbd67b413fdfe09caba83fc90eed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Mar 2017 16:53:41 -0700 Subject: Use proper bools for boolean states --- Alc/mixer.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 91c0623e..b9eb4a99 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -371,9 +371,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ResamplerFunc Resample; ALbufferlistitem *BufferListItem; ALuint DataPosInt, DataPosFrac; - ALboolean Looping; + bool isplaying = true; + bool islooping; ALint increment; - ALenum State; ALsizei OutPos; ALsizei NumChannels; ALsizei SampleSize; @@ -384,11 +384,10 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei send; /* Get source info */ - State = AL_PLAYING; /* Only called while playing. */ DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); + islooping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); NumChannels = voice->NumChannels; SampleSize = voice->SampleSize; increment = voice->Step; @@ -446,9 +445,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Data += chan*SampleSize; /* If current pos is beyond the loop range, do not loop */ - if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd) + if(!islooping || DataPosInt >= (ALuint)ALBuffer->LoopEnd) { - Looping = AL_FALSE; + islooping = false; /* Load what's left to play from the source buffer, and * clear the rest of the temp buffer */ @@ -516,7 +515,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } } tmpiter = tmpiter->next; - if(!tmpiter && Looping) + if(!tmpiter && islooping) tmpiter = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); else if(!tmpiter) { @@ -718,7 +717,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei break; } - if(Looping && Source->SourceType == AL_STATIC) + if(islooping && Source->SourceType == AL_STATIC) { assert(LoopEnd > LoopStart); DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; @@ -730,11 +729,11 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if(!(BufferListItem=BufferListItem->next)) { - if(Looping) + if(islooping) BufferListItem = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); else { - State = AL_STOPPED; + isplaying = false; BufferListItem = NULL; DataPosInt = 0; DataPosFrac = 0; @@ -744,7 +743,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei DataPosInt -= DataSize; } - } while(State == AL_PLAYING && OutPos < SamplesToDo); + } while(isplaying && OutPos < SamplesToDo); voice->Flags |= VOICE_IS_MOVING; @@ -752,5 +751,5 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); - return State == AL_PLAYING; + return isplaying; } -- cgit v1.2.3 From 42bcf0870d7f7358b4e1775d37e20e3b9162d249 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Mar 2017 19:22:41 -0700 Subject: Make DataPosInt an ALsizei --- Alc/mixer.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index b9eb4a99..bc9c715e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -368,26 +368,27 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { - ResamplerFunc Resample; ALbufferlistitem *BufferListItem; - ALuint DataPosInt, DataPosFrac; - bool isplaying = true; - bool islooping; - ALint increment; - ALsizei OutPos; - ALsizei NumChannels; - ALsizei SampleSize; + ALsizei NumChannels, SampleSize; + ResamplerFunc Resample; + ALsizei DataPosInt; + ALuint DataPosFrac; ALint64 DataSize64; + ALint increment; ALsizei Counter; + ALsizei OutPos; ALsizei IrSize; + bool isplaying; + bool islooping; ALsizei chan; ALsizei send; /* Get source info */ - DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); + isplaying = true; /* Will only be called while playing. */ + islooping = ATOMIC_LOAD(&Source->looping, almemory_order_acquire); + DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - islooping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); NumChannels = voice->NumChannels; SampleSize = voice->SampleSize; increment = voice->Step; @@ -445,7 +446,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Data += chan*SampleSize; /* If current pos is beyond the loop range, do not loop */ - if(!islooping || DataPosInt >= (ALuint)ALBuffer->LoopEnd) + if(!islooping || DataPosInt >= ALBuffer->LoopEnd) { islooping = false; @@ -489,7 +490,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei { /* Crawl the buffer queue to fill in the temp buffer */ ALbufferlistitem *tmpiter = BufferListItem; - ALuint pos = DataPosInt; + ALsizei pos = DataPosInt; while(tmpiter && SrcBufferSize > SrcDataSize) { @@ -497,7 +498,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if((ALBuffer=tmpiter->buffer) != NULL) { const ALubyte *Data = ALBuffer->data; - ALuint DataSize = ALBuffer->SampleLen; + ALsizei DataSize = ALBuffer->SampleLen; /* Skip the data already played */ if(DataSize <= pos) @@ -713,7 +714,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei DataSize = ALBuffer->SampleLen; LoopStart = ALBuffer->LoopStart; LoopEnd = ALBuffer->LoopEnd; - if((ALuint)LoopEnd > DataPosInt) + if(LoopEnd > DataPosInt) break; } @@ -724,7 +725,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei break; } - if((ALuint)DataSize > DataPosInt) + if(DataSize > DataPosInt) break; if(!(BufferListItem=BufferListItem->next)) -- cgit v1.2.3 From cdfe0d8f5af871258f1f58493e9659148659cacb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 20 Mar 2017 21:25:39 -0700 Subject: Use an atomic flag to test if a source needs to update --- Alc/ALc.c | 2 +- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f275871e..f830a602 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2254,7 +2254,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } - source->NeedsUpdate = AL_TRUE; + ATOMIC_FLAG_CLEAR(&source->PropsClean, almemory_order_release); /* Clear any pre-existing source property structs, in case the * number of auxiliary sends changed. Playing (or paused) sources diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 284d5cbe..5b1e2547 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -149,7 +149,7 @@ typedef struct ALsource { ATOMIC(ALboolean) looping; - ALenum NeedsUpdate; + ATOMIC_FLAG PropsClean; ATOMIC(struct ALsourceProps*) Update; ATOMIC(struct ALsourceProps*) FreeList; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index fef00e5a..e32bb5c8 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -421,7 +421,7 @@ static ALint Int64ValsByProp(ALenum prop) if(SourceShouldUpdate(Source, Context)) \ UpdateSourceProps(Source, device->NumAuxSends); \ else \ - Source->NeedsUpdate = AL_TRUE; \ + ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \ } while(0) static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) @@ -2429,7 +2429,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) break; } - source->NeedsUpdate = AL_FALSE; + ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire); UpdateSourceProps(source, device->NumAuxSends); /* Make sure this source isn't already active, and if not, look for an @@ -2948,7 +2948,10 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) ATOMIC_INIT(&Source->looping, AL_FALSE); - Source->NeedsUpdate = AL_TRUE; + /* No way to do an 'init' here, so just test+set with relaxed ordering and + * ignore the test. + */ + ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Source->Update, NULL); ATOMIC_INIT(&Source->FreeList, NULL); @@ -3098,11 +3101,8 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source != NULL && source->NeedsUpdate) - { - source->NeedsUpdate = AL_FALSE; + if(source != NULL && ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) UpdateSourceProps(source, num_sends); - } } } -- cgit v1.2.3 From b062d50bf1fcf86814b8ffdba56b8a929dfe350d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 21 Mar 2017 16:40:23 -0700 Subject: Fix setting Ambi formats for loopback devices --- Alc/ALc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f830a602..8d241802 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1904,7 +1904,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(schans == ALC_BFORMAT3D_SOFT) { - device->FmtChans = DevFmtAmbi1 + aorder; + device->FmtChans = DevFmtAmbi1 + (aorder-1); device->AmbiLayout = alayout; device->AmbiScale = ascale; } -- cgit v1.2.3 From 85042a74eefdf02397530b19248a789a4fcb49f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 22 Mar 2017 03:13:36 -0700 Subject: Update ChangeLog --- ChangeLog | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6663dd03..6a9652ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,11 +7,16 @@ openal-soft-1.18.0: Implemented 3D processing for some effects. Currently implemented for Reverb, Compressor, Equalizer, and Ring Modulator. - Implemented 2-channel UHJ output encoding. Used by default for stereo playback. + Implemented 2-channel UHJ output encoding. This needs to be enabled with a + config option to be used. Implemented dual-band processing for high-quality ambisonic decoding. - Implemented distance-compensation for high-quality ambisonic decoding. + Implemented distance-compensation for surround sound output. + + Implemented near-field emulation and compensation with ambisonic rendering. + Currently only applies when using the high-quality ambisonic decoder or + ambisonic output, with appropriate config options. Implemented a config option to select a preferred HRTF. -- cgit v1.2.3 From 5404b2225aca57407f2f3704e2e2616a281d85ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Mar 2017 01:16:13 -0700 Subject: Add some comments for ALsource functions --- OpenAL32/alSource.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e32bb5c8..a882cb83 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -139,13 +139,21 @@ static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext * return NULL; } +/** + * Returns if the last known state for the source was playing or paused. Does + * not sync with the mixer voice. + */ static inline bool IsPlayingOrPaused(ALsource *source) { ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire); return state == AL_PLAYING || state == AL_PAUSED; } -static ALenum GetSourceState(ALsource *source, ALvoice *voice) +/** + * Returns an updated source state using the matching voice's status (or lack + * thereof). + */ +static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) { if(!voice) { @@ -158,6 +166,10 @@ static ALenum GetSourceState(ALsource *source, ALvoice *voice) return ATOMIC_LOAD(&source->state, almemory_order_acquire); } +/** + * Returns if the source should specify an update, given the context's + * deferring state and the source's last known state. + */ static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) { return !ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire) && -- cgit v1.2.3 From 1c49d0542d53133c1e023fc22ff5537ea3ca41aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Mar 2017 19:16:32 -0700 Subject: Use an atomic flag to mark auxiliary effect slot updates --- OpenAL32/Include/alAuxEffectSlot.h | 5 +++-- OpenAL32/alAuxEffectSlot.c | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 3c24f80c..c6e40a55 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -4,6 +4,7 @@ #include "alMain.h" #include "alEffect.h" +#include "atomic.h" #include "align.h" #ifdef __cplusplus @@ -88,8 +89,6 @@ struct ALeffectslotProps { typedef struct ALeffectslot { - ALboolean NeedsUpdate; - ALfloat Gain; ALboolean AuxSendAuto; @@ -100,6 +99,8 @@ typedef struct ALeffectslot { ALeffectState *State; } Effect; + ATOMIC_FLAG PropsClean; + RefCount ref; ATOMIC(struct ALeffectslotProps*) Update; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 37316549..8fc62bde 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -60,7 +60,7 @@ static void ALeffectState_DecRef(ALeffectState *state); if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ UpdateEffectSlotProps(slot); \ else \ - slot->NeedsUpdate = AL_TRUE; \ + ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \ } while(0) @@ -579,9 +579,9 @@ ALenum InitEffectSlot(ALeffectslot *slot) if(!(slot->Effect.State=V0(factory,create)())) return AL_OUT_OF_MEMORY; - slot->NeedsUpdate = AL_FALSE; slot->Gain = 1.0; slot->AuxSendAuto = AL_TRUE; + ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_relaxed); InitRef(&slot->ref, 0); ATOMIC_INIT(&slot->Update, NULL); @@ -683,9 +683,8 @@ void UpdateAllEffectSlotProps(ALCcontext *context) slot = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); while(slot) { - if(slot->NeedsUpdate) + if(ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) UpdateEffectSlotProps(slot); - slot->NeedsUpdate = AL_FALSE; slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } UnlockEffectSlotsRead(context); -- cgit v1.2.3 From 1aca34468877feb07a2c05a23d4fdb8f41cecfd2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Mar 2017 19:32:53 -0700 Subject: Fix handling of the PropsClean flags --- OpenAL32/alAuxEffectSlot.c | 2 +- OpenAL32/alSource.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 8fc62bde..65107287 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -683,7 +683,7 @@ void UpdateAllEffectSlotProps(ALCcontext *context) slot = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); while(slot) { - if(ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) + if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) UpdateEffectSlotProps(slot); slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a882cb83..e18a00e2 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3113,7 +3113,7 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source != NULL && ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) + if(source != NULL && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) UpdateSourceProps(source, num_sends); } } -- cgit v1.2.3 From 9ca92be0b87c97fccf613acb14b5c121cc881a88 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Mar 2017 14:08:04 -0700 Subject: Properly calculate the echo damping --- Alc/effects/echo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 4293674f..672cdaca 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -126,7 +126,7 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co state->FeedGain = props->Echo.Feedback; - gain = minf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ + gain = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, gain, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gain, 1.0f)); -- cgit v1.2.3 From 5c37eca2c50c57b460406101737b5128798ad306 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Mar 2017 14:35:25 -0700 Subject: Use ALsizei for more index lookups --- Alc/effects/echo.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 672cdaca..1c37752f 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -34,14 +34,14 @@ typedef struct ALechoState { DERIVE_FROM_TYPE(ALeffectState); ALfloat *SampleBuffer; - ALuint BufferLength; + ALsizei BufferLength; // The echo is two tap. The delay is the number of samples from before the // current offset struct { - ALuint delay; + ALsizei delay; } Tap[2]; - ALuint Offset; + ALsizei Offset; /* The panning gains for the two taps */ ALfloat Gain[2][MAX_OUTPUT_CHANNELS]; @@ -83,12 +83,12 @@ static ALvoid ALechoState_Destruct(ALechoState *state) static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) { - ALuint maxlen, i; + ALsizei 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 = fastf2i(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; + maxlen += fastf2i(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) @@ -112,8 +112,8 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gain, lrpan, spread; - state->Tap[0].delay = fastf2u(props->Echo.Delay * frequency) + 1; - state->Tap[1].delay = fastf2u(props->Echo.LRDelay * frequency); + state->Tap[0].delay = fastf2i(props->Echo.Delay * frequency) + 1; + state->Tap[1].delay = fastf2i(props->Echo.LRDelay * frequency); state->Tap[1].delay += state->Tap[0].delay; spread = props->Echo.Spread; @@ -144,13 +144,13 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - const ALuint mask = state->BufferLength-1; - const ALuint tap1 = state->Tap[0].delay; - const ALuint tap2 = state->Tap[1].delay; - ALuint offset = state->Offset; + const ALsizei mask = state->BufferLength-1; + const ALsizei tap1 = state->Tap[0].delay; + const ALsizei tap2 = state->Tap[1].delay; + ALsizei offset = state->Offset; ALfloat x[2], y[2], in, out; - ALuint base; - ALuint i, k; + ALuint base, k; + ALsizei i; x[0] = state->Filter.x[0]; x[1] = state->Filter.x[1]; @@ -159,7 +159,7 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const for(base = 0;base < SamplesToDo;) { ALfloat temps[128][2]; - ALuint td = minu(128, SamplesToDo-base); + ALsizei td = mini(128, SamplesToDo-base); for(i = 0;i < td;i++) { -- cgit v1.2.3 From 1d559ec703653386ca65175d884f7487b36032e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 24 Mar 2017 15:34:36 -0700 Subject: Properly update the resampler label in the UI --- utils/alsoft-config/mainwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index c2e36fb4..26d05f8f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -596,7 +596,8 @@ void MainWindow::loadConfig(const QString &fname) ui->srcSendLineEdit->insert(settings.value("sends").toString()); QString resampler = settings.value("resampler").toString().trimmed(); - ui->resamplerSlider->setValue(0); + ui->resamplerSlider->setValue(2); + ui->resamplerLabel->setText(resamplerList[2].name); /* The "cubic" and "sinc8" resamplers are no longer supported. Use "sinc4" * as a fallback. */ @@ -607,6 +608,7 @@ void MainWindow::loadConfig(const QString &fname) if(resampler == resamplerList[i].value) { ui->resamplerSlider->setValue(i); + ui->resamplerLabel->setText(resamplerList[i].name); break; } } -- cgit v1.2.3 From 56428cdb74a6ee8449cb9977a9575c22c1844d26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 25 Mar 2017 23:48:57 -0700 Subject: Use a loop to apply NFC filters --- Alc/mixer.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index bc9c715e..46de5cbe 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -557,46 +557,31 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ); else { + static void (*const NfcUpdate[MAX_AMBI_ORDER])( + NfcFilter*,float*,const float*,const int + ) = { + NfcFilterUpdate1, NfcFilterUpdate2, NfcFilterUpdate3 + }; ALfloat *nfcsamples = Device->NFCtrlData; - ALsizei chanoffset = 0; + ALsizei ord, chanoffset = 0; + MixSamples(samples, voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize ); chanoffset += voice->Direct.ChannelsPerOrder[0]; - if(voice->Direct.ChannelsPerOrder[1] > 0) - { - NfcFilterUpdate1(&parms->NFCtrlFilter[0], nfcsamples, samples, - DstBufferSize); - MixSamples(nfcsamples, - voice->Direct.ChannelsPerOrder[1], voice->Direct.Buffer+chanoffset, - parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, - Counter, OutPos, DstBufferSize - ); - chanoffset += voice->Direct.ChannelsPerOrder[1]; - } - if(voice->Direct.ChannelsPerOrder[2] > 0) - { - NfcFilterUpdate2(&parms->NFCtrlFilter[1], nfcsamples, samples, - DstBufferSize); - MixSamples(nfcsamples, - voice->Direct.ChannelsPerOrder[2], voice->Direct.Buffer+chanoffset, - parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, - Counter, OutPos, DstBufferSize - ); - chanoffset += voice->Direct.ChannelsPerOrder[2]; - } - if(voice->Direct.ChannelsPerOrder[3] > 0) + for(ord = 1;ord < MAX_AMBI_ORDER+1;ord++) { - NfcFilterUpdate3(&parms->NFCtrlFilter[2], nfcsamples, samples, + if(voice->Direct.ChannelsPerOrder[ord] <= 0) + break; + NfcUpdate[ord-1](&parms->NFCtrlFilter[ord-1], nfcsamples, samples, DstBufferSize); - MixSamples(nfcsamples, - voice->Direct.ChannelsPerOrder[3], voice->Direct.Buffer+chanoffset, - parms->Gains.Current+chanoffset, parms->Gains.Target+chanoffset, - Counter, OutPos, DstBufferSize + MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[ord], + voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, + parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize ); - chanoffset += voice->Direct.ChannelsPerOrder[3]; + chanoffset += voice->Direct.ChannelsPerOrder[ord]; } } } -- cgit v1.2.3 From 9f4e47d7be96da4759cc008ef376addb32061a99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Mar 2017 02:44:34 -0700 Subject: Fix HRTF interpolated gain calculation --- Alc/mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 46de5cbe..b8f4b91f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -637,7 +637,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei * fade time this mix handles. */ gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - minf(1.0f, (ALfloat)Counter/DstBufferSize)); + (ALfloat)DstBufferSize/Counter); hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; @@ -650,7 +650,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ); /* Update the old parameters with the result. */ parms->Hrtf.Old = parms->Hrtf.Target; - if(Counter > DstBufferSize) + if(DstBufferSize < Counter) parms->Hrtf.Old.Gain = hrtfparams.Gain; } } -- cgit v1.2.3 From 7f55d34a7dd99afb8f23311ab7e3098903c1ceff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Mar 2017 15:11:15 -0700 Subject: Add include/AL to the exported includes destination --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bff76185..2599b67b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1336,7 +1336,7 @@ IF(ALSOFT_INSTALL) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/AL ) EXPORT(TARGETS OpenAL NAMESPACE OpenAL:: -- cgit v1.2.3 From b49a79a15fa16e93e2e2ff1fc76dbae0425fd503 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Mar 2017 21:24:20 -0700 Subject: Require CMake 3.0.2 Seems it's necessary for the INCLUDES install property with the cmake config export. --- CMakeLists.txt | 52 +--------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2599b67b..2cb95402 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # CMake build file list for OpenAL -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5) +CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2) PROJECT(OpenAL) @@ -275,12 +275,6 @@ HAVE_C11_ATOMIC) # Add definitions, compiler switches, etc. 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 @@ -329,17 +323,6 @@ ELSE() SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror") ENDIF() - # Force enable -fPIC for CMake versions before 2.8.9 (later versions have - # the POSITION_INDEPENDENT_CODE target property). The static common library - # will be linked into the dynamic OpenAL library, which requires all its - # code to be position-independent. - IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32) - CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH) - IF(HAVE_FPIC_SWITCH) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC") - ENDIF() - ENDIF() - # We want RelWithDebInfo to actually include debug stuff (define _DEBUG # instead of NDEBUG) FOREACH(flag_var CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO) @@ -880,9 +863,6 @@ IF(ALSA_FOUND) SET(BACKENDS "${BACKENDS} ALSA${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/alsa.c) ADD_BACKEND_LIBS(${ALSA_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${ALSA_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_ALSA AND NOT HAVE_ALSA) @@ -898,9 +878,6 @@ IF(OSS_FOUND) SET(HAVE_OSS 1) SET(BACKENDS "${BACKENDS} OSS,") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.c) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${OSS_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_OSS AND NOT HAVE_OSS) @@ -916,9 +893,6 @@ IF(AUDIOIO_FOUND) SET(HAVE_SOLARIS 1) SET(BACKENDS "${BACKENDS} Solaris,") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/solaris.c) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${AUDIOIO_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SOLARIS AND NOT HAVE_SOLARIS) @@ -935,9 +909,6 @@ IF(SOUNDIO_FOUND) SET(BACKENDS "${BACKENDS} SndIO (linked),") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sndio.c) SET(EXTRA_LIBS ${SOUNDIO_LIBRARIES} ${EXTRA_LIBS}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${SOUNDIO_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SNDIO AND NOT HAVE_SNDIO) @@ -954,9 +925,6 @@ IF(QSA_FOUND) SET(BACKENDS "${BACKENDS} QSA (linked),") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/qsa.c) SET(EXTRA_LIBS ${QSA_LIBRARIES} ${EXTRA_LIBS}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${QSA_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_QSA AND NOT HAVE_QSA) @@ -992,9 +960,6 @@ IF(HAVE_WINDOWS_H) SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.c) ADD_BACKEND_LIBS(${DSOUND_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${DSOUND_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() @@ -1029,9 +994,6 @@ IF(PORTAUDIO_FOUND) SET(BACKENDS "${BACKENDS} PortAudio${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/portaudio.c) ADD_BACKEND_LIBS(${PORTAUDIO_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${PORTAUDIO_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_PORTAUDIO AND NOT HAVE_PORTAUDIO) @@ -1048,9 +1010,6 @@ IF(PULSEAUDIO_FOUND) SET(BACKENDS "${BACKENDS} PulseAudio${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/pulseaudio.c) ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${PULSEAUDIO_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO) @@ -1067,9 +1026,6 @@ IF(JACK_FOUND) SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c) ADD_BACKEND_LIBS(${JACK_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK) @@ -1189,13 +1145,7 @@ IF(ALSOFT_EXAMPLES) FIND_PACKAGE(SDL2) IF(SDL2_FOUND) FIND_PACKAGE(SDL_sound) - IF(SDL_SOUND_FOUND AND CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - ENDIF() FIND_PACKAGE(FFmpeg COMPONENTS AVFORMAT AVCODEC AVUTIL SWSCALE SWRESAMPLE) - IF(FFMPEG_FOUND AND CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${FFMPEG_INCLUDE_DIRS}) - ENDIF() ENDIF() ENDIF() -- cgit v1.2.3 From 70aefa75e2253ef7a93cdd6412e8523663d3c6e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 27 Mar 2017 23:16:23 -0700 Subject: Use an array of pointers for effects instead of a linked list --- Alc/ALc.c | 12 +++- Alc/ALu.c | 34 +++++------ OpenAL32/Include/alAuxEffectSlot.h | 8 ++- OpenAL32/Include/alMain.h | 2 +- OpenAL32/alAuxEffectSlot.c | 113 +++++++++++++++++++++++-------------- common/uintmap.c | 75 ++++++++++++++++++++++++ include/uintmap.h | 1 + 7 files changed, 179 insertions(+), 66 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8d241802..84007020 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2449,6 +2449,7 @@ static ALCboolean VerifyDevice(ALCdevice **device) static ALvoid InitContext(ALCcontext *Context) { ALlistener *listener = Context->Listener; + struct ALeffectslotArray *auxslots; //Initialise listener listener->Gain = 1.0f; @@ -2490,6 +2491,10 @@ static ALvoid InitContext(ALCcontext *Context) InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); + auxslots = al_calloc(DEF_ALIGN, offsetof(struct ALeffectslotArray, slot[0])); + auxslots->count = 0; + ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); + //Set globals Context->DistanceModel = DefaultDistanceModel; Context->SourceDistanceModel = AL_FALSE; @@ -2510,11 +2515,16 @@ static ALvoid InitContext(ALCcontext *Context) static void FreeContext(ALCcontext *context) { ALlistener *listener = context->Listener; + struct ALeffectslotArray *auxslots; struct ALlistenerProps *lprops; size_t count; TRACE("%p\n", context); + auxslots = ATOMIC_EXCHANGE(struct ALeffectslotArray*, &context->ActiveAuxSlots, + NULL, almemory_order_relaxed); + al_free(auxslots); + if(context->SourceMap.size > 0) { WARN("(%p) Deleting %d Source%s\n", context, context->SourceMap.size, @@ -3511,7 +3521,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALContext->Listener = (ALlistener*)ALContext->_listener_mem; ALContext->Device = device; - ATOMIC_INIT(&ALContext->ActiveAuxSlotList, NULL); + ATOMIC_INIT(&ALContext->ActiveAuxSlots, NULL); ALContext->Voices = NULL; ALContext->MaxVoices = 0; diff --git a/Alc/ALu.c b/Alc/ALu.c index 7936c706..f0e4d735 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1281,20 +1281,18 @@ static void CalcSourceParams(ALvoice *voice, ALsource *source, ALCcontext *conte } -static void UpdateContextSources(ALCcontext *ctx, ALeffectslot *slot) +static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray *slots) { ALvoice **voice, **voice_end; ALsource *source; + ALsizei i; IncrementRef(&ctx->UpdateCount); if(!ATOMIC_LOAD(&ctx->HoldUpdates, almemory_order_acquire)) { ALboolean force = CalcListenerParams(ctx); - while(slot) - { - force |= CalcEffectSlotParams(slot, ctx->Device); - slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); - } + for(i = 0;i < slots->count;i++) + force |= CalcEffectSlotParams(slots->slot[i], ctx->Device); voice = ctx->Voices; voice_end = voice + ctx->VoiceCount; @@ -1417,24 +1415,23 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if((slot=device->DefaultSlot) != NULL) { CalcEffectSlotParams(device->DefaultSlot, device); - for(i = 0;i < slot->NumChannels;i++) - memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); + for(c = 0;c < slot->NumChannels;c++) + memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); } ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire); while(ctx) { - ALeffectslot *slotroot; + const struct ALeffectslotArray *auxslots; - slotroot = ATOMIC_LOAD(&ctx->ActiveAuxSlotList, almemory_order_acquire); - UpdateContextSources(ctx, slotroot); + auxslots = ATOMIC_LOAD(&ctx->ActiveAuxSlots, almemory_order_acquire); + UpdateContextSources(ctx, auxslots); - slot = slotroot; - while(slot) + for(i = 0;i < auxslots->count;i++) { - for(i = 0;i < slot->NumChannels;i++) - memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); - slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); + ALeffectslot *slot = auxslots->slot[i]; + for(c = 0;c < slot->NumChannels;c++) + memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); } /* source processing */ @@ -1455,13 +1452,12 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } /* effect slot processing */ - slot = slotroot; - while(slot) + for(i = 0;i < auxslots->count;i++) { + ALeffectslot *slot = auxslots->slot[i]; ALeffectState *state = slot->Params.EffectState; V(state,process)(SamplesToDo, SAFE_CONST(ALfloatBUFFERSIZE*,slot->WetBuffer), state->OutBuffer, state->OutChannels); - slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } ctx = ctx->next; diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index c6e40a55..7f95dc91 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -75,6 +75,12 @@ static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = #define MAX_EFFECT_CHANNELS (4) +struct ALeffectslotArray { + ALsizei count; + struct ALeffectslot *slot[]; +}; + + struct ALeffectslotProps { ALfloat Gain; ALboolean AuxSendAuto; @@ -134,8 +140,6 @@ typedef struct ALeffectslot { * first-order device output (FOAOut). */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; - - ATOMIC(struct ALeffectslot*) next; } ALeffectslot; inline void LockEffectSlotsRead(ALCcontext *context) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2182d3f0..9c1ef099 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -855,7 +855,7 @@ struct ALCcontext_struct { ALsizei VoiceCount; ALsizei MaxVoices; - ATOMIC(struct ALeffectslot*) ActiveAuxSlotList; + ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; ALCdevice *Device; const ALCchar *ExtensionList; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 65107287..743fac14 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -42,8 +42,6 @@ extern inline void UnlockEffectSlotsWrite(ALCcontext *context); extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); -static void RemoveEffectSlotList(ALCcontext *Context, ALeffectslot *slot); - static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) { @@ -67,7 +65,7 @@ static void ALeffectState_DecRef(ALeffectState *state); AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { ALCcontext *context; - ALeffectslot *first, *last; + ALeffectslot **tmpslots = NULL; ALsizei cur; ALenum err; @@ -76,8 +74,9 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(!(n >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); - first = last = NULL; + LockEffectSlotsWrite(context); for(cur = 0;cur < n;cur++) { ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot)); @@ -85,13 +84,15 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) { al_free(slot); + UnlockEffectSlotsWrite(context); + alDeleteAuxiliaryEffectSlots(cur, effectslots); SET_ERROR_AND_GOTO(context, err, done); } err = NewThunkEntry(&slot->id); if(err == AL_NO_ERROR) - err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot); + err = InsertUIntMapEntryNoLock(&context->EffectSlotMap, slot->id, slot); if(err != AL_NO_ERROR) { FreeThunkEntry(slot->id); @@ -99,6 +100,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(slot->Params.EffectState) ALeffectState_DecRef(slot->Params.EffectState); al_free(slot); + UnlockEffectSlotsWrite(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); SET_ERROR_AND_GOTO(context, err, done); @@ -106,22 +108,36 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo aluInitEffectPanning(slot); - if(!first) first = slot; - if(last) ATOMIC_STORE(&last->next, slot, almemory_order_relaxed); - last = slot; - + tmpslots[cur] = slot; effectslots[cur] = slot->id; } - if(last != NULL) + if(n > 0) { - ALeffectslot *root = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); - do { - ATOMIC_STORE(&last->next, root, almemory_order_relaxed); - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALeffectslot*, &context->ActiveAuxSlotList, - &root, first)); + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); + struct ALeffectslotArray *newarray = NULL; + ALsizei newcount = curarray->count + n; + ALCdevice *device; + + newarray = al_calloc(DEF_ALIGN, + offsetof(struct ALeffectslotArray, slot[newcount]) + ); + newarray->count = newcount; + memcpy(newarray->slot, tmpslots, sizeof(ALeffectslot*)*n); + if(curarray) + memcpy(newarray->slot+n, curarray->slot, sizeof(ALeffectslot*)*curarray->count); + + newarray = ATOMIC_EXCHANGE(struct ALeffectslotArray*, + &context->ActiveAuxSlots, newarray, almemory_order_acq_rel + ); + device = context->Device; + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(newarray); } + UnlockEffectSlotsWrite(context); done: + al_free(tmpslots); ALCcontext_DecRef(context); } @@ -146,13 +162,46 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * } // All effectslots are valid + if(n > 0) + { + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); + struct ALeffectslotArray *newarray = NULL; + ALsizei newcount = curarray->count - n; + ALCdevice *device; + ALsizei j, k; + + assert(newcount >= 0); + newarray = al_calloc(DEF_ALIGN, + offsetof(struct ALeffectslotArray, slot[newcount]) + ); + newarray->count = newcount; + for(i = j = 0;i < newarray->count;) + { + slot = curarray->slot[j++]; + for(k = 0;k < n;k++) + { + if(slot->id == effectslots[k]) + break; + } + if(k == n) + newarray->slot[i++] = slot; + } + + newarray = ATOMIC_EXCHANGE(struct ALeffectslotArray*, + &context->ActiveAuxSlots, newarray, almemory_order_acq_rel + ); + device = context->Device; + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(newarray); + } + for(i = 0;i < n;i++) { if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL) continue; FreeThunkEntry(slot->id); - RemoveEffectSlotList(context, slot); DeinitEffectSlot(slot); memset(slot, 0, sizeof(*slot)); @@ -430,27 +479,6 @@ done: } -static void RemoveEffectSlotList(ALCcontext *context, ALeffectslot *slot) -{ - ALCdevice *device = context->Device; - ALeffectslot *root, *next; - - root = slot; - next = ATOMIC_LOAD_SEQ(&slot->next); - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALeffectslot*, &context->ActiveAuxSlotList, &root, next)) - { - ALeffectslot *cur; - do { - cur = root; - root = slot; - } while(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALeffectslot*, &cur->next, &root, next)); - } - /* Wait for any mix that may be using these effect slots to finish. */ - while((ReadRef(&device->MixCount)&1) != 0) - althrd_yield(); -} - - void InitEffectFactoryMap(void) { InitUIntMap(&EffectStateFactoryMap, ~0); @@ -595,8 +623,6 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.DecayTime = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; - ATOMIC_INIT(&slot->next, NULL); - return AL_NO_ERROR; } @@ -677,15 +703,16 @@ void UpdateEffectSlotProps(ALeffectslot *slot) void UpdateAllEffectSlotProps(ALCcontext *context) { - ALeffectslot *slot; + struct ALeffectslotArray *auxslots; + ALsizei i; LockEffectSlotsRead(context); - slot = ATOMIC_LOAD_SEQ(&context->ActiveAuxSlotList); - while(slot) + auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); + for(i = 0;i < auxslots->count;i++) { + ALeffectslot *slot = auxslots->slot[i]; if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) UpdateEffectSlotProps(slot); - slot = ATOMIC_LOAD(&slot->next, almemory_order_relaxed); } UnlockEffectSlotsRead(context); } diff --git a/common/uintmap.c b/common/uintmap.c index 7b27b36e..21a921b2 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -119,6 +119,81 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) return AL_NO_ERROR; } +ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value) +{ + ALsizei pos = 0; + + if(map->size > 0) + { + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + } + + if(pos == map->size || map->keys[pos] != key) + { + if(map->size == map->limit) + return AL_OUT_OF_MEMORY; + + if(map->size == map->capacity) + { + ALuint *keys = NULL; + ALvoid **values; + ALsizei newcap, keylen; + + newcap = (map->capacity ? (map->capacity<<1) : 4); + if(map->limit > 0 && newcap > map->limit) + newcap = map->limit; + if(newcap > map->capacity) + { + /* Round the memory size for keys up to a multiple of the + * pointer size. + */ + keylen = newcap * sizeof(map->keys[0]); + keylen += sizeof(map->values[0]) - 1; + keylen -= keylen%sizeof(map->values[0]); + + keys = al_malloc(16, keylen + newcap*sizeof(map->values[0])); + } + if(!keys) + return AL_OUT_OF_MEMORY; + values = (ALvoid**)((ALbyte*)keys + keylen); + + if(map->keys) + { + memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); + memcpy(values, map->values, map->size*sizeof(map->values[0])); + } + al_free(map->keys); + map->keys = keys; + map->values = values; + map->capacity = newcap; + } + + if(pos < map->size) + { + memmove(&map->keys[pos+1], &map->keys[pos], + (map->size-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos+1], &map->values[pos], + (map->size-pos)*sizeof(map->values[0])); + } + map->size++; + } + map->keys[pos] = key; + map->values[pos] = value; + + return AL_NO_ERROR; +} + ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) { ALvoid *ptr = NULL; diff --git a/include/uintmap.h b/include/uintmap.h index acb2749a..f70d99fd 100644 --- a/include/uintmap.h +++ b/include/uintmap.h @@ -24,6 +24,7 @@ typedef struct UIntMap { void InitUIntMap(UIntMap *map, ALsizei limit); void ResetUIntMap(UIntMap *map); ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); +ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key); ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); -- cgit v1.2.3 From facd8ab109a7fefa5cd81380ec42d3a52c79a9c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 28 Mar 2017 05:33:43 -0700 Subject: Make ReleaseContext return if any contexts still remain --- Alc/ALc.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 84007020..12d0d608 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1320,7 +1320,6 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum ALCbackendFactory *factory = backendinfo->getFactory(); V(factory,probe)(type); } - UnlockLists(); } static void ProbeAllDevicesList(void) @@ -2573,11 +2572,13 @@ static void FreeContext(ALCcontext *context) /* ReleaseContext * * Removes the context reference from the given device and removes it from - * being current on the running thread or globally. + * being current on the running thread or globally. Returns true if other + * contexts still exist on the device. */ -static void ReleaseContext(ALCcontext *context, ALCdevice *device) +static bool ReleaseContext(ALCcontext *context, ALCdevice *device) { - ALCcontext *origctx; + ALCcontext *origctx, *newhead; + bool ret = true; if(altss_get(LocalContext) == context) { @@ -2592,8 +2593,8 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) ALCdevice_Lock(device); origctx = context; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &device->ContextList, - &origctx, context->next)) + newhead = context->next; + if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &device->ContextList, &origctx, newhead)) { ALCcontext *volatile*list = &origctx->next; while(*list) @@ -2606,9 +2607,12 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) list = &(*list)->next; } } + else + ret = !!newhead; ALCdevice_Unlock(device); ALCcontext_DecRef(context); + return ret; } void ALCcontext_IncRef(ALCcontext *context) @@ -3501,6 +3505,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALfloat valf; ALCenum err; + /* Explicitly hold the list lock while taking the BackendLock in case the + * device is asynchronously destropyed, to ensure this new context is + * properly cleaned up after being made. + */ LockLists(); if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected) { @@ -3609,13 +3617,18 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALCdevice *Device; LockLists(); - /* alcGetContextsDevice sets an error for invalid contexts */ - Device = alcGetContextsDevice(context); + if(!VerifyContext(&context)) + { + UnlockLists(); + alcSetError(NULL, ALC_INVALID_CONTEXT); + return; + } + + Device = context->Device; if(Device) { almtx_lock(&Device->BackendLock); - ReleaseContext(context, Device); - if(!ATOMIC_LOAD_SEQ(&Device->ContextList)) + if(!ReleaseContext(context, Device)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; @@ -3623,6 +3636,8 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) almtx_unlock(&Device->BackendLock); } UnlockLists(); + + ALCcontext_DecRef(context); } -- cgit v1.2.3 From c68dac879c7f9f6e76d86eb9c95a1dd5a27fc565 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 Mar 2017 00:11:38 -0700 Subject: Update the ambisonic docs to mention the near-field effect --- docs/ambdec.txt | 2 +- docs/ambisonics.txt | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/ambdec.txt b/docs/ambdec.txt index 5a3ba988..1f328937 100644 --- a/docs/ambdec.txt +++ b/docs/ambdec.txt @@ -75,7 +75,7 @@ Soft has its own config option for this, this is ignored. /opt/xover_freq Specifies the crossover frequency for dual-band decoders. Frequencies less than this are fed to the low-frequency matrix, and frequencies greater than this are -fed to the high-freqyency matrix. Unused for single-band decoders. +fed to the high-frequency matrix. Unused for single-band decoders. /opt/xover_ratio Specifies the volume ratio between the frequency bands. Values greater than 0 diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt index 4e4d8faa..b50e76c2 100644 --- a/docs/ambisonics.txt +++ b/docs/ambisonics.txt @@ -20,8 +20,8 @@ of any specific speaker layout, so with a proper decoder the same recording can be played back on a variety of speaker setups, from quadrophonic and hexagonal to cubic and other periphonic (with height) layouts. -Although it was developed over 30 years ago, various factors held ambisonics -back from really taking hold in the consumer market. However, given the solid +Although it was developed decades ago, various factors held ambisonics back +from really taking hold in the consumer market. However, given the solid theories backing it, as well as the potential and practical benefits on offer, it continued to be a topic of research over the years, with improvements being made over the original design. One of the improvements made is the use of @@ -60,6 +60,13 @@ proper sound wave that's perceived to come from the intended direction. Doing this creates a larger sweet spot, allowing the perceived sound direction to remain correct over a larger area around the center of the speakers. +In addition, Ambisonics can encode the near-field effect of sounds, effectively +capturing the sound distance. The near-field effect is a subtle low-frequency +boost as a result of wave-front curvature, and properly compensating for this +occuring with the output speakers (as well as emulating it with a synthesized +soundfield) can create an improved sense of distance for sounds that move near +or far. + How Is It Used? =============== @@ -69,8 +76,8 @@ the speaker setup the user has. Since the OpenAL API does not explicitly handle the output channel configuration, it has a lot of leeway in how to deal with the audio before it's played back for the user to hear. Consequently, OpenAL Soft (or any other OpenAL implementation that wishes to) can render using -Ambisonics and decode the ambisonic mix for a high level of directional -accuracy over what simple pan-pot could provide. +Ambisonics and decode the ambisonic mix for a high level of accuracy over what +simple pan-pot could provide. This is effectively what the high-quality mode option does, when given an appropriate decoder configuation for the playback channel layout. 3D rendering @@ -113,7 +120,7 @@ response, with ambisonics or not. It will do the best it can, but there are trade-offs between detail and accuracy. Another issue lies with HRTF. While it's certainly possible to play an -ambisonic mix using HRTF, doing so with a high degree of spatial detail -requires a fair amount of resources, in both memory and processing time. And -even with it, mixing sounds with HRTF directly will still be better for -positional accuracy. +ambisonic mix using HRTF and retain a sense of 3D sound, doing so with a high +degree of spatial detail requires a fair amount of resources, in both memory +and processing time. And even with it, mixing sounds with HRTF directly will +still be better for positional accuracy. -- cgit v1.2.3 From 7dc3fb98abad1876410b2913e7ae2b344e08f6ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 02:15:24 -0700 Subject: Use the correct types' sizes for HRTF storage --- Alc/hrtf.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 91895cb9..ab2708cb 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -389,11 +389,11 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(!failed) { size_t total = sizeof(struct Hrtf); - total += sizeof(azCount[0])*evCount; + total += sizeof(Hrtf->azCount[0])*evCount; total = (total+1)&~1; /* Align for (u)short fields */ - total += sizeof(evOffset[0])*evCount; - total += sizeof(coeffs[0])*irSize*irCount; - total += sizeof(delays[0])*irCount; + total += sizeof(Hrtf->evOffset[0])*evCount; + total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->delays[0])*irCount; total += al_string_length(filename)+1; Hrtf = al_calloc(16, total); @@ -570,11 +570,11 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(!failed) { size_t total = sizeof(struct Hrtf); - total += sizeof(azCount[0])*evCount; + total += sizeof(Hrtf->azCount[0])*evCount; total = (total+1)&~1; /* Align for (u)short fields */ - total += sizeof(evOffset[0])*evCount; - total += sizeof(coeffs[0])*irSize*irCount; - total += sizeof(delays[0])*irCount; + total += sizeof(Hrtf->evOffset[0])*evCount; + total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->delays[0])*irCount; total += al_string_length(filename)+1; Hrtf = al_calloc(16, total); -- cgit v1.2.3 From 2a8970368f0161bcd3dbbc85ab9b50a83f128b0b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 03:45:26 -0700 Subject: Combine some HRTF loading code --- Alc/hrtf.c | 150 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 72 insertions(+), 78 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index ab2708cb..a086c1a3 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -231,6 +231,74 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize } +static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount, + const ALubyte *azCount, const ALushort *evOffset, + const ALshort *coeffs, const ALubyte *delays, + const_al_string filename) +{ + struct Hrtf *Hrtf; + size_t total; + + total = sizeof(struct Hrtf); + total += sizeof(Hrtf->azCount[0])*evCount; + total = RoundUp(total, 2); /* Align for (u)short fields */ + total += sizeof(Hrtf->evOffset[0])*evCount; + total += sizeof(Hrtf->coeffs[0])*irSize*irCount; + total += sizeof(Hrtf->delays[0])*irCount; + total += al_string_length(filename)+1; + + Hrtf = al_calloc(16, total); + if(Hrtf == NULL) + ERR("Out of memory.\n"); + else + { + uintptr_t offset = sizeof(struct Hrtf); + char *base = (char*)Hrtf; + ALushort *_evOffset; + ALubyte *_azCount; + ALubyte *_delays; + ALshort *_coeffs; + char *_name; + ALsizei i; + + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->evCount = evCount; + + /* Set up pointers to storage following the main HRTF struct. */ + _azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount; + offset += sizeof(_azCount[0])*evCount; + + offset = RoundUp(offset, 2); /* Align for (u)short fields */ + _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset; + offset += sizeof(_evOffset[0])*evCount; + + _coeffs = (ALshort*)(base + offset); Hrtf->coeffs = _coeffs; + offset += sizeof(_coeffs[0])*irSize*irCount; + + _delays = (ALubyte*)(base + offset); Hrtf->delays = _delays; + offset += sizeof(_delays[0])*irCount; + + _name = (char*)(base + offset); Hrtf->filename = _name; + offset += sizeof(_name[0])*(al_string_length(filename)+1); + + Hrtf->next = NULL; + + /* Copy input data to storage. */ + for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; + for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; + for(i = 0;i < irSize*irCount;i++) _coeffs[i] = coeffs[i]; + for(i = 0;i < irCount;i++) _delays[i] = delays[i]; + for(i = 0;i < (ALsizei)al_string_length(filename);i++) + _name[i] = VECTOR_ELEM(filename, i); + _name[i] = '\0'; + + assert(offset == total); + } + + return Hrtf; +} + static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; @@ -387,45 +455,8 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str } if(!failed) - { - size_t total = sizeof(struct Hrtf); - total += sizeof(Hrtf->azCount[0])*evCount; - total = (total+1)&~1; /* Align for (u)short fields */ - total += sizeof(Hrtf->evOffset[0])*evCount; - total += sizeof(Hrtf->coeffs[0])*irSize*irCount; - total += sizeof(Hrtf->delays[0])*irCount; - total += al_string_length(filename)+1; - - Hrtf = al_calloc(16, total); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - char *base = (char*)Hrtf; - uintptr_t offset = sizeof(*Hrtf); - - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]); - offset = (offset+1)&~1; /* Align for (u)short fields */ - Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]); - Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]); - Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]); - Hrtf->filename = ((char*)(base + offset)); - Hrtf->next = NULL; - - memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); - memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); - memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); - memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); - memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); - } + Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount, + evOffset, coeffs, delays, filename); free(azCount); free(evOffset); @@ -568,45 +599,8 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str } if(!failed) - { - size_t total = sizeof(struct Hrtf); - total += sizeof(Hrtf->azCount[0])*evCount; - total = (total+1)&~1; /* Align for (u)short fields */ - total += sizeof(Hrtf->evOffset[0])*evCount; - total += sizeof(Hrtf->coeffs[0])*irSize*irCount; - total += sizeof(Hrtf->delays[0])*irCount; - total += al_string_length(filename)+1; - - Hrtf = al_calloc(16, total); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - char *base = (char*)Hrtf; - uintptr_t offset = sizeof(*Hrtf); - - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(base + offset)); offset += evCount*sizeof(Hrtf->azCount[0]); - offset = (offset+1)&~1; /* Align for (u)short fields */ - Hrtf->evOffset = ((ALushort*)(base + offset)); offset += evCount*sizeof(Hrtf->evOffset[0]); - Hrtf->coeffs = ((ALshort*)(base + offset)); offset += irSize*irCount*sizeof(Hrtf->coeffs[0]); - Hrtf->delays = ((ALubyte*)(base + offset)); offset += irCount*sizeof(Hrtf->delays[0]); - Hrtf->filename = ((char*)(base + offset)); - Hrtf->next = NULL; - - memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); - memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); - memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); - memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); - memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); - } + Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount, + evOffset, coeffs, delays, filename); free(evOffset); free(coeffs); -- cgit v1.2.3 From 9fb07101dc0ab5b7f2785584b4c29e18232ba99c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 04:25:22 -0700 Subject: Load HRTF coefficients as pre-normalized floats --- Alc/hrtf.c | 85 ++++++++++++++++++++++++++++++++++---------------------------- Alc/hrtf.h | 2 +- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index a086c1a3..0f4c53f6 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -51,7 +51,7 @@ static const ALchar magicMarker01[8] = "MinPHR01"; /* First value for pass-through coefficients (remaining are 0), used for omni- * directional sounds. */ -static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/; +static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; static struct Hrtf *LoadedHrtfs = NULL; @@ -110,12 +110,12 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /* Calculate the normalized and attenuated HRIR coefficients. */ i = 0; - coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact) * (1.0f/32767.0f); - coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact) * (1.0f/32767.0f); + coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact); + coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact); for(i = 1;i < Hrtf->irSize;i++) { - coeffs[i][0] = Hrtf->coeffs[lidx+i]*(1.0f/32767.0f) * dirfact; - coeffs[i][1] = Hrtf->coeffs[ridx+i]*(1.0f/32767.0f) * dirfact; + coeffs[i][0] = Hrtf->coeffs[lidx+i] * dirfact; + coeffs[i][1] = Hrtf->coeffs[ridx+i] * dirfact; } } @@ -132,7 +132,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize ALsizei min_delay = HRTF_HISTORY_LENGTH; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; - ALsizei i, j, c, b; + ALsizei i, c, b; for(c = 0;c < AmbiCount;c++) { @@ -163,63 +163,69 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); for(c = 0;c < AmbiCount;c++) { - const ALshort *fir; + const ALfloat *fir; ALsizei delay; - /* Convert the left FIR from shorts to float */ + /* Add to the left output coefficients with the specified delay. */ fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; + delay = Hrtf->delays[lidx[c]] - min_delay; if(NUM_BANDS == 1) { - for(i = 0;i < Hrtf->irSize;i++) - temps[0][i] = fir[i] / 32767.0f; + for(i = 0;i < NumChannels;++i) + { + ALsizei j = delay, k = 0; + while(j < HRIR_LENGTH && k < Hrtf->irSize) + state->Chan[i].Coeffs[j++][0] += fir[k++] * AmbiMatrix[c][0][i]; + } } else { /* Band-split left HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i] / 32767.0f; + temps[2][i] = fir[i]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - } - /* Add to the left output coefficients with the specified delay. */ - delay = Hrtf->delays[lidx[c]] - min_delay; - for(i = 0;i < NumChannels;++i) - { - for(b = 0;b < NUM_BANDS;b++) + for(i = 0;i < NumChannels;++i) { - ALsizei k = 0; - for(j = delay;j < HRIR_LENGTH;++j) - state->Chan[i].Coeffs[j][0] += temps[b][k++] * AmbiMatrix[c][b][i]; + for(b = 0;b < NUM_BANDS;b++) + { + ALsizei j = delay, k = 0; + while(j < HRIR_LENGTH) + state->Chan[i].Coeffs[j++][0] += temps[b][k++] * AmbiMatrix[c][b][i]; + } } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); - /* Convert the right FIR from shorts to float */ + /* Add to the right output coefficients with the specified delay. */ fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; + delay = Hrtf->delays[ridx[c]] - min_delay; if(NUM_BANDS == 1) { - for(i = 0;i < Hrtf->irSize;i++) - temps[0][i] = fir[i] / 32767.0f; + for(i = 0;i < NumChannels;++i) + { + ALsizei j = delay, k = 0; + while(j < HRIR_LENGTH && k < Hrtf->irSize) + state->Chan[i].Coeffs[j++][1] += fir[k++] * AmbiMatrix[c][0][i]; + } } else { /* Band-split right HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i] / 32767.0f; + temps[2][i] = fir[i]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); - } - /* Add to the right output coefficients with the specified delay. */ - delay = Hrtf->delays[ridx[c]] - min_delay; - for(i = 0;i < NumChannels;++i) - { - for(b = 0;b < NUM_BANDS;b++) + for(i = 0;i < NumChannels;++i) { - ALuint k = 0; - for(j = delay;j < HRIR_LENGTH;++j) - state->Chan[i].Coeffs[j][1] += temps[b][k++] * AmbiMatrix[c][b][i]; + for(b = 0;b < NUM_BANDS;b++) + { + ALsizei j = delay, k = 0; + while(j < HRIR_LENGTH) + state->Chan[i].Coeffs[j++][1] += temps[b][k++] * AmbiMatrix[c][b][i]; + } } } max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); @@ -241,8 +247,9 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount total = sizeof(struct Hrtf); total += sizeof(Hrtf->azCount[0])*evCount; - total = RoundUp(total, 2); /* Align for (u)short fields */ + total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ total += sizeof(Hrtf->evOffset[0])*evCount; + total = RoundUp(total, sizeof(ALfloat)); /* Align for float fields */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; total += al_string_length(filename)+1; @@ -257,7 +264,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount ALushort *_evOffset; ALubyte *_azCount; ALubyte *_delays; - ALshort *_coeffs; + ALfloat *_coeffs; char *_name; ALsizei i; @@ -269,11 +276,12 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount _azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount; offset += sizeof(_azCount[0])*evCount; - offset = RoundUp(offset, 2); /* Align for (u)short fields */ + offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset; offset += sizeof(_evOffset[0])*evCount; - _coeffs = (ALshort*)(base + offset); Hrtf->coeffs = _coeffs; + offset = RoundUp(offset, sizeof(ALfloat)); /* Align for float fields */ + _coeffs = (ALfloat*)(base + offset); Hrtf->coeffs = _coeffs; offset += sizeof(_coeffs[0])*irSize*irCount; _delays = (ALubyte*)(base + offset); Hrtf->delays = _delays; @@ -287,7 +295,8 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount /* Copy input data to storage. */ for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; - for(i = 0;i < irSize*irCount;i++) _coeffs[i] = coeffs[i]; + for(i = 0;i < irSize*irCount;i++) + _coeffs[i] = coeffs[i] / 32768.0f; for(i = 0;i < irCount;i++) _delays[i] = delays[i]; for(i = 0;i < (ALsizei)al_string_length(filename);i++) _name[i] = VECTOR_ELEM(filename, i); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 7391131f..c5257d3d 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -15,7 +15,7 @@ struct Hrtf { const ALubyte *azCount; const ALushort *evOffset; - const ALshort *coeffs; + const ALfloat *coeffs; const ALubyte *delays; const char *filename; -- cgit v1.2.3 From ac8b4aa5f66db68609459a9444c2a7083b2e8f28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 06:54:46 -0700 Subject: Convert integer samples to float using a power-of-2 divisor This should cut down on unnecessary quantization noise (however minor) for 8- and 16-bit samples. Unfortunately a power-of-2 multiple can't be used as easily for converting float samples to integer, due to integer types having a non- power-of-2 maximum amplitude (it'd require more per-sample clamping). --- Alc/mixer.c | 4 ++-- OpenAL32/sample_cvt.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index b8f4b91f..88dbde88 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -283,10 +283,10 @@ void aluInitMixer(void) static inline ALfloat Sample_ALbyte(ALbyte val) -{ return val * (1.0f/127.0f); } +{ return val * (1.0f/128.0f); } static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32767.0f); } +{ return val * (1.0f/32768.0f); } static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index aff3de83..daea548a 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -608,17 +608,17 @@ static inline T Conv_##T##_##UT(UT val) { return (T)Conv_##ST##_##UT(val) * OP; #define DECL_TEMPLATE2(T1, T2, OP) \ DECL_TEMPLATE(T1, AL##T2, ALu##T2, OP) -DECL_TEMPLATE2(ALfloat, byte, (1.0f/127.0f)) -DECL_TEMPLATE2(ALdouble, byte, (1.0/127.0)) -DECL_TEMPLATE2(ALfloat, short, (1.0f/32767.0f)) -DECL_TEMPLATE2(ALdouble, short, (1.0/32767.0)) -DECL_TEMPLATE2(ALdouble, int, (1.0/2147483647.0)) +DECL_TEMPLATE2(ALfloat, byte, (1.0f/128.0f)) +DECL_TEMPLATE2(ALdouble, byte, (1.0/128.0)) +DECL_TEMPLATE2(ALfloat, short, (1.0f/32768.0f)) +DECL_TEMPLATE2(ALdouble, short, (1.0/32768.0)) +DECL_TEMPLATE2(ALdouble, int, (1.0/2147483648.0)) /* Special handling for int32 to float32, since it would overflow. */ static inline ALfloat Conv_ALfloat_ALint(ALint val) -{ return (ALfloat)(val>>7) * (1.0f/16777215.0f); } +{ return (ALfloat)(val>>7) * (1.0f/16777216.0f); } static inline ALfloat Conv_ALfloat_ALuint(ALuint val) -{ return (ALfloat)(Conv_ALint_ALuint(val)>>7) * (1.0f/16777215.0f); } +{ return (ALfloat)(Conv_ALint_ALuint(val)>>7) * (1.0f/16777216.0f); } #undef DECL_TEMPLATE2 #undef DECL_TEMPLATE -- cgit v1.2.3 From 355a8898cf4886e4193d43ffa0b7204c1eef7d93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 08:15:20 -0700 Subject: Remove the (u)byte3 sample formats They're not accessible since the removal of the buffer_samples extension, and were kind of clunky to work with as 24-bit packed values. --- OpenAL32/Include/alBuffer.h | 2 - OpenAL32/alBuffer.c | 4 -- OpenAL32/sample_cvt.c | 112 +------------------------------------------- 3 files changed, 1 insertion(+), 117 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 062be452..b13e1231 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -17,8 +17,6 @@ enum UserFmtType { UserFmtUInt = AL_UNSIGNED_INT_SOFT, UserFmtFloat = AL_FLOAT_SOFT, UserFmtDouble = AL_DOUBLE_SOFT, - UserFmtByte3 = AL_BYTE3_SOFT, - UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT, UserFmtMulaw = AL_MULAW_SOFT, UserFmtAlaw = 0x10000000, UserFmtIMA4, diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 45a8cb5b..e45b8d08 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -183,8 +183,6 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtInt: case UserFmtUInt: - case UserFmtByte3: - case UserFmtUByte3: case UserFmtDouble: framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; if((size%framesize) != 0) @@ -1086,8 +1084,6 @@ ALsizei BytesFromUserFmt(enum UserFmtType type) case UserFmtUInt: return sizeof(ALuint); case UserFmtFloat: return sizeof(ALfloat); case UserFmtDouble: return sizeof(ALdouble); - case UserFmtByte3: return sizeof(ALbyte[3]); - case UserFmtUByte3: return sizeof(ALubyte[3]); case UserFmtMulaw: return sizeof(ALubyte); case UserFmtAlaw: return sizeof(ALubyte); case UserFmtIMA4: break; /* not handled here */ diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index daea548a..22f2e898 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -174,14 +174,6 @@ typedef ALubyte ALmulaw; typedef ALubyte ALalaw; typedef ALubyte ALima4; typedef ALubyte ALmsadpcm; -typedef struct { - ALbyte b[3]; -} ALbyte3; -static_assert(sizeof(ALbyte3)==sizeof(ALbyte[3]), "ALbyte3 size is not 3"); -typedef struct { - ALubyte b[3]; -} ALubyte3; -static_assert(sizeof(ALubyte3)==sizeof(ALubyte[3]), "ALubyte3 size is not 3"); static inline ALshort DecodeMuLaw(ALmulaw val) { return muLawDecompressionTable[val]; } @@ -498,49 +490,6 @@ static void EncodeMSADPCMBlock(ALmsadpcm *dst, const ALshort *src, ALint *sample } -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) -{ - if(IS_LITTLE_ENDIAN) - { - ALbyte3 ret = {{ val, val>>8, val>>16 }}; - return ret; - } - else - { - ALbyte3 ret = {{ val>>16, val>>8, val }}; - return ret; - } -} - -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) -{ - if(IS_LITTLE_ENDIAN) - { - ALubyte3 ret = {{ val, val>>8, val>>16 }}; - return ret; - } - else - { - ALubyte3 ret = {{ val>>16, val>>8, val }}; - return ret; - } -} - - /* Define same-type pass-through sample conversion functions (excludes ADPCM, * which are block-based). */ #define DECL_TEMPLATE(T) \ @@ -552,8 +501,6 @@ DECL_TEMPLATE(ALshort); DECL_TEMPLATE(ALushort); DECL_TEMPLATE(ALint); DECL_TEMPLATE(ALuint); -DECL_TEMPLATE(ALbyte3); -DECL_TEMPLATE(ALubyte3); DECL_TEMPLATE(ALalaw); DECL_TEMPLATE(ALmulaw); @@ -652,35 +599,6 @@ static inline ALuint Conv_ALuint_ALfloat(ALfloat val) #undef DECL_TEMPLATE -/* Define byte3 and ubyte3 functions (goes through int and uint functions). */ -#define DECL_TEMPLATE(T) \ -static inline ALbyte3 Conv_ALbyte3_##T(T val) \ -{ return EncodeByte3(Conv_ALint_##T(val)>>8); } \ -static inline T Conv_##T##_ALbyte3(ALbyte3 val) \ -{ return Conv_##T##_ALint(DecodeByte3(val)<<8); } \ - \ -static inline ALubyte3 Conv_ALubyte3_##T(T val) \ -{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); } \ -static inline T Conv_##T##_ALubyte3(ALubyte3 val) \ -{ return Conv_##T##_ALuint(DecodeUByte3(val)<<8); } - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) - -#undef DECL_TEMPLATE - -/* Define byte3 <-> ubyte3 functions. */ -static inline ALbyte3 Conv_ALbyte3_ALubyte3(ALubyte3 val) -{ return EncodeByte3(DecodeUByte3(val)-8388608); } -static inline ALubyte3 Conv_ALubyte3_ALbyte3(ALbyte3 val) -{ return EncodeUByte3(DecodeByte3(val)+8388608); } - /* Define muLaw and aLaw functions (goes through short functions). */ #define DECL_TEMPLATE(T) \ static inline ALmulaw Conv_ALmulaw_##T(T val) \ @@ -701,8 +619,6 @@ DECL_TEMPLATE(ALint) DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -735,9 +651,7 @@ DECL_TEMPLATE(T, ALuint) \ DECL_TEMPLATE(T, ALfloat) \ DECL_TEMPLATE(T, ALdouble) \ DECL_TEMPLATE(T, ALmulaw) \ -DECL_TEMPLATE(T, ALalaw) \ -DECL_TEMPLATE(T, ALbyte3) \ -DECL_TEMPLATE(T, ALubyte3) +DECL_TEMPLATE(T, ALalaw) DECL_TEMPLATE2(ALbyte) DECL_TEMPLATE2(ALubyte) @@ -749,8 +663,6 @@ DECL_TEMPLATE2(ALfloat) DECL_TEMPLATE2(ALdouble) DECL_TEMPLATE2(ALmulaw) DECL_TEMPLATE2(ALalaw) -DECL_TEMPLATE2(ALbyte3) -DECL_TEMPLATE2(ALubyte3) #undef DECL_TEMPLATE2 #undef DECL_TEMPLATE @@ -800,8 +712,6 @@ DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -853,8 +763,6 @@ DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -906,8 +814,6 @@ DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -957,8 +863,6 @@ DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -1035,12 +939,6 @@ static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ case UserFmtMSADPCM: \ Convert_##T##_ALmsadpcm(dst, src, numchans, len, align); \ break; \ - case UserFmtByte3: \ - Convert_##T##_ALbyte3(dst, src, numchans, len, align); \ - break; \ - case UserFmtUByte3: \ - Convert_##T##_ALubyte3(dst, src, numchans, len, align); \ - break; \ } \ } @@ -1056,8 +954,6 @@ DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) DECL_TEMPLATE(ALima4) DECL_TEMPLATE(ALmsadpcm) -DECL_TEMPLATE(ALbyte3) -DECL_TEMPLATE(ALubyte3) #undef DECL_TEMPLATE @@ -1102,11 +998,5 @@ void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum case UserFmtMSADPCM: Convert_ALmsadpcm(dst, src, srcType, numchans, len, align); break; - case UserFmtByte3: - Convert_ALbyte3(dst, src, srcType, numchans, len, align); - break; - case UserFmtUByte3: - Convert_ALubyte3(dst, src, srcType, numchans, len, align); - break; } } -- cgit v1.2.3 From 90c005bbec6cc9c8226bc57028c896c54801b580 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 09:11:28 -0700 Subject: Convert float samples to integer using a power-of-2 multiple --- Alc/ALu.c | 22 +++++++++------------- OpenAL32/sample_cvt.c | 14 ++++++++------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f0e4d735..710b64be 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1306,34 +1306,30 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } -/* Specialized function to clamp to [-1, +1] with only one branch. This also - * converts NaN to 0. */ -static inline ALfloat aluClampf(ALfloat val) -{ - if(fabsf(val) <= 1.0f) return val; - return (ALfloat)((0.0f < val) - (val < 0.0f)); -} - static inline ALfloat aluF2F(ALfloat val) { return val; } +#define S25_MAX_NORM (16777215.0f/16777216.0f) static inline ALint aluF2I(ALfloat val) { - /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max - * integer range normalized floats can be safely converted to. + /* Floats only have a 24-bit mantissa, so [-16777216, +16777216] is the max + * integer range normalized floats can be safely converted to (a bit of the + * exponent helps out, effectively giving 25 bits). */ - return fastf2i(aluClampf(val)*16777215.0f)<<7; + return fastf2i(clampf(val, -1.0f, S25_MAX_NORM)*16777216.0f)<<7; } static inline ALuint aluF2UI(ALfloat val) { return aluF2I(val)+2147483648u; } +#define S16_MAX_NORM (32767.0f/32768.0f) static inline ALshort aluF2S(ALfloat val) -{ return fastf2i(aluClampf(val)*32767.0f); } +{ return fastf2i(clampf(val, -1.0f, S16_MAX_NORM)*32768.0f); } static inline ALushort aluF2US(ALfloat val) { return aluF2S(val)+32768; } +#define S8_MAX_NORM (127.0f/128.0f) static inline ALbyte aluF2B(ALfloat val) -{ return fastf2i(aluClampf(val)*127.0f); } +{ return fastf2i(clampf(val, -1.0f, S8_MAX_NORM)*128.0f); } static inline ALubyte aluF2UB(ALfloat val) { return aluF2B(val)+128; } diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 22f2e898..89c2a408 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -574,9 +574,10 @@ static inline ALfloat Conv_ALfloat_ALuint(ALuint val) #define DECL_TEMPLATE(FT, T, smin, smax) \ static inline AL##T Conv_AL##T##_##FT(FT val) \ { \ - if(val > 1.0f) return smax; \ - if(val < -1.0f) return smin; \ - return (AL##T)(val * (FT)smax); \ + val *= (FT)smax + 1; \ + if(val >= (FT)smax) return smax; \ + if(val <= (FT)smin) return smin; \ + return (AL##T)val; \ } \ static inline ALu##T Conv_ALu##T##_##FT(FT val) \ { return Conv_ALu##T##_AL##T(Conv_AL##T##_##FT(val)); } @@ -590,9 +591,10 @@ DECL_TEMPLATE(ALdouble, int, -2147483647-1, 2147483647) /* Special handling for float32 to int32, since it would overflow. */ static inline ALint Conv_ALint_ALfloat(ALfloat val) { - if(val > 1.0f) return 2147483647; - if(val < -1.0f) return -2147483647-1; - return (ALint)(val * 16777215.0f) << 7; + val *= 16777216.0f; + if(val >= 16777215.0f) return 0x7fffff80/*16777215 << 7*/; + if(val <= -16777216.0f) return 0x80000000/*-16777216 << 7*/; + return (ALint)val << 7; } static inline ALuint Conv_ALuint_ALfloat(ALfloat val) { return Conv_ALuint_ALint(Conv_ALint_ALfloat(val)); } -- cgit v1.2.3 From af833c855444d61521be9c115a8be0ac61fadedf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 09:21:31 -0700 Subject: Remove a couple more uses of BYTE3 --- OpenAL32/alBuffer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index e45b8d08..376741bd 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1324,8 +1324,6 @@ static ALboolean IsValidType(ALenum type) case AL_UNSIGNED_INT_SOFT: case AL_FLOAT_SOFT: case AL_DOUBLE_SOFT: - case AL_BYTE3_SOFT: - case AL_UNSIGNED_BYTE3_SOFT: case AL_MULAW_SOFT: return AL_TRUE; } -- cgit v1.2.3 From 5f245d5950ea7fd5938f72720f93ff5c5879eff6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Mar 2017 23:22:06 -0700 Subject: Avoid some unnecessary string reallocation --- Alc/hrtf.c | 101 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 0f4c53f6..2f6e9983 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -616,7 +616,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str return Hrtf; } -static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) +static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) { HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; struct Hrtf *hrtf = NULL; @@ -626,58 +626,58 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) const char *ext; int i; -#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0) +#define MATCH_FNAME(i) (al_string_cmp_cstr(filename, (i)->hrtf->filename) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); - goto done; + TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(filename)); + return; } #undef MATCH_FNAME entry.hrtf = LoadedHrtfs; while(entry.hrtf) { - if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0) + if(al_string_cmp_cstr(filename, entry.hrtf->filename) == 0) { - TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename)); + TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(filename)); goto skip_load; } entry.hrtf = entry.hrtf->next; } - TRACE("Loading %s...\n", al_string_get_cstr(*filename)); - fmap = MapFileToMem(al_string_get_cstr(*filename)); + TRACE("Loading %s...\n", al_string_get_cstr(filename)); + fmap = MapFileToMem(al_string_get_cstr(filename)); if(fmap.ptr == NULL) { - ERR("Could not open %s\n", al_string_get_cstr(*filename)); - goto done; + ERR("Could not open %s\n", al_string_get_cstr(filename)); + return; } if(fmap.len < sizeof(magicMarker01)) - ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), fmap.len); + ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(filename), fmap.len); else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), - fmap.len-sizeof(magicMarker01), *filename + fmap.len-sizeof(magicMarker01), filename ); } else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), - fmap.len-sizeof(magicMarker00), *filename + fmap.len-sizeof(magicMarker00), filename ); } else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), (const char*)fmap.ptr); + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(filename), (const char*)fmap.ptr); UnmapFileMem(&fmap); if(!hrtf) { - ERR("Failed to load %s\n", al_string_get_cstr(*filename)); - goto done; + ERR("Failed to load %s\n", al_string_get_cstr(filename)); + return; } hrtf->next = LoadedHrtfs; @@ -689,9 +689,9 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - name = strrchr(al_string_get_cstr(*filename), '/'); - if(!name) name = strrchr(al_string_get_cstr(*filename), '\\'); - if(!name) name = al_string_get_cstr(*filename); + name = strrchr(al_string_get_cstr(filename), '/'); + if(!name) name = strrchr(al_string_get_cstr(filename), '\\'); + if(!name) name = al_string_get_cstr(filename); else ++name; ext = strrchr(name, '.'); @@ -716,71 +716,68 @@ skip_load: } while(iter != VECTOR_END(*list)); TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name), - al_string_get_cstr(*filename)); + al_string_get_cstr(filename)); VECTOR_PUSH_BACK(*list, entry); - -done: - al_string_deinit(filename); } /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename) +static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, const_al_string filename) { HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; struct Hrtf *hrtf = NULL; const HrtfEntry *iter; int i; -#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0) +#define MATCH_FNAME(i) (al_string_cmp_cstr(filename, (i)->hrtf->filename) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename)); - goto done; + TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(filename)); + return; } #undef MATCH_FNAME entry.hrtf = LoadedHrtfs; while(entry.hrtf) { - if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0) + if(al_string_cmp_cstr(filename, entry.hrtf->filename) == 0) { - TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename)); + TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(filename)); goto skip_load; } entry.hrtf = entry.hrtf->next; } - TRACE("Loading %s...\n", al_string_get_cstr(*filename)); + TRACE("Loading %s...\n", al_string_get_cstr(filename)); if(datalen < sizeof(magicMarker01)) { - ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), datalen); - goto done; + ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(filename), datalen); + return; } if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); hrtf = LoadHrtf01(data+sizeof(magicMarker01), - datalen-sizeof(magicMarker01), *filename + datalen-sizeof(magicMarker01), filename ); } else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); hrtf = LoadHrtf00(data+sizeof(magicMarker00), - datalen-sizeof(magicMarker00), *filename + datalen-sizeof(magicMarker00), filename ); } else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), data); + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(filename), data); if(!hrtf) { - ERR("Failed to load %s\n", al_string_get_cstr(*filename)); - goto done; + ERR("Failed to load %s\n", al_string_get_cstr(filename)); + return; } hrtf->next = LoadedHrtfs; @@ -792,7 +789,7 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t skip_load: i = 0; do { - al_string_copy(&entry.name, *filename); + al_string_copy(&entry.name, filename); if(i != 0) { char str[64]; @@ -808,9 +805,6 @@ skip_load: TRACE("Adding built-in entry \"%s\"\n", al_string_get_cstr(entry.name)); VECTOR_PUSH_BACK(*list, entry); - -done: - al_string_deinit(filename); } @@ -917,6 +911,7 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) { + al_string pname = AL_STRING_INIT_STATIC(); while(pathlist && *pathlist) { const char *next, *end; @@ -939,49 +934,53 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) --end; if(end != pathlist) { - al_string pname = AL_STRING_INIT_STATIC(); vector_al_string flist; + size_t i; al_string_append_range(&pname, pathlist, end); flist = SearchDataFiles(".mhr", al_string_get_cstr(pname)); - VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); + for(i = 0;i < VECTOR_SIZE(flist);i++) + AddFileEntry(&list, VECTOR_ELEM(flist, i)); + VECTOR_FOR_EACH(al_string, flist, al_string_deinit); VECTOR_DEINIT(flist); - - al_string_deinit(&pname); } pathlist = next; } + + al_string_deinit(&pname); } else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables")) ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) { + al_string ename = AL_STRING_INIT_STATIC(); vector_al_string flist; const ALubyte *rdata; - size_t rsize; + size_t rsize, i; flist = SearchDataFiles(".mhr", "openal/hrtf"); - VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); + for(i = 0;i < VECTOR_SIZE(flist);i++) + AddFileEntry(&list, VECTOR_ELEM(flist, i)); + VECTOR_FOR_EACH(al_string, flist, al_string_deinit); VECTOR_DEINIT(flist); rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); if(rdata != NULL && rsize > 0) { - al_string ename = AL_STRING_INIT_STATIC(); al_string_copy_cstr(&ename, "Built-In 44100hz"); - AddBuiltInEntry(&list, rdata, rsize, &ename); + AddBuiltInEntry(&list, rdata, rsize, ename); } rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); if(rdata != NULL && rsize > 0) { - al_string ename = AL_STRING_INIT_STATIC(); al_string_copy_cstr(&ename, "Built-In 48000hz"); - AddBuiltInEntry(&list, rdata, rsize, &ename); + AddBuiltInEntry(&list, rdata, rsize, ename); } + al_string_deinit(&ename); } if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) -- cgit v1.2.3 From 1ef916a54b56fa07821f4a72699ada55894fdca6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Apr 2017 01:08:18 -0700 Subject: Make a pointer restrict and assume aligned --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 710b64be..2cac3ce0 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1341,7 +1341,7 @@ static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ { \ - const ALfloat *in = InBuffer[j]; \ + const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \ T *restrict out = (T*)OutBuffer + j; \ const ALfloat gain = distcomp[j].Gain; \ const ALsizei base = distcomp[j].Length; \ -- cgit v1.2.3 From 52112b0b8d796aa1617a560288ab12dd027fd99b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Apr 2017 02:38:44 -0700 Subject: Constify a variable --- Alc/ALu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 2cac3ce0..9e2b041f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1450,10 +1450,10 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) /* effect slot processing */ for(i = 0;i < auxslots->count;i++) { - ALeffectslot *slot = auxslots->slot[i]; + const ALeffectslot *slot = auxslots->slot[i]; ALeffectState *state = slot->Params.EffectState; - V(state,process)(SamplesToDo, SAFE_CONST(ALfloatBUFFERSIZE*,slot->WetBuffer), - state->OutBuffer, state->OutChannels); + V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer, + state->OutChannels); } ctx = ctx->next; -- cgit v1.2.3 From 13d7d6fe9574e0c19efdbbe8e0c25193fc94bc12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Apr 2017 03:00:24 -0700 Subject: Don't rely on sizeof being the offset to a struct's unsized array --- Alc/vector.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/vector.h b/Alc/vector.h index 4bb92458..8af8b40c 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -37,13 +37,14 @@ typedef const _##N* const_##N; \ if(((_x) ? (_x)->Capacity : 0) < _cap) \ { \ + ptrdiff_t data_offset = (char*)((_x)->Data) - (char*)(_x); \ size_t old_size = ((_x) ? (_x)->Size : 0); \ void *temp; \ \ - temp = al_calloc(16, sizeof(*(_x)) + sizeof((_x)->Data[0])*_cap); \ + temp = al_calloc(16, data_offset + sizeof((_x)->Data[0])*_cap); \ assert(temp != NULL); \ if((_x)) \ - memcpy(((ALubyte*)temp)+sizeof(*(_x)), (_x)->Data, \ + memcpy(((char*)temp)+data_offset, (_x)->Data, \ sizeof((_x)->Data[0])*old_size); \ \ al_free((_x)); \ -- cgit v1.2.3 From 497d078f508b773aec453584a6bd3a744127404a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Apr 2017 03:04:15 -0700 Subject: Remove a couple unused macros --- Alc/vector.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Alc/vector.h b/Alc/vector.h index 8af8b40c..ed0780e3 100644 --- a/Alc/vector.h +++ b/Alc/vector.h @@ -79,13 +79,6 @@ typedef const _##N* const_##N; _f(_iter); \ } while(0) -#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...) do { \ - _t *_iter = VECTOR_BEGIN((_x)); \ - _t *_end = VECTOR_END((_x)); \ - for(;_iter != _end;++_iter) \ - _f(__VA_ARGS__, _iter); \ -} while(0) - #define VECTOR_FIND_IF(_i, _t, _x, _f) do { \ _t *_iter = VECTOR_BEGIN((_x)); \ _t *_end = VECTOR_END((_x)); \ @@ -97,15 +90,4 @@ typedef const _##N* const_##N; (_i) = _iter; \ } while(0) -#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...) do { \ - _t *_iter = VECTOR_BEGIN((_x)); \ - _t *_end = VECTOR_END((_x)); \ - for(;_iter != _end;++_iter) \ - { \ - if(_f(__VA_ARGS__, _iter)) \ - break; \ - } \ - (_i) = _iter; \ -} while(0) - #endif /* AL_VECTOR_H */ -- cgit v1.2.3 From d52752a3fe4e6c35ceaba4261d2845dca3247c85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 1 Apr 2017 06:07:14 -0700 Subject: Recognize %-encoded characters for config section names --- Alc/alcConfig.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c index f83ffd94..5224f0f5 100644 --- a/Alc/alcConfig.c +++ b/Alc/alcConfig.c @@ -233,7 +233,61 @@ static void LoadConfigFromFile(FILE *f) curSection[0] = 0; else { - strncpy(curSection, section, sizeof(curSection)-1); + size_t len, p = 0; + do { + char *nextp = strchr(section, '%'); + if(!nextp) + { + strncpy(curSection+p, section, sizeof(curSection)-1-p); + break; + } + + len = nextp - section; + if(len > sizeof(curSection)-1-p) + len = sizeof(curSection)-1-p; + strncpy(curSection+p, section, len); + p += len; + section = nextp; + + if(((section[1] >= '0' && section[1] <= '9') || + (section[1] >= 'a' && section[1] <= 'f') || + (section[1] >= 'A' && section[1] <= 'F')) && + ((section[2] >= '0' && section[2] <= '9') || + (section[2] >= 'a' && section[2] <= 'f') || + (section[2] >= 'A' && section[2] <= 'F'))) + { + unsigned char b = 0; + if(section[1] >= '0' && section[1] <= '9') + b = (section[1]-'0') << 4; + else if(section[1] >= 'a' && section[1] <= 'f') + b = (section[1]-'a'+0xa) << 4; + else if(section[1] >= 'A' && section[1] <= 'F') + b = (section[1]-'A'+0x0a) << 4; + if(section[2] >= '0' && section[2] <= '9') + b |= (section[2]-'0'); + else if(section[2] >= 'a' && section[2] <= 'f') + b |= (section[2]-'a'+0xa); + else if(section[2] >= 'A' && section[2] <= 'F') + b |= (section[2]-'A'+0x0a); + if(p < sizeof(curSection)-1) + curSection[p++] = b; + section += 3; + } + else if(section[1] == '%') + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 2; + } + else + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 1; + } + if(p < sizeof(curSection)-1) + curSection[p] = 0; + } while(p < sizeof(curSection)-1 && *section != 0); curSection[sizeof(curSection)-1] = 0; } -- cgit v1.2.3 From b78ddc7ef7bd145a3468e520e9bc4be5c551a952 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Apr 2017 06:35:44 -0700 Subject: Make sure the mix is done after setting the looping property --- OpenAL32/alSource.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e18a00e2..071ac8d4 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -699,6 +699,15 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p WriteLock(&Source->queue_lock); ATOMIC_STORE_SEQ(&Source->looping, *values); + if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) == AL_PLAYING) + { + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } WriteUnlock(&Source->queue_lock); return AL_TRUE; -- cgit v1.2.3 From 26144ca9dffd935c3e7499b417ccb9a6ef93eea0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 4 Apr 2017 06:58:53 -0700 Subject: Rename al_string_* functions to alstr_* --- Alc/ALc.c | 38 ++++++------ Alc/alcConfig.c | 38 ++++++------ Alc/alstring.h | 36 +++++------ Alc/ambdec.c | 12 ++-- Alc/backends/alsa.c | 34 +++++------ Alc/backends/coreaudio.c | 4 +- Alc/backends/dsound.c | 26 ++++---- Alc/backends/jack.c | 12 ++-- Alc/backends/loopback.c | 2 +- Alc/backends/mmdevapi.c | 46 +++++++------- Alc/backends/null.c | 2 +- Alc/backends/opensl.c | 2 +- Alc/backends/oss.c | 4 +- Alc/backends/portaudio.c | 4 +- Alc/backends/pulseaudio.c | 80 ++++++++++++------------ Alc/backends/qsa.c | 4 +- Alc/backends/sndio.c | 2 +- Alc/backends/solaris.c | 2 +- Alc/backends/wave.c | 2 +- Alc/backends/winmm.c | 40 ++++++------ Alc/helpers.c | 152 +++++++++++++++++++++++----------------------- Alc/hrtf.c | 108 ++++++++++++++++---------------- Alc/panning.c | 48 +++++++-------- 23 files changed, 348 insertions(+), 350 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 12d0d608..f248a998 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1311,7 +1311,7 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DO_INITCONFIG(); LockLists(); - al_string_clear(list); + alstr_clear(list); if(backendinfo->Probe) backendinfo->Probe(type); @@ -1331,7 +1331,7 @@ static void AppendDevice(const ALCchar *name, al_string *devnames) { size_t len = strlen(name); if(len > 0) - al_string_append_range(devnames, name, name+len+1); + alstr_append_range(devnames, name, name+len+1); } void AppendAllDevicesList(const ALCchar *name) { AppendDevice(name, &alcAllDevicesList); } @@ -1985,7 +1985,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } #undef TRACE_ATTR - ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "frequency", &freq); + ConfigValueUInt(alstr_get_cstr(device->DeviceName), NULL, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); device->UpdateSize = (ALuint64)device->UpdateSize * freq / @@ -1998,7 +1998,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->NumMonoSources = numMono; device->NumStereoSources = numStereo; - if(ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &new_sends)) + if(ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "sends", &new_sends)) new_sends = mini(numSends, clampi(new_sends, 0, MAX_SENDS)); else new_sends = numSends; @@ -2037,7 +2037,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(device->Type != Loopback) { const char *hrtf; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf", &hrtf)) + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf", &hrtf)) { if(strcasecmp(hrtf, "true") == 0) hrtf_userreq = Hrtf_Enable; @@ -2869,26 +2869,26 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para case ALC_ALL_DEVICES_SPECIFIER: if(VerifyDevice(&Device)) { - value = al_string_get_cstr(Device->DeviceName); + value = alstr_get_cstr(Device->DeviceName); ALCdevice_DecRef(Device); } else { ProbeAllDevicesList(); - value = al_string_get_cstr(alcAllDevicesList); + value = alstr_get_cstr(alcAllDevicesList); } break; case ALC_CAPTURE_DEVICE_SPECIFIER: if(VerifyDevice(&Device)) { - value = al_string_get_cstr(Device->DeviceName); + value = alstr_get_cstr(Device->DeviceName); ALCdevice_DecRef(Device); } else { ProbeCaptureDeviceList(); - value = al_string_get_cstr(alcCaptureDeviceList); + value = alstr_get_cstr(alcCaptureDeviceList); } break; @@ -2898,13 +2898,13 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: - if(al_string_empty(alcAllDevicesList)) + if(alstr_empty(alcAllDevicesList)) ProbeAllDevicesList(); VerifyDevice(&Device); free(alcDefaultAllDevicesSpecifier); - alcDefaultAllDevicesSpecifier = strdup(al_string_get_cstr(alcAllDevicesList)); + alcDefaultAllDevicesSpecifier = strdup(alstr_get_cstr(alcAllDevicesList)); if(!alcDefaultAllDevicesSpecifier) alcSetError(Device, ALC_OUT_OF_MEMORY); @@ -2913,13 +2913,13 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: - if(al_string_empty(alcCaptureDeviceList)) + if(alstr_empty(alcCaptureDeviceList)) ProbeCaptureDeviceList(); VerifyDevice(&Device); free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcCaptureDeviceList)); + alcCaptureDefaultDeviceSpecifier = strdup(alstr_get_cstr(alcCaptureDeviceList)); if(!alcCaptureDefaultDeviceSpecifier) alcSetError(Device, ALC_OUT_OF_MEMORY); @@ -2943,7 +2943,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para else { almtx_lock(&Device->BackendLock); - value = (Device->HrtfHandle ? al_string_get_cstr(Device->HrtfName) : ""); + value = (Device->HrtfHandle ? alstr_get_cstr(Device->HrtfName) : ""); almtx_unlock(&Device->BackendLock); ALCdevice_DecRef(Device); } @@ -3578,7 +3578,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCdevice_IncRef(ALContext->Device); InitContext(ALContext); - if(ConfigValueFloat(al_string_get_cstr(device->DeviceName), NULL, "volume-adjust", &valf)) + if(ConfigValueFloat(alstr_get_cstr(device->DeviceName), NULL, "volume-adjust", &valf)) { if(!isfinite(valf)) ERR("volume-adjust must be finite: %f\n", valf); @@ -3937,7 +3937,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } almtx_init(&device->BackendLock, almtx_plain); - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { if(strcasecmp(fmt, "fuma") == 0) { @@ -3985,7 +3985,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); } - TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); + TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); return device; } @@ -4155,7 +4155,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); } - TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); + TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); return device; } @@ -4519,7 +4519,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum { case ALC_HRTF_SPECIFIER_SOFT: if(index >= 0 && (size_t)index < VECTOR_SIZE(device->HrtfList)) - str = al_string_get_cstr(VECTOR_ELEM(device->HrtfList, index).name); + str = alstr_get_cstr(VECTOR_ELEM(device->HrtfList, index).name); else alcSetError(device, ALC_INVALID_VALUE); break; diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c index 5224f0f5..6fd01746 100644 --- a/Alc/alcConfig.c +++ b/Alc/alcConfig.c @@ -373,25 +373,25 @@ void ReadALConfig(void) if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) { al_string filepath = AL_STRING_INIT_STATIC(); - al_string_copy_wcstr(&filepath, buffer); - al_string_append_cstr(&filepath, "\\alsoft.ini"); + alstr_copy_wcstr(&filepath, buffer); + alstr_append_cstr(&filepath, "\\alsoft.ini"); - TRACE("Loading config %s...\n", al_string_get_cstr(filepath)); - f = al_fopen(al_string_get_cstr(filepath), "rt"); + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); if(f) { LoadConfigFromFile(f); fclose(f); } - al_string_deinit(&filepath); + alstr_reset(&filepath); } ppath = GetProcPath(); - if(!al_string_empty(ppath)) + if(!alstr_empty(ppath)) { - al_string_append_cstr(&ppath, "\\alsoft.ini"); - TRACE("Loading config %s...\n", al_string_get_cstr(ppath)); - f = al_fopen(al_string_get_cstr(ppath), "r"); + alstr_append_cstr(&ppath, "\\alsoft.ini"); + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + f = al_fopen(alstr_get_cstr(ppath), "r"); if(f) { LoadConfigFromFile(f); @@ -402,19 +402,19 @@ void ReadALConfig(void) if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) { al_string filepath = AL_STRING_INIT_STATIC(); - al_string_copy_wcstr(&filepath, str); + alstr_copy_wcstr(&filepath, str); - TRACE("Loading config %s...\n", al_string_get_cstr(filepath)); - f = al_fopen(al_string_get_cstr(filepath), "rt"); + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); if(f) { LoadConfigFromFile(f); fclose(f); } - al_string_deinit(&filepath); + alstr_reset(&filepath); } - al_string_deinit(&ppath); + alstr_reset(&ppath); } #else void ReadALConfig(void) @@ -502,11 +502,11 @@ void ReadALConfig(void) } ppath = GetProcPath(); - if(!al_string_empty(ppath)) + if(!alstr_empty(ppath)) { - al_string_append_cstr(&ppath, "/alsoft.conf"); - TRACE("Loading config %s...\n", al_string_get_cstr(ppath)); - f = al_fopen(al_string_get_cstr(ppath), "r"); + alstr_append_cstr(&ppath, "/alsoft.conf"); + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + f = al_fopen(alstr_get_cstr(ppath), "r"); if(f) { LoadConfigFromFile(f); @@ -525,7 +525,7 @@ void ReadALConfig(void) } } - al_string_deinit(&ppath); + alstr_reset(&ppath); } #endif diff --git a/Alc/alstring.h b/Alc/alstring.h index 6167f5ce..a7513516 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -10,40 +10,40 @@ typedef char al_string_char_type; TYPEDEF_VECTOR(al_string_char_type, al_string) TYPEDEF_VECTOR(al_string, vector_al_string) -inline void al_string_deinit(al_string *str) +inline void alstr_reset(al_string *str) { VECTOR_DEINIT(*str); } #define AL_STRING_INIT(_x) do { (_x) = (al_string)NULL; } while(0) #define AL_STRING_INIT_STATIC() ((al_string)NULL) -#define AL_STRING_DEINIT(_x) al_string_deinit(&(_x)) +#define AL_STRING_DEINIT(_x) alstr_reset(&(_x)) -inline size_t al_string_length(const_al_string str) +inline size_t alstr_length(const_al_string str) { return VECTOR_SIZE(str); } -inline ALboolean al_string_empty(const_al_string str) -{ return al_string_length(str) == 0; } +inline ALboolean alstr_empty(const_al_string str) +{ return alstr_length(str) == 0; } -inline const al_string_char_type *al_string_get_cstr(const_al_string str) +inline const al_string_char_type *alstr_get_cstr(const_al_string str) { return str ? &VECTOR_FRONT(str) : ""; } -void al_string_clear(al_string *str); +void alstr_clear(al_string *str); -int al_string_cmp(const_al_string str1, const_al_string str2); -int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2); +int alstr_cmp(const_al_string str1, const_al_string str2); +int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2); -void al_string_copy(al_string *str, const_al_string from); -void al_string_copy_cstr(al_string *str, const al_string_char_type *from); -void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); +void alstr_copy(al_string *str, const_al_string from); +void alstr_copy_cstr(al_string *str, const al_string_char_type *from); +void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); -void al_string_append_char(al_string *str, const al_string_char_type c); -void al_string_append_cstr(al_string *str, const al_string_char_type *from); -void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); +void alstr_append_char(al_string *str, const al_string_char_type c); +void alstr_append_cstr(al_string *str, const al_string_char_type *from); +void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); #ifdef _WIN32 #include /* Windows-only methods to deal with WideChar strings. */ -void al_string_copy_wcstr(al_string *str, const wchar_t *from); -void al_string_append_wcstr(al_string *str, const wchar_t *from); -void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); +void alstr_copy_wcstr(al_string *str, const wchar_t *from); +void alstr_append_wcstr(al_string *str, const wchar_t *from); +void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); #endif #endif /* ALSTRING_H */ diff --git a/Alc/ambdec.c b/Alc/ambdec.c index 719b509c..da114335 100644 --- a/Alc/ambdec.c +++ b/Alc/ambdec.c @@ -164,7 +164,7 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t const char *conn = my_strtok_r(NULL, " \t", saveptr); if(!name) WARN("Name not specified for speaker %u\n", cur+1); - else al_string_copy_cstr(&conf->Speakers[cur].Name, name); + else alstr_copy_cstr(&conf->Speakers[cur].Name, name); if(!dist) WARN("Distance not specified for speaker %u\n", cur+1); else read_float(&conf->Speakers[cur].Distance, dist); if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1); @@ -172,7 +172,7 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1); else read_float(&conf->Speakers[cur].Elevation, elev); if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1); - else al_string_copy_cstr(&conf->Speakers[cur].Connection, conn); + else alstr_copy_cstr(&conf->Speakers[cur].Connection, conn); cur++; } @@ -293,11 +293,11 @@ void ambdec_deinit(AmbDecConf *conf) { ALsizei i; - al_string_deinit(&conf->Description); + alstr_reset(&conf->Description); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { - al_string_deinit(&conf->Speakers[i].Name); - al_string_deinit(&conf->Speakers[i].Connection); + alstr_reset(&conf->Speakers[i].Name); + alstr_reset(&conf->Speakers[i].Connection); } memset(conf, 0, sizeof(*conf)); } @@ -331,7 +331,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname) if(strcmp(command, "description") == 0) { char *value = my_strtok_r(NULL, "", &saveptr); - al_string_copy_cstr(&conf->Description, lstrip(value)); + alstr_copy_cstr(&conf->Description, lstrip(value)); } else if(strcmp(command, "version") == 0) { diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 2fa806ae..4a7b81ba 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -213,7 +213,7 @@ static ALCboolean alsa_load(void) p##f = GetSymbol(alsa_handle, #f); \ if(p##f == NULL) { \ error = ALC_TRUE; \ - al_string_append_cstr(&missing_funcs, "\n" #f); \ + alstr_append_cstr(&missing_funcs, "\n" #f); \ } \ } while(0) ALSA_FUNCS(LOAD_FUNC); @@ -221,11 +221,11 @@ static ALCboolean alsa_load(void) if(error) { - WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); CloseLib(alsa_handle); alsa_handle = NULL; } - al_string_deinit(&missing_funcs); + alstr_reset(&missing_funcs); } #endif @@ -276,8 +276,8 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.name, alsaDevice); - al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? + alstr_copy_cstr(&entry.name, alsaDevice); + alstr_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default")); VECTOR_PUSH_BACK(*DeviceList, entry); @@ -344,8 +344,8 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) TRACE("Got device \"%s\", \"%s\"\n", name, device); AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.name, name); - al_string_copy_cstr(&entry.device_name, device); + alstr_copy_cstr(&entry.name, name); + alstr_copy_cstr(&entry.device_name, device); VECTOR_PUSH_BACK(*DeviceList, entry); } snd_ctl_close(handle); @@ -636,12 +636,12 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) if(VECTOR_SIZE(PlaybackDevices) == 0) probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; - driver = al_string_get_cstr(iter->device_name); + driver = alstr_get_cstr(iter->device_name); } else { @@ -660,7 +660,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ snd_config_update_free_global(); - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } @@ -711,7 +711,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1); + allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1); periods = device->NumUpdates; periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; bufferLen = periodLen * periods; @@ -777,7 +777,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ - if(!GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || + if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) { if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) @@ -977,12 +977,12 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(VECTOR_SIZE(CaptureDevices) == 0) probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; - driver = al_string_get_cstr(iter->device_name); + driver = alstr_get_cstr(iter->device_name); } else { @@ -1072,7 +1072,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) } } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; @@ -1314,9 +1314,9 @@ static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(al_string_get_cstr(entry->name)); } +{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); } +{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } typedef struct ALCalsaBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index eb93f9ea..5e0b03bd 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -183,7 +183,7 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); device->ExtraData = data; return ALC_NO_ERROR; } @@ -596,7 +596,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) ); if(!data->ring) goto error; - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 084d1125..3dc297ff 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -145,16 +145,16 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA { const DevMap *iter; - al_string_copy_cstr(&entry.name, DEVNAME_HEAD); - al_string_append_wcstr(&entry.name, desc); + alstr_copy_cstr(&entry.name, DEVNAME_HEAD); + alstr_append_wcstr(&entry.name, desc); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } -#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY); if(iter == VECTOR_END(*devices)) break; #undef MATCH_ENTRY @@ -165,7 +165,7 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA hr = StringFromCLSID(guid, &guidstr); if(SUCCEEDED(hr)) { - TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry.name), guidstr); + TRACE("Got device \"%s\", GUID \"%ls\"\n", alstr_get_cstr(entry.name), guidstr); CoTaskMemFree(guidstr); } @@ -343,14 +343,14 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0) { - deviceName = al_string_get_cstr(VECTOR_FRONT(PlaybackDevices).name); + deviceName = alstr_get_cstr(VECTOR_FRONT(PlaybackDevices).name); guid = &VECTOR_FRONT(PlaybackDevices).guid; } else { const DevMap *iter; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(PlaybackDevices)) @@ -381,7 +381,7 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; } @@ -706,14 +706,14 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0) { - deviceName = al_string_get_cstr(VECTOR_FRONT(CaptureDevices).name); + deviceName = alstr_get_cstr(VECTOR_FRONT(CaptureDevices).name); guid = &VECTOR_FRONT(CaptureDevices).guid; } else { const DevMap *iter; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(CaptureDevices)) @@ -855,7 +855,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi self->BufferBytes = DSCBDescription.dwBufferBytes; SetDefaultWFXChannelOrder(device); - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); return ALC_NO_ERROR; } @@ -958,9 +958,9 @@ done: static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(al_string_get_cstr(entry->name)); } +{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); } +{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } typedef struct ALCdsoundBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index f1cd82bd..cce828e9 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -115,7 +115,7 @@ static ALCboolean jack_load(void) p##f = GetSymbol(jack_handle, #f); \ if(p##f == NULL) { \ error = ALC_TRUE; \ - al_string_append_cstr(&missing_funcs, "\n" #f); \ + alstr_append_cstr(&missing_funcs, "\n" #f); \ } \ } while(0) JACK_FUNCS(LOAD_FUNC); @@ -123,11 +123,11 @@ static ALCboolean jack_load(void) if(error) { - WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); CloseLib(jack_handle); jack_handle = NULL; } - al_string_deinit(&missing_funcs); + alstr_reset(&missing_funcs); } #endif @@ -220,7 +220,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); bufsize += device->UpdateSize; device->NumUpdates = bufsize / device->UpdateSize; @@ -373,7 +373,7 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) jack_set_process_callback(self->Client, ALCjackPlayback_process, self); jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self); - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } @@ -415,7 +415,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) device->NumUpdates = 2; bufsize = device->UpdateSize; - if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) + if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); bufsize += device->UpdateSize; device->NumUpdates = bufsize / device->UpdateSize; diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c index 0164bc5a..8f23aad9 100644 --- a/Alc/backends/loopback.c +++ b/Alc/backends/loopback.c @@ -59,7 +59,7 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 6ff9d931..339ea8d3 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -130,14 +130,14 @@ static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_stri PROPVARIANT pvguid; HRESULT hr; - al_string_copy_cstr(name, DEVNAME_HEAD); + alstr_copy_cstr(name, DEVNAME_HEAD); hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - al_string_append_cstr(name, "Unknown Device Name"); - if(guid!=NULL)al_string_copy_cstr(guid, "Unknown Device GUID"); + alstr_append_cstr(name, "Unknown Device Name"); + if(guid!=NULL)alstr_copy_cstr(guid, "Unknown Device GUID"); return; } @@ -147,14 +147,14 @@ static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_stri if(FAILED(hr)) { WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - al_string_append_cstr(name, "Unknown Device Name"); + alstr_append_cstr(name, "Unknown Device Name"); } else if(pvname.vt == VT_LPWSTR) - al_string_append_wcstr(name, pvname.pwszVal); + alstr_append_wcstr(name, pvname.pwszVal); else { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); - al_string_append_cstr(name, "Unknown Device Name"); + alstr_append_cstr(name, "Unknown Device Name"); } PropVariantClear(&pvname); @@ -165,14 +165,14 @@ static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_stri if(FAILED(hr)) { WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - al_string_copy_cstr(guid, "Unknown Device GUID"); + alstr_copy_cstr(guid, "Unknown Device GUID"); } else if(pvguid.vt == VT_LPWSTR) - al_string_copy_wcstr(guid, pvguid.pwszVal); + alstr_copy_wcstr(guid, pvguid.pwszVal); else { WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); - al_string_copy_cstr(guid, "Unknown Device GUID"); + alstr_copy_cstr(guid, "Unknown Device GUID"); } PropVariantClear(&pvguid); @@ -228,22 +228,22 @@ static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *lis { const DevMap *iter; - al_string_copy(&entry.name, tmpname); + alstr_copy(&entry.name, tmpname); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } -#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); if(iter == VECTOR_END(*list)) break; #undef MATCH_ENTRY count++; } - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.endpoint_guid), entry.devid); + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); VECTOR_PUSH_BACK(*list, entry); AL_STRING_DEINIT(tmpname); @@ -716,8 +716,8 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi } hr = E_FAIL; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \ - al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(PlaybackDevices)) @@ -739,7 +739,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->devid = strdupW(iter->devid); - al_string_copy(&device->DeviceName, iter->name); + alstr_copy(&device->DeviceName, iter->name); hr = S_OK; } } @@ -797,7 +797,7 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) if(SUCCEEDED(hr)) { self->client = ptr; - if(al_string_empty(device->DeviceName)) + if(alstr_empty(device->DeviceName)) get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); } @@ -1377,8 +1377,8 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device } hr = E_FAIL; -#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0 || \ - al_string_cmp_cstr((i)->endpoint_guid, deviceName) == 0) +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(CaptureDevices)) @@ -1400,7 +1400,7 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; self->devid = strdupW(iter->devid); - al_string_copy(&device->DeviceName, iter->name); + alstr_copy(&device->DeviceName, iter->name); hr = S_OK; } } @@ -1476,7 +1476,7 @@ static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) if(SUCCEEDED(hr)) { self->client = ptr; - if(al_string_empty(device->DeviceName)) + if(alstr_empty(device->DeviceName)) get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); } @@ -1777,9 +1777,9 @@ ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, A static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(al_string_get_cstr(entry->name)); } +{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); } +{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } typedef struct ALCmmdevBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); diff --git a/Alc/backends/null.c b/Alc/backends/null.c index 41636538..e8c43782 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -130,7 +130,7 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) return ALC_INVALID_VALUE; device = STATIC_CAST(ALCbackend, self)->mDevice; - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index b8d6d29a..41f55120 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -399,7 +399,7 @@ static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *na return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index b22e87ba..6706405d 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -374,7 +374,7 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } @@ -717,7 +717,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_OUT_OF_MEMORY; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 129b0606..b713f330 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -245,7 +245,7 @@ retry_open: return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; @@ -445,7 +445,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 14b37ee6..79ca38e5 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -202,7 +202,7 @@ static ALCboolean pulse_load(void) p##x = GetSymbol(pa_handle, #x); \ if(!(p##x)) { \ ret = ALC_FALSE; \ - al_string_append_cstr(&missing_funcs, "\n" #x); \ + alstr_append_cstr(&missing_funcs, "\n" #x); \ } \ } while(0) LOAD_FUNC(pa_context_unref); @@ -276,11 +276,11 @@ static ALCboolean pulse_load(void) if(ret == ALC_FALSE) { - WARN("Missing expected functions:%s\n", al_string_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); CloseLib(pa_handle); pa_handle = NULL; } - al_string_deinit(&missing_funcs); + alstr_reset(&missing_funcs); } #endif /* HAVE_DYNLOAD */ return ret; @@ -533,7 +533,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p return; } -#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) +#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME); if(iter != VECTOR_END(PlaybackDevices)) return; #undef MATCH_INFO_NAME @@ -541,27 +541,27 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.device_name, info->name); + alstr_copy_cstr(&entry.device_name, info->name); count = 0; while(1) { - al_string_copy_cstr(&entry.name, info->description); + alstr_copy_cstr(&entry.name, info->description); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } -#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY); if(iter == VECTOR_END(PlaybackDevices)) break; #undef MATCH_ENTRY count++; } - TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name)); + TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); VECTOR_PUSH_BACK(PlaybackDevices, entry); } @@ -737,7 +737,7 @@ static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const return; } - al_string_copy_cstr(&device->DeviceName, info->description); + alstr_copy_cstr(&device->DeviceName, info->description); } @@ -745,9 +745,9 @@ static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { ALCpulsePlayback *self = pdata; - al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); + alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); - TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name)); + TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); } @@ -866,12 +866,12 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name if(VECTOR_SIZE(PlaybackDevices) == 0) ALCpulsePlayback_probeDevices(); -#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0) +#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; - pulse_name = al_string_get_cstr(iter->device_name); + pulse_name = alstr_get_cstr(iter->device_name); dev_name = iter->name; } @@ -902,11 +902,11 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name } pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self); - al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - if(al_string_empty(dev_name)) + alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); + if(alstr_empty(dev_name)) { pa_operation *o = pa_context_get_sink_info_by_name( - self->context, al_string_get_cstr(self->device_name), + self->context, alstr_get_cstr(self->device_name), ALCpulsePlayback_sinkNameCallback, self ); wait_for_operation(o, self->loop); @@ -914,7 +914,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name else { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - al_string_copy(&device->DeviceName, dev_name); + alstr_copy(&device->DeviceName, dev_name); } pa_threaded_mainloop_unlock(self->loop); @@ -929,7 +929,7 @@ static void ALCpulsePlayback_close(ALCpulsePlayback *self) self->context = NULL; self->stream = NULL; - al_string_clear(&self->device_name); + alstr_clear(&self->device_name); } static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) @@ -954,11 +954,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) self->stream = NULL; } - o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name), + o = pa_context_get_sink_info_by_name(self->context, alstr_get_cstr(self->device_name), ALCpulsePlayback_sinkInfoCallback, self); wait_for_operation(o, self->loop); - if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) flags |= PA_STREAM_FIX_RATE; flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; @@ -1044,7 +1044,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2); self->attr.maxlength = -1; - self->stream = ALCpulsePlayback_connectStream(al_string_get_cstr(self->device_name), + self->stream = ALCpulsePlayback_connectStream(alstr_get_cstr(self->device_name), self->loop, self->context, flags, &self->attr, &self->spec, &chanmap); if(!self->stream) @@ -1261,7 +1261,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa return; } -#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) +#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME); if(iter != VECTOR_END(CaptureDevices)) return; #undef MATCH_INFO_NAME @@ -1269,27 +1269,27 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.device_name, info->name); + alstr_copy_cstr(&entry.device_name, info->name); count = 0; while(1) { - al_string_copy_cstr(&entry.name, info->description); + alstr_copy_cstr(&entry.name, info->description); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } -#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY); if(iter == VECTOR_END(CaptureDevices)) break; #undef MATCH_ENTRY count++; } - TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name)); + TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); VECTOR_PUSH_BACK(CaptureDevices, entry); } @@ -1382,7 +1382,7 @@ static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), cons return; } - al_string_copy_cstr(&device->DeviceName, info->description); + alstr_copy_cstr(&device->DeviceName, info->description); } @@ -1390,9 +1390,9 @@ static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { ALCpulseCapture *self = pdata; - al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); + alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); - TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name)); + TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); } @@ -1452,13 +1452,13 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) if(VECTOR_SIZE(CaptureDevices) == 0) ALCpulseCapture_probeDevices(); -#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0) +#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); #undef MATCH_NAME if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; - pulse_name = al_string_get_cstr(iter->device_name); - al_string_copy(&device->DeviceName, iter->name); + pulse_name = alstr_get_cstr(iter->device_name); + alstr_copy(&device->DeviceName, iter->name); } if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self)) @@ -1531,11 +1531,11 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self); pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self); - al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - if(al_string_empty(device->DeviceName)) + alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); + if(alstr_empty(device->DeviceName)) { pa_operation *o = pa_context_get_source_info_by_name( - self->context, al_string_get_cstr(self->device_name), + self->context, alstr_get_cstr(self->device_name), ALCpulseCapture_sourceNameCallback, self ); wait_for_operation(o, self->loop); @@ -1560,7 +1560,7 @@ static void ALCpulseCapture_close(ALCpulseCapture *self) self->context = NULL; self->stream = NULL; - al_string_clear(&self->device_name); + alstr_clear(&self->device_name); } static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self) @@ -1785,14 +1785,14 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e { case ALL_DEVICE_PROBE: ALCpulsePlayback_probeDevices(); -#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(al_string_get_cstr((e)->name)) +#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(alstr_get_cstr((e)->name)) VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST); #undef APPEND_ALL_DEVICES_LIST break; case CAPTURE_DEVICE_PROBE: ALCpulseCapture_probeDevices(); -#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name)) +#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(alstr_get_cstr((e)->name)) VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST); #undef APPEND_CAPTURE_DEVICE_LIST break; diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index dabe5ee9..9563a918 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -296,7 +296,7 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName) return ALC_INVALID_DEVICE; } - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); device->ExtraData = data; return ALC_NO_ERROR; @@ -643,7 +643,7 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) return ALC_INVALID_DEVICE; } - al_string_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, deviceName); device->ExtraData = data; switch (device->FmtType) diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 00d7c654..ac2dc03f 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -145,7 +145,7 @@ static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index c70e0b46..98c00525 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -185,7 +185,7 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na } device = STATIC_CAST(ALCbackend,self)->mDevice; - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 1b13746e..36d7cbca 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -228,7 +228,7 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) } device = STATIC_CAST(ALCbackend, self)->mDevice; - al_string_copy_cstr(&device->DeviceName, name); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 2b6db4ad..da0d67a1 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -45,7 +45,7 @@ static vector_al_string CaptureDevices; static void clear_devlist(vector_al_string *list) { - VECTOR_FOR_EACH(al_string, *list, al_string_deinit); + VECTOR_FOR_EACH(al_string, *list, alstr_reset); VECTOR_RESIZE(*list, 0, 0); } @@ -71,23 +71,23 @@ static void ProbePlaybackDevices(void) ALuint count = 0; while(1) { - al_string_copy_cstr(&dname, DEVNAME_HEAD); - al_string_append_wcstr(&dname, WaveCaps.szPname); + alstr_copy_cstr(&dname, DEVNAME_HEAD); + alstr_append_wcstr(&dname, WaveCaps.szPname); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&dname, str); + alstr_append_cstr(&dname, str); } count++; -#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); if(iter == VECTOR_END(PlaybackDevices)) break; #undef MATCH_ENTRY } - TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); + TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); } VECTOR_PUSH_BACK(PlaybackDevices, dname); } @@ -114,23 +114,23 @@ static void ProbeCaptureDevices(void) ALuint count = 0; while(1) { - al_string_copy_cstr(&dname, DEVNAME_HEAD); - al_string_append_wcstr(&dname, WaveCaps.szPname); + alstr_copy_cstr(&dname, DEVNAME_HEAD); + alstr_append_wcstr(&dname, WaveCaps.szPname); if(count != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", count+1); - al_string_append_cstr(&dname, str); + alstr_append_cstr(&dname, str); } count++; -#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) +#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); if(iter == VECTOR_END(CaptureDevices)) break; #undef MATCH_ENTRY } - TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); + TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i); } VECTOR_PUSH_BACK(CaptureDevices, dname); } @@ -257,8 +257,8 @@ static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *devi ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \ - (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0)) +#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ + (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; @@ -300,7 +300,7 @@ retry_open: goto failure; } - al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); + alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: @@ -544,7 +544,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid -#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0)) +#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; @@ -638,7 +638,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; - al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); + alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: @@ -715,13 +715,13 @@ static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) static inline void AppendAllDevicesList2(const al_string *name) { - if(!al_string_empty(*name)) - AppendAllDevicesList(al_string_get_cstr(*name)); + if(!alstr_empty(*name)) + AppendAllDevicesList(alstr_get_cstr(*name)); } static inline void AppendCaptureDeviceList2(const al_string *name) { - if(!al_string_empty(*name)) - AppendCaptureDeviceList(al_string_get_cstr(*name)); + if(!alstr_empty(*name)) + AppendCaptureDeviceList(alstr_get_cstr(*name)); } typedef struct ALCwinmmBackendFactory { diff --git a/Alc/helpers.c b/Alc/helpers.c index 1ce567b2..5d23c3a7 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -358,7 +358,7 @@ void RestoreFPUMode(const FPUCtl *ctl) static int StringSortCompare(const void *str1, const void *str2) { - return al_string_cmp(*(const_al_string*)str1, *(const_al_string*)str2); + return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2); } #ifdef _WIN32 @@ -406,10 +406,10 @@ al_string GetProcPath(void) } else if((sep = strrchrW(pathname, '/'))) *sep = 0; - al_string_copy_wcstr(&ret, pathname); + alstr_copy_wcstr(&ret, pathname); free(pathname); - TRACE("Got: %s\n", al_string_get_cstr(ret)); + TRACE("Got: %s\n", alstr_get_cstr(ret)); return ret; } @@ -526,13 +526,13 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string WCHAR *wpath; HANDLE hdl; - al_string_copy_cstr(&pathstr, path); - al_string_append_cstr(&pathstr, "\\*"); - al_string_append_cstr(&pathstr, ext); + alstr_copy_cstr(&pathstr, path); + alstr_append_cstr(&pathstr, "\\*"); + alstr_append_cstr(&pathstr, ext); - TRACE("Searching %s\n", al_string_get_cstr(pathstr)); + TRACE("Searching %s\n", alstr_get_cstr(pathstr)); - wpath = FromUTF8(al_string_get_cstr(pathstr)); + wpath = FromUTF8(alstr_get_cstr(pathstr)); hdl = FindFirstFileW(wpath, &fdata); if(hdl != INVALID_HANDLE_VALUE) @@ -540,10 +540,10 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string size_t base = VECTOR_SIZE(*results); do { al_string str = AL_STRING_INIT_STATIC(); - al_string_copy_cstr(&str, path); - al_string_append_char(&str, '\\'); - al_string_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", al_string_get_cstr(str)); + alstr_copy_cstr(&str, path); + alstr_append_char(&str, '\\'); + alstr_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", alstr_get_cstr(str)); VECTOR_PUSH_BACK(*results, str); } while(FindNextFileW(hdl, &fdata)); FindClose(hdl); @@ -554,7 +554,7 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string } free(wpath); - al_string_deinit(&pathstr); + alstr_reset(&pathstr); } vector_al_string SearchDataFiles(const char *ext, const char *subdir) @@ -571,14 +571,14 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { al_string path = AL_STRING_INIT_STATIC(); - al_string_copy_cstr(&path, subdir); + alstr_copy_cstr(&path, subdir); #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - DirectorySearch(al_string_get_cstr(path), ext, &results); + DirectorySearch(alstr_get_cstr(path), ext, &results); - al_string_deinit(&path); + alstr_reset(&path); } else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') DirectorySearch(subdir, ext, &results); @@ -590,7 +590,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) /* Search the app-local directory. */ if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0') { - al_string_copy_wcstr(&path, cwdbuf); + alstr_copy_wcstr(&path, cwdbuf); if(is_slash(VECTOR_BACK(path))) { VECTOR_POP_BACK(path); @@ -598,10 +598,10 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) } } else if(!(cwdbuf=_wgetcwd(NULL, 0))) - al_string_copy_cstr(&path, "."); + alstr_copy_cstr(&path, "."); else { - al_string_copy_wcstr(&path, cwdbuf); + alstr_copy_wcstr(&path, cwdbuf); if(is_slash(VECTOR_BACK(path))) { VECTOR_POP_BACK(path); @@ -612,7 +612,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - DirectorySearch(al_string_get_cstr(path), ext, &results); + DirectorySearch(alstr_get_cstr(path), ext, &results); /* Search the local and global data dirs. */ for(i = 0;i < COUNTOF(ids);i++) @@ -620,19 +620,19 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) WCHAR buffer[PATH_MAX]; if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) { - al_string_copy_wcstr(&path, buffer); + alstr_copy_wcstr(&path, buffer); if(!is_slash(VECTOR_BACK(path))) - al_string_append_char(&path, '\\'); - al_string_append_cstr(&path, subdir); + alstr_append_char(&path, '\\'); + alstr_append_cstr(&path, subdir); #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - DirectorySearch(al_string_get_cstr(path), ext, &results); + DirectorySearch(alstr_get_cstr(path), ext, &results); } } - al_string_deinit(&path); + alstr_reset(&path); } ATOMIC_STORE_SEQ(&search_lock, 0); @@ -740,12 +740,12 @@ al_string GetProcPath(void) pathname[len] = 0; sep = strrchr(pathname, '/'); if(sep) - al_string_copy_range(&ret, pathname, sep); + alstr_copy_range(&ret, pathname, sep); else - al_string_copy_cstr(&ret, pathname); + alstr_copy_cstr(&ret, pathname); free(pathname); - TRACE("Got: %s\n", al_string_get_cstr(ret)); + TRACE("Got: %s\n", alstr_get_cstr(ret)); return ret; } @@ -820,11 +820,11 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string continue; AL_STRING_INIT(str); - al_string_copy_cstr(&str, path); + alstr_copy_cstr(&str, path); if(VECTOR_BACK(str) != '/') - al_string_append_char(&str, '/'); - al_string_append_cstr(&str, dirent->d_name); - TRACE("Got result %s\n", al_string_get_cstr(str)); + alstr_append_char(&str, '/'); + alstr_append_cstr(&str, dirent->d_name); + TRACE("Got result %s\n", alstr_get_cstr(str)); VECTOR_PUSH_BACK(*results, str); } closedir(dir); @@ -862,23 +862,23 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) // Search local data dir if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') { - al_string_copy_cstr(&path, str); + alstr_copy_cstr(&path, str); if(VECTOR_BACK(path) != '/') - al_string_append_char(&path, '/'); - al_string_append_cstr(&path, subdir); - DirectorySearch(al_string_get_cstr(path), ext, &results); + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); } else if((str=getenv("HOME")) != NULL && str[0] != '\0') { - al_string_copy_cstr(&path, str); + alstr_copy_cstr(&path, str); if(VECTOR_BACK(path) == '/') { VECTOR_POP_BACK(path); *VECTOR_END(path) = 0; } - al_string_append_cstr(&path, "/.local/share/"); - al_string_append_cstr(&path, subdir); - DirectorySearch(al_string_get_cstr(path), ext, &results); + alstr_append_cstr(&path, "/.local/share/"); + alstr_append_cstr(&path, subdir); + DirectorySearch(alstr_get_cstr(path), ext, &results); } // Search global data dirs @@ -890,23 +890,23 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) { next = strchr(str, ':'); if(!next) - al_string_copy_cstr(&path, str); + alstr_copy_cstr(&path, str); else { - al_string_copy_range(&path, str, next); + alstr_copy_range(&path, str, next); ++next; } - if(!al_string_empty(path)) + if(!alstr_empty(path)) { if(VECTOR_BACK(path) != '/') - al_string_append_char(&path, '/'); - al_string_append_cstr(&path, subdir); + alstr_append_char(&path, '/'); + alstr_append_cstr(&path, subdir); - DirectorySearch(al_string_get_cstr(path), ext, &results); + DirectorySearch(alstr_get_cstr(path), ext, &results); } } - al_string_deinit(&path); + alstr_reset(&path); } ATOMIC_STORE_SEQ(&search_lock, 0); @@ -983,14 +983,14 @@ void SetRTPriority(void) } -extern inline void al_string_deinit(al_string *str); -extern inline size_t al_string_length(const_al_string str); -extern inline ALboolean al_string_empty(const_al_string str); -extern inline const al_string_char_type *al_string_get_cstr(const_al_string str); +extern inline void alstr_reset(al_string *str); +extern inline size_t alstr_length(const_al_string str); +extern inline ALboolean alstr_empty(const_al_string str); +extern inline const al_string_char_type *alstr_get_cstr(const_al_string str); -void al_string_clear(al_string *str) +void alstr_clear(al_string *str) { - if(!al_string_empty(*str)) + if(!alstr_empty(*str)) { /* Reserve one more character than the total size of the string. This * is to ensure we have space to add a null terminator in the string @@ -1001,8 +1001,8 @@ void al_string_clear(al_string *str) } } -static inline int al_string_compare(const al_string_char_type *str1, size_t str1len, - const al_string_char_type *str2, size_t str2len) +static inline int alstr_compare(const al_string_char_type *str1, size_t str1len, + const al_string_char_type *str2, size_t str2len) { size_t complen = (str1len < str2len) ? str1len : str2len; int ret = memcmp(str1, str2, complen); @@ -1013,20 +1013,20 @@ static inline int al_string_compare(const al_string_char_type *str1, size_t str1 } return ret; } -int al_string_cmp(const_al_string str1, const_al_string str2) +int alstr_cmp(const_al_string str1, const_al_string str2) { - return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - &VECTOR_FRONT(str2), al_string_length(str2)); + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + &VECTOR_FRONT(str2), alstr_length(str2)); } -int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2) +int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2) { - return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - str2, strlen(str2)); + return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1), + str2, strlen(str2)); } -void al_string_copy(al_string *str, const_al_string from) +void alstr_copy(al_string *str, const_al_string from) { - size_t len = al_string_length(from); + size_t len = alstr_length(from); size_t i; VECTOR_RESIZE(*str, len, len+1); @@ -1035,7 +1035,7 @@ void al_string_copy(al_string *str, const_al_string from) VECTOR_ELEM(*str, i) = 0; } -void al_string_copy_cstr(al_string *str, const al_string_char_type *from) +void alstr_copy_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); size_t i; @@ -1046,7 +1046,7 @@ void al_string_copy_cstr(al_string *str, const al_string_char_type *from) VECTOR_ELEM(*str, i) = 0; } -void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { size_t len = to - from; size_t i; @@ -1057,20 +1057,20 @@ void al_string_copy_range(al_string *str, const al_string_char_type *from, const VECTOR_ELEM(*str, i) = 0; } -void al_string_append_char(al_string *str, const al_string_char_type c) +void alstr_append_char(al_string *str, const al_string_char_type c) { - size_t len = al_string_length(*str); + size_t len = alstr_length(*str); VECTOR_RESIZE(*str, len, len+2); VECTOR_PUSH_BACK(*str, c); VECTOR_ELEM(*str, len+1) = 0; } -void al_string_append_cstr(al_string *str, const al_string_char_type *from) +void alstr_append_cstr(al_string *str, const al_string_char_type *from) { size_t len = strlen(from); if(len != 0) { - size_t base = al_string_length(*str); + size_t base = alstr_length(*str); size_t i; VECTOR_RESIZE(*str, base+len, base+len+1); @@ -1080,12 +1080,12 @@ void al_string_append_cstr(al_string *str, const al_string_char_type *from) } } -void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) +void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) { size_t len = to - from; if(len != 0) { - size_t base = al_string_length(*str); + size_t base = alstr_length(*str); size_t i; VECTOR_RESIZE(*str, base+len, base+len+1); @@ -1096,7 +1096,7 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con } #ifdef _WIN32 -void al_string_copy_wcstr(al_string *str, const wchar_t *from) +void alstr_copy_wcstr(al_string *str, const wchar_t *from) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) @@ -1107,24 +1107,24 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from) } } -void al_string_append_wcstr(al_string *str, const wchar_t *from) +void alstr_append_wcstr(al_string *str, const wchar_t *from) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) { - size_t base = al_string_length(*str); + size_t base = alstr_length(*str); VECTOR_RESIZE(*str, base+len-1, base+len); WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL); VECTOR_ELEM(*str, base+len-1) = 0; } } -void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) { int len; if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) { - size_t base = al_string_length(*str); + size_t base = alstr_length(*str); VECTOR_RESIZE(*str, base+len, base+len+1); WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL); VECTOR_ELEM(*str, base+len) = 0; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 2f6e9983..4634e6eb 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -252,7 +252,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount total = RoundUp(total, sizeof(ALfloat)); /* Align for float fields */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; - total += al_string_length(filename)+1; + total += alstr_length(filename)+1; Hrtf = al_calloc(16, total); if(Hrtf == NULL) @@ -288,7 +288,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount offset += sizeof(_delays[0])*irCount; _name = (char*)(base + offset); Hrtf->filename = _name; - offset += sizeof(_name[0])*(al_string_length(filename)+1); + offset += sizeof(_name[0])*(alstr_length(filename)+1); Hrtf->next = NULL; @@ -298,7 +298,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount for(i = 0;i < irSize*irCount;i++) _coeffs[i] = coeffs[i] / 32768.0f; for(i = 0;i < irCount;i++) _delays[i] = delays[i]; - for(i = 0;i < (ALsizei)al_string_length(filename);i++) + for(i = 0;i < (ALsizei)alstr_length(filename);i++) _name[i] = VECTOR_ELEM(filename, i); _name[i] = '\0'; @@ -325,7 +325,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < 9) { ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", - al_string_get_cstr(filename), 9, datalen); + alstr_get_cstr(filename), 9, datalen); return NULL; } @@ -364,7 +364,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < evCount*2) { ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", - al_string_get_cstr(filename), evCount*2, datalen); + alstr_get_cstr(filename), evCount*2, datalen); return NULL; } @@ -433,7 +433,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < reqsize) { ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n", - al_string_get_cstr(filename), reqsize, datalen); + alstr_get_cstr(filename), reqsize, datalen); failed = AL_TRUE; } } @@ -489,7 +489,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < 6) { ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), 6, datalen); + alstr_get_cstr(filename), 6, datalen); return NULL; } @@ -523,7 +523,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < evCount) { ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), evCount, datalen); + alstr_get_cstr(filename), evCount, datalen); return NULL; } @@ -575,7 +575,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < reqsize) { ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - al_string_get_cstr(filename), reqsize, datalen); + alstr_get_cstr(filename), reqsize, datalen); failed = AL_TRUE; } } @@ -626,11 +626,11 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) const char *ext; int i; -#define MATCH_FNAME(i) (al_string_cmp_cstr(filename, (i)->hrtf->filename) == 0) +#define MATCH_FNAME(i) (alstr_cmp_cstr(filename, (i)->hrtf->filename) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(filename)); + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); return; } #undef MATCH_FNAME @@ -638,24 +638,24 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) entry.hrtf = LoadedHrtfs; while(entry.hrtf) { - if(al_string_cmp_cstr(filename, entry.hrtf->filename) == 0) + if(alstr_cmp_cstr(filename, entry.hrtf->filename) == 0) { - TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(filename)); + TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); goto skip_load; } entry.hrtf = entry.hrtf->next; } - TRACE("Loading %s...\n", al_string_get_cstr(filename)); - fmap = MapFileToMem(al_string_get_cstr(filename)); + TRACE("Loading %s...\n", alstr_get_cstr(filename)); + fmap = MapFileToMem(alstr_get_cstr(filename)); if(fmap.ptr == NULL) { - ERR("Could not open %s\n", al_string_get_cstr(filename)); + ERR("Could not open %s\n", alstr_get_cstr(filename)); return; } if(fmap.len < sizeof(magicMarker01)) - ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(filename), fmap.len); + ERR("%s data is too short ("SZFMT" bytes)\n", alstr_get_cstr(filename), fmap.len); else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); @@ -671,12 +671,12 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) ); } else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(filename), (const char*)fmap.ptr); + ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)fmap.ptr); UnmapFileMem(&fmap); if(!hrtf) { - ERR("Failed to load %s\n", al_string_get_cstr(filename)); + ERR("Failed to load %s\n", alstr_get_cstr(filename)); return; } @@ -689,9 +689,9 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ - name = strrchr(al_string_get_cstr(filename), '/'); - if(!name) name = strrchr(al_string_get_cstr(filename), '\\'); - if(!name) name = al_string_get_cstr(filename); + name = strrchr(alstr_get_cstr(filename), '/'); + if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); + if(!name) name = alstr_get_cstr(filename); else ++name; ext = strrchr(name, '.'); @@ -699,24 +699,24 @@ skip_load: i = 0; do { if(!ext) - al_string_copy_cstr(&entry.name, name); + alstr_copy_cstr(&entry.name, name); else - al_string_copy_range(&entry.name, name, ext); + alstr_copy_range(&entry.name, name, ext); if(i != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", i+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } ++i; -#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name), - al_string_get_cstr(filename)); + TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), + alstr_get_cstr(filename)); VECTOR_PUSH_BACK(*list, entry); } @@ -730,11 +730,11 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t const HrtfEntry *iter; int i; -#define MATCH_FNAME(i) (al_string_cmp_cstr(filename, (i)->hrtf->filename) == 0) +#define MATCH_FNAME(i) (alstr_cmp_cstr(filename, (i)->hrtf->filename) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); if(iter != VECTOR_END(*list)) { - TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(filename)); + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); return; } #undef MATCH_FNAME @@ -742,18 +742,18 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t entry.hrtf = LoadedHrtfs; while(entry.hrtf) { - if(al_string_cmp_cstr(filename, entry.hrtf->filename) == 0) + if(alstr_cmp_cstr(filename, entry.hrtf->filename) == 0) { - TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(filename)); + TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); goto skip_load; } entry.hrtf = entry.hrtf->next; } - TRACE("Loading %s...\n", al_string_get_cstr(filename)); + TRACE("Loading %s...\n", alstr_get_cstr(filename)); if(datalen < sizeof(magicMarker01)) { - ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(filename), datalen); + ERR("%s data is too short ("SZFMT" bytes)\n", alstr_get_cstr(filename), datalen); return; } @@ -772,11 +772,11 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t ); } else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(filename), data); + ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), data); if(!hrtf) { - ERR("Failed to load %s\n", al_string_get_cstr(filename)); + ERR("Failed to load %s\n", alstr_get_cstr(filename)); return; } @@ -789,21 +789,21 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t skip_load: i = 0; do { - al_string_copy(&entry.name, filename); + alstr_copy(&entry.name, filename); if(i != 0) { char str[64]; snprintf(str, sizeof(str), " #%d", i+1); - al_string_append_cstr(&entry.name, str); + alstr_append_cstr(&entry.name, str); } ++i; -#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0) +#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - TRACE("Adding built-in entry \"%s\"\n", al_string_get_cstr(entry.name)); + TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); VECTOR_PUSH_BACK(*list, entry); } @@ -909,7 +909,7 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) const char *pathlist = ""; bool usedefaults = true; - if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) + if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) { al_string pname = AL_STRING_INIT_STATIC(); while(pathlist && *pathlist) @@ -937,21 +937,21 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) vector_al_string flist; size_t i; - al_string_append_range(&pname, pathlist, end); + alstr_append_range(&pname, pathlist, end); - flist = SearchDataFiles(".mhr", al_string_get_cstr(pname)); + flist = SearchDataFiles(".mhr", alstr_get_cstr(pname)); for(i = 0;i < VECTOR_SIZE(flist);i++) AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, al_string_deinit); + VECTOR_FOR_EACH(al_string, flist, alstr_reset); VECTOR_DEINIT(flist); } pathlist = next; } - al_string_deinit(&pname); + alstr_reset(&pname); } - else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables")) + else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables")) ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); if(usedefaults) @@ -964,30 +964,30 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) flist = SearchDataFiles(".mhr", "openal/hrtf"); for(i = 0;i < VECTOR_SIZE(flist);i++) AddFileEntry(&list, VECTOR_ELEM(flist, i)); - VECTOR_FOR_EACH(al_string, flist, al_string_deinit); + VECTOR_FOR_EACH(al_string, flist, alstr_reset); VECTOR_DEINIT(flist); rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize); if(rdata != NULL && rsize > 0) { - al_string_copy_cstr(&ename, "Built-In 44100hz"); + alstr_copy_cstr(&ename, "Built-In 44100hz"); AddBuiltInEntry(&list, rdata, rsize, ename); } rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); if(rdata != NULL && rsize > 0) { - al_string_copy_cstr(&ename, "Built-In 48000hz"); + alstr_copy_cstr(&ename, "Built-In 48000hz"); AddBuiltInEntry(&list, rdata, rsize, ename); } - al_string_deinit(&ename); + alstr_reset(&ename); } - if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) + if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) { const HrtfEntry *iter; /* Find the preferred HRTF and move it to the front of the list. */ -#define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0) +#define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY); #undef FIND_ENTRY if(iter == VECTOR_END(list)) @@ -1006,9 +1006,7 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) void FreeHrtfList(vector_HrtfEntry *list) { -#define CLEAR_ENTRY(i) do { \ - al_string_deinit(&(i)->name); \ -} while(0) +#define CLEAR_ENTRY(i) alstr_reset(&(i)->name) VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY); VECTOR_DEINIT(*list); #undef CLEAR_ENTRY diff --git a/Alc/panning.c b/Alc/panning.c index 0ff58c3a..ce86a561 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -386,45 +386,45 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp * use the side channels when the device is configured for back, * and vice-versa. */ - if(al_string_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) + if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) c = GetChannelIdxByName(device->RealOut, FrontLeft); - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) c = GetChannelIdxByName(device->RealOut, FrontRight); - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) c = GetChannelIdxByName(device->RealOut, FrontCenter); - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) { if(device->FmtChans == DevFmtX51Rear) c = GetChannelIdxByName(device->RealOut, BackLeft); else c = GetChannelIdxByName(device->RealOut, SideLeft); } - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) { if(device->FmtChans == DevFmtX51Rear) c = GetChannelIdxByName(device->RealOut, BackRight); else c = GetChannelIdxByName(device->RealOut, SideRight); } - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) { if(device->FmtChans == DevFmtX51) c = GetChannelIdxByName(device->RealOut, SideLeft); else c = GetChannelIdxByName(device->RealOut, BackLeft); } - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) { if(device->FmtChans == DevFmtX51) c = GetChannelIdxByName(device->RealOut, SideRight); else c = GetChannelIdxByName(device->RealOut, BackRight); } - else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) + else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) c = GetChannelIdxByName(device->RealOut, BackCenter); else { - const char *name = al_string_get_cstr(conf->Speakers[i].Name); + const char *name = alstr_get_cstr(conf->Speakers[i].Name); unsigned int n; char ch; @@ -439,7 +439,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp if(c == -1) { ERR("Failed to lookup AmbDec speaker label %s\n", - al_string_get_cstr(conf->Speakers[i].Name)); + alstr_get_cstr(conf->Speakers[i].Name)); return false; } speakermap[i] = c; @@ -489,7 +489,7 @@ static const ChannelMap MonoCfg[1] = { static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, bool periphonic) { - const char *devname = al_string_get_cstr(device->DeviceName); + const char *devname = alstr_get_cstr(device->DeviceName); ALsizei i; if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) @@ -514,7 +514,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { - const char *devname = al_string_get_cstr(device->DeviceName); + const char *devname = alstr_get_cstr(device->DeviceName); ALfloat maxdist = 0.0f; ALsizei total = 0; ALsizei i; @@ -540,14 +540,14 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL srate + 0.5f); if(delay >= (ALfloat)MAX_DELAY_LENGTH) ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n", - al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); + alstr_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH); device->ChannelDelay[chan].Length = (ALsizei)clampf( delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1) ); device->ChannelDelay[chan].Gain = conf->Speakers[i].Distance / maxdist; TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan, - al_string_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, + alstr_get_cstr(conf->Speakers[i].Name), device->ChannelDelay[chan].Length, device->ChannelDelay[chan].Gain ); @@ -628,7 +628,7 @@ static void InitPanning(ALCdevice *device) if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) { - const char *devname = al_string_get_cstr(device->DeviceName); + const char *devname = alstr_get_cstr(device->DeviceName); const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : @@ -1005,7 +1005,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf al_free(device->Hrtf); device->Hrtf = NULL; device->HrtfHandle = NULL; - al_string_clear(&device->HrtfName); + alstr_clear(&device->HrtfName); device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); @@ -1033,7 +1033,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf ambdec_init(&conf); - devname = al_string_get_cstr(device->DeviceName); + devname = alstr_get_cstr(device->DeviceName); switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; @@ -1110,7 +1110,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->Type != Loopback) { const char *mode; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) { if(strcasecmp(mode, "headphones") == 0) headphones = true; @@ -1154,7 +1154,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(entry->hrtf->sampleRate == device->Frequency) { device->HrtfHandle = entry->hrtf; - al_string_copy(&device->HrtfName, entry->name); + alstr_copy(&device->HrtfName, entry->name); } } @@ -1164,7 +1164,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(entry->hrtf->sampleRate == device->Frequency) { device->HrtfHandle = entry->hrtf; - al_string_copy(&device->HrtfName, entry->name); + alstr_copy(&device->HrtfName, entry->name); } } @@ -1173,7 +1173,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf bool hoa_mode; device->Render_Mode = HrtfRender; - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) device->Render_Mode = HrtfRender; @@ -1201,7 +1201,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), - al_string_get_cstr(device->HrtfName) + alstr_get_cstr(device->HrtfName) ); InitHrtfPanning(device, hoa_mode); return; @@ -1219,7 +1219,7 @@ no_hrtf: bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; if(device->Type != Loopback) - ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); @@ -1231,7 +1231,7 @@ no_hrtf: TRACE("BS2B disabled\n"); - if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) + if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "stereo-encoding", &mode)) { if(strcasecmp(mode, "uhj") == 0) device->Render_Mode = NormalRender; -- cgit v1.2.3 From e7ca61e8b585d1546cb92ddcf0cfcd1fe084484c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Apr 2017 07:09:16 -0700 Subject: Store the HRTF's filename separate from the entry storage --- Alc/hrtf.c | 117 +++++++++++++++++++++++++++++++++++++------------------------ Alc/hrtf.h | 3 -- 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 4634e6eb..0aad5e97 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -53,7 +53,11 @@ static const ALchar magicMarker01[8] = "MinPHR01"; * directional sounds. */ static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; -static struct Hrtf *LoadedHrtfs = NULL; +static struct LoadedHrtfEntry { + struct LoadedHrtfEntry *next; + struct Hrtf *hrtf; + char filename[]; +} *LoadedHrtfs = NULL; /* Calculate the elevation index given the polar elevation in radians. This @@ -252,11 +256,10 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount total = RoundUp(total, sizeof(ALfloat)); /* Align for float fields */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; - total += alstr_length(filename)+1; Hrtf = al_calloc(16, total); if(Hrtf == NULL) - ERR("Out of memory.\n"); + ERR("Out of memory allocating storage for %s.\n", alstr_get_cstr(filename)); else { uintptr_t offset = sizeof(struct Hrtf); @@ -265,7 +268,6 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount ALubyte *_azCount; ALubyte *_delays; ALfloat *_coeffs; - char *_name; ALsizei i; Hrtf->sampleRate = rate; @@ -287,20 +289,12 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount _delays = (ALubyte*)(base + offset); Hrtf->delays = _delays; offset += sizeof(_delays[0])*irCount; - _name = (char*)(base + offset); Hrtf->filename = _name; - offset += sizeof(_name[0])*(alstr_length(filename)+1); - - Hrtf->next = NULL; - /* Copy input data to storage. */ for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; for(i = 0;i < irSize*irCount;i++) _coeffs[i] = coeffs[i] / 32768.0f; for(i = 0;i < irCount;i++) _delays[i] = delays[i]; - for(i = 0;i < (ALsizei)alstr_length(filename);i++) - _name[i] = VECTOR_ELEM(filename, i); - _name[i] = '\0'; assert(offset == total); } @@ -619,6 +613,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) { HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; + struct LoadedHrtfEntry *loaded_entry; struct Hrtf *hrtf = NULL; const HrtfEntry *iter; struct FileMapping fmap; @@ -626,24 +621,27 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) const char *ext; int i; -#define MATCH_FNAME(i) (alstr_cmp_cstr(filename, (i)->hrtf->filename) == 0) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); - if(iter != VECTOR_END(*list)) + /* Check if this file has already been loaded globally. */ + loaded_entry = LoadedHrtfs; + while(loaded_entry) { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); - return; - } + if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + { + /* Check if this entry has already been added to the list. */ +#define MATCH_ENTRY(i) (loaded_entry->hrtf == (i)->hrtf) + VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_ENTRY); + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + return; + } #undef MATCH_FNAME - entry.hrtf = LoadedHrtfs; - while(entry.hrtf) - { - if(alstr_cmp_cstr(filename, entry.hrtf->filename) == 0) - { TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); + hrtf = loaded_entry->hrtf; goto skip_load; } - entry.hrtf = entry.hrtf->next; + loaded_entry = loaded_entry->next; } TRACE("Loading %s...\n", alstr_get_cstr(filename)); @@ -680,11 +678,16 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) return; } - hrtf->next = LoadedHrtfs; - LoadedHrtfs = hrtf; + loaded_entry = al_calloc(DEF_ALIGN, + offsetof(struct LoadedHrtfEntry, filename[alstr_length(filename)+1]) + ); + loaded_entry->next = LoadedHrtfs; + loaded_entry->hrtf = hrtf; + strcpy(loaded_entry->filename, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; + TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - entry.hrtf = hrtf; skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -714,6 +717,7 @@ skip_load: VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); + entry.hrtf = hrtf; TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(filename)); @@ -726,28 +730,32 @@ skip_load: static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, const_al_string filename) { HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; + struct LoadedHrtfEntry *loaded_entry; struct Hrtf *hrtf = NULL; const HrtfEntry *iter; + const char *name; + const char *ext; int i; -#define MATCH_FNAME(i) (alstr_cmp_cstr(filename, (i)->hrtf->filename) == 0) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME); - if(iter != VECTOR_END(*list)) + loaded_entry = LoadedHrtfs; + while(loaded_entry) { - TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); - return; - } + if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) + { +#define MATCH_ENTRY(i) (loaded_entry->hrtf == (i)->hrtf) + VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_ENTRY); + if(iter != VECTOR_END(*list)) + { + TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); + return; + } #undef MATCH_FNAME - entry.hrtf = LoadedHrtfs; - while(entry.hrtf) - { - if(alstr_cmp_cstr(filename, entry.hrtf->filename) == 0) - { TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); + hrtf = loaded_entry->hrtf; goto skip_load; } - entry.hrtf = entry.hrtf->next; + loaded_entry = loaded_entry->next; } TRACE("Loading %s...\n", alstr_get_cstr(filename)); @@ -780,16 +788,33 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t return; } - hrtf->next = LoadedHrtfs; - LoadedHrtfs = hrtf; + loaded_entry = al_calloc(DEF_ALIGN, + offsetof(struct LoadedHrtfEntry, filename[alstr_length(filename)+1]) + ); + loaded_entry->next = LoadedHrtfs; + loaded_entry->hrtf = hrtf; + strcpy(loaded_entry->filename, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; + TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - entry.hrtf = hrtf; skip_load: + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ + name = strrchr(alstr_get_cstr(filename), '/'); + if(!name) name = strrchr(alstr_get_cstr(filename), '\\'); + if(!name) name = alstr_get_cstr(filename); + else ++name; + + ext = strrchr(name, '.'); + i = 0; do { - alstr_copy(&entry.name, filename); + if(!ext) + alstr_copy_cstr(&entry.name, name); + else + alstr_copy_range(&entry.name, name, ext); if(i != 0) { char str[64]; @@ -802,6 +827,7 @@ skip_load: VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); + entry.hrtf = hrtf; TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); VECTOR_PUSH_BACK(*list, entry); @@ -1015,12 +1041,13 @@ void FreeHrtfList(vector_HrtfEntry *list) void FreeHrtfs(void) { - struct Hrtf *Hrtf = LoadedHrtfs; + struct LoadedHrtfEntry *Hrtf = LoadedHrtfs; LoadedHrtfs = NULL; while(Hrtf != NULL) { - struct Hrtf *next = Hrtf->next; + struct LoadedHrtfEntry *next = Hrtf->next; + al_free(Hrtf->hrtf); al_free(Hrtf); Hrtf = next; } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index c5257d3d..deaf11c2 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -17,9 +17,6 @@ struct Hrtf { const ALushort *evOffset; const ALfloat *coeffs; const ALubyte *delays; - - const char *filename; - struct Hrtf *next; }; #define HRTFDELAY_BITS (20) -- cgit v1.2.3 From f76dea0c0321ebcc0f5a8838f1826309463cd2c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Apr 2017 11:29:58 -0700 Subject: Store the loaded hrtf entry container in the enumerated hrtf entry --- Alc/ALc.c | 10 +++---- Alc/hrtf.c | 74 ++++++++++++++++++++++------------------------- Alc/hrtf.h | 26 +++++++++++------ Alc/panning.c | 14 +++++---- OpenAL32/Include/alMain.h | 11 +++---- 5 files changed, 70 insertions(+), 65 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f248a998..d154e240 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2056,11 +2056,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(VECTOR_SIZE(device->HrtfList) > 0) { - device->FmtChans = DevFmtStereo; + const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, 0).hrtf->handle; if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) - device->Frequency = VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf->sampleRate; - else - device->Frequency = VECTOR_ELEM(device->HrtfList, 0).hrtf->sampleRate; + hrtf = VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf->handle; + device->FmtChans = DevFmtStereo; + device->Frequency = hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; } else @@ -2088,7 +2088,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } for(i = 0;i < VECTOR_SIZE(device->HrtfList);i++) { - const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, i).hrtf; + const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, i).hrtf->handle; if(hrtf->sampleRate == device->Frequency) break; } diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 0aad5e97..f0ec9a98 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -53,11 +53,7 @@ static const ALchar magicMarker01[8] = "MinPHR01"; * directional sounds. */ static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; -static struct LoadedHrtfEntry { - struct LoadedHrtfEntry *next; - struct Hrtf *hrtf; - char filename[]; -} *LoadedHrtfs = NULL; +static struct HrtfEntry *LoadedHrtfs = NULL; /* Calculate the elevation index given the polar elevation in radians. This @@ -610,12 +606,12 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str return Hrtf; } -static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) +static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) { - HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; - struct LoadedHrtfEntry *loaded_entry; + EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; + struct HrtfEntry *loaded_entry; struct Hrtf *hrtf = NULL; - const HrtfEntry *iter; + const EnumeratedHrtf *iter; struct FileMapping fmap; const char *name; const char *ext; @@ -628,8 +624,8 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) { /* Check if this entry has already been added to the list. */ -#define MATCH_ENTRY(i) (loaded_entry->hrtf == (i)->hrtf) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_ENTRY); +#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); if(iter != VECTOR_END(*list)) { TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); @@ -638,7 +634,6 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) #undef MATCH_FNAME TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); - hrtf = loaded_entry->hrtf; goto skip_load; } loaded_entry = loaded_entry->next; @@ -679,15 +674,15 @@ static void AddFileEntry(vector_HrtfEntry *list, const_al_string filename) } loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct LoadedHrtfEntry, filename[alstr_length(filename)+1]) + offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) ); loaded_entry->next = LoadedHrtfs; - loaded_entry->hrtf = hrtf; + loaded_entry->handle = hrtf; strcpy(loaded_entry->filename, alstr_get_cstr(filename)); LoadedHrtfs = loaded_entry; TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -714,10 +709,10 @@ skip_load: ++i; #define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - entry.hrtf = hrtf; + entry.hrtf = loaded_entry; TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(filename)); @@ -727,12 +722,12 @@ skip_load: /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, const_al_string filename) +static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const ALubyte *data, size_t datalen, const_al_string filename) { - HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; - struct LoadedHrtfEntry *loaded_entry; + EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; + struct HrtfEntry *loaded_entry; struct Hrtf *hrtf = NULL; - const HrtfEntry *iter; + const EnumeratedHrtf *iter; const char *name; const char *ext; int i; @@ -742,8 +737,8 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t { if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0) { -#define MATCH_ENTRY(i) (loaded_entry->hrtf == (i)->hrtf) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_ENTRY); +#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); if(iter != VECTOR_END(*list)) { TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); @@ -752,7 +747,6 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t #undef MATCH_FNAME TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); - hrtf = loaded_entry->hrtf; goto skip_load; } loaded_entry = loaded_entry->next; @@ -789,15 +783,15 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t } loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct LoadedHrtfEntry, filename[alstr_length(filename)+1]) + offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) ); loaded_entry->next = LoadedHrtfs; - loaded_entry->hrtf = hrtf; + loaded_entry->handle = hrtf; strcpy(loaded_entry->filename, alstr_get_cstr(filename)); LoadedHrtfs = loaded_entry; TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a @@ -824,10 +818,10 @@ skip_load: ++i; #define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME); + VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME); #undef MATCH_NAME } while(iter != VECTOR_END(*list)); - entry.hrtf = hrtf; + entry.hrtf = loaded_entry; TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name)); VECTOR_PUSH_BACK(*list, entry); @@ -928,9 +922,9 @@ static const ALubyte *GetResource(int name, size_t *size) #endif #endif -vector_HrtfEntry EnumerateHrtf(const_al_string devname) +vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) { - vector_HrtfEntry list = VECTOR_INIT_STATIC(); + vector_EnumeratedHrtf list = VECTOR_INIT_STATIC(); const char *defaulthrtf = ""; const char *pathlist = ""; bool usedefaults = true; @@ -1011,18 +1005,18 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) { - const HrtfEntry *iter; + const EnumeratedHrtf *iter; /* Find the preferred HRTF and move it to the front of the list. */ #define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0) - VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY); + VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY); #undef FIND_ENTRY if(iter == VECTOR_END(list)) WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf); else if(iter != VECTOR_BEGIN(list)) { - HrtfEntry entry = *iter; + EnumeratedHrtf entry = *iter; memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0), - (iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry)); + (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf)); VECTOR_ELEM(list,0) = entry; } } @@ -1030,10 +1024,10 @@ vector_HrtfEntry EnumerateHrtf(const_al_string devname) return list; } -void FreeHrtfList(vector_HrtfEntry *list) +void FreeHrtfList(vector_EnumeratedHrtf *list) { #define CLEAR_ENTRY(i) alstr_reset(&(i)->name) - VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY); + VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY); VECTOR_DEINIT(*list); #undef CLEAR_ENTRY } @@ -1041,13 +1035,13 @@ void FreeHrtfList(vector_HrtfEntry *list) void FreeHrtfs(void) { - struct LoadedHrtfEntry *Hrtf = LoadedHrtfs; + struct HrtfEntry *Hrtf = LoadedHrtfs; LoadedHrtfs = NULL; while(Hrtf != NULL) { - struct LoadedHrtfEntry *next = Hrtf->next; - al_free(Hrtf->hrtf); + struct HrtfEntry *next = Hrtf->next; + al_free(Hrtf->handle); al_free(Hrtf); Hrtf = next; } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index deaf11c2..009bddea 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -8,6 +8,16 @@ #include "alstring.h" +#define HRTFDELAY_BITS (20) +#define HRTFDELAY_FRACONE (1<= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) { - const HrtfEntry *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); - if(entry->hrtf->sampleRate == device->Frequency) + const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); + const struct Hrtf *hrtf = entry->hrtf->handle; + if(hrtf->sampleRate == device->Frequency) { - device->HrtfHandle = entry->hrtf; + device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); } } for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) { - const HrtfEntry *entry = &VECTOR_ELEM(device->HrtfList, i); - if(entry->hrtf->sampleRate == device->Frequency) + const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); + const struct Hrtf *hrtf = entry->hrtf->handle; + if(hrtf->sampleRate == device->Frequency) { - device->HrtfHandle = entry->hrtf; + device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 9c1ef099..3a26bff2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -358,6 +358,7 @@ extern "C" { #endif struct Hrtf; +struct HrtfEntry; #define DEFAULT_OUTPUT_RATE (44100) @@ -633,12 +634,12 @@ typedef struct DirectHrtfState { } Chan[]; } DirectHrtfState; -typedef struct HrtfEntry { +typedef struct EnumeratedHrtf { al_string name; - const struct Hrtf *hrtf; -} HrtfEntry; -TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry) + const struct HrtfEntry *hrtf; +} EnumeratedHrtf; +TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf) /* Maximum delay in samples for speaker distance compensation. */ @@ -702,7 +703,7 @@ struct ALCdevice_struct DirectHrtfState *Hrtf; al_string HrtfName; const struct Hrtf *HrtfHandle; - vector_HrtfEntry HrtfList; + vector_EnumeratedHrtf HrtfList; ALCenum HrtfStatus; /* UHJ encoder state */ -- cgit v1.2.3 From 2eaa10fc213dd60b197129da17b431b3d7e9f1d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Apr 2017 12:27:30 -0700 Subject: Load HRTF files as needed Currently only applies to external files, rather than embedded datasets. Also, HRTFs aren't unloaded after being loaded, until library shutdown. --- Alc/ALc.c | 40 +++---------- Alc/hrtf.c | 140 +++++++++++++++++++++++++++------------------- Alc/hrtf.h | 9 +-- Alc/panning.c | 8 +-- OpenAL32/Include/alMain.h | 2 +- 5 files changed, 97 insertions(+), 102 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d154e240..ed2c5e8e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2049,6 +2049,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { + const struct Hrtf *hrtf = NULL; if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); @@ -2056,9 +2057,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(VECTOR_SIZE(device->HrtfList) > 0) { - const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, 0).hrtf->handle; if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) - hrtf = VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf->handle; + hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf); + else + hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, 0).hrtf); + } + + if(hrtf) + { device->FmtChans = DevFmtStereo; device->Frequency = hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; @@ -2071,36 +2077,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } } - else if(hrtf_appreq == Hrtf_Enable) - { - size_t i = VECTOR_SIZE(device->HrtfList); - /* Loopback device. We don't need to match to a specific HRTF entry - * here. If the requested ID matches, we'll pick that later, if not, - * we'll try to auto-select one anyway. Just make sure one exists - * that'll work. - */ - if(device->FmtChans == DevFmtStereo) - { - if(VECTOR_SIZE(device->HrtfList) == 0) - { - VECTOR_DEINIT(device->HrtfList); - device->HrtfList = EnumerateHrtf(device->DeviceName); - } - for(i = 0;i < VECTOR_SIZE(device->HrtfList);i++) - { - const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, i).hrtf->handle; - if(hrtf->sampleRate == device->Frequency) - break; - } - } - if(i == VECTOR_SIZE(device->HrtfList)) - { - ERR("Requested format not HRTF compatible: %s, %uhz\n", - DevFmtChannelsString(device->FmtChans), device->Frequency); - hrtf_appreq = Hrtf_Disable; - device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; - } - } oldFreq = device->Frequency; oldChans = device->FmtChans; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index f0ec9a98..4394cf56 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -46,6 +46,12 @@ #define MIN_AZ_COUNT (1) #define MAX_AZ_COUNT (128) +struct HrtfEntry { + struct HrtfEntry *next; + struct Hrtf *handle; + char filename[]; +}; + static const ALchar magicMarker00[8] = "MinPHR00"; static const ALchar magicMarker01[8] = "MinPHR01"; @@ -240,7 +246,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, const ALushort *evOffset, const ALshort *coeffs, const ALubyte *delays, - const_al_string filename) + const char *filename) { struct Hrtf *Hrtf; size_t total; @@ -255,7 +261,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount Hrtf = al_calloc(16, total); if(Hrtf == NULL) - ERR("Out of memory allocating storage for %s.\n", alstr_get_cstr(filename)); + ERR("Out of memory allocating storage for %s.\n", filename); else { uintptr_t offset = sizeof(struct Hrtf); @@ -298,7 +304,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount return Hrtf; } -static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename) +static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; @@ -314,8 +320,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < 9) { - ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", - alstr_get_cstr(filename), 9, datalen); + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, 9, datalen); return NULL; } @@ -353,8 +358,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < evCount*2) { - ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", - alstr_get_cstr(filename), evCount*2, datalen); + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen); return NULL; } @@ -423,7 +427,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str if(datalen < reqsize) { ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n", - alstr_get_cstr(filename), reqsize, datalen); + filename, reqsize, datalen); failed = AL_TRUE; } } @@ -463,7 +467,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str return Hrtf; } -static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) +static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; @@ -478,8 +482,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < 6) { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - alstr_get_cstr(filename), 6, datalen); + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 6, datalen); return NULL; } @@ -512,8 +515,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < evCount) { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - alstr_get_cstr(filename), evCount, datalen); + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen); return NULL; } @@ -565,7 +567,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str if(datalen < reqsize) { ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - alstr_get_cstr(filename), reqsize, datalen); + filename, reqsize, datalen); failed = AL_TRUE; } } @@ -610,9 +612,7 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) { EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; struct HrtfEntry *loaded_entry; - struct Hrtf *hrtf = NULL; const EnumeratedHrtf *iter; - struct FileMapping fmap; const char *name; const char *ext; int i; @@ -639,51 +639,14 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) loaded_entry = loaded_entry->next; } - TRACE("Loading %s...\n", alstr_get_cstr(filename)); - fmap = MapFileToMem(alstr_get_cstr(filename)); - if(fmap.ptr == NULL) - { - ERR("Could not open %s\n", alstr_get_cstr(filename)); - return; - } - - if(fmap.len < sizeof(magicMarker01)) - ERR("%s data is too short ("SZFMT" bytes)\n", alstr_get_cstr(filename), fmap.len); - else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), - fmap.len-sizeof(magicMarker01), filename - ); - } - else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), - fmap.len-sizeof(magicMarker00), filename - ); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)fmap.ptr); - UnmapFileMem(&fmap); - - if(!hrtf) - { - ERR("Failed to load %s\n", alstr_get_cstr(filename)); - return; - } - loaded_entry = al_calloc(DEF_ALIGN, offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) ); loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = hrtf; + loaded_entry->handle = NULL; strcpy(loaded_entry->filename, alstr_get_cstr(filename)); LoadedHrtfs = loaded_entry; - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ @@ -762,19 +725,19 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const ALubyte *data, si if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(data+sizeof(magicMarker01), - datalen-sizeof(magicMarker01), filename + hrtf = LoadHrtf01((const ALubyte*)data+sizeof(magicMarker01), + datalen-sizeof(magicMarker01), alstr_get_cstr(filename) ); } else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(data+sizeof(magicMarker00), - datalen-sizeof(magicMarker00), filename + hrtf = LoadHrtf00((const ALubyte*)data+sizeof(magicMarker00), + datalen-sizeof(magicMarker00), alstr_get_cstr(filename) ); } else - ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), data); + ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)data); if(!hrtf) { @@ -1032,6 +995,65 @@ void FreeHrtfList(vector_EnumeratedHrtf *list) #undef CLEAR_ENTRY } +struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) +{ + static ATOMIC_FLAG LoadLock = ATOMIC_FLAG_INIT; + struct Hrtf *hrtf = NULL; + struct FileMapping fmap; + + while(ATOMIC_FLAG_TEST_AND_SET(&LoadLock, almemory_order_seq_cst)) + althrd_yield(); + + if(entry->handle) + { + hrtf = entry->handle; + goto done; + } + + TRACE("Loading %s...\n", entry->filename); + fmap = MapFileToMem(entry->filename); + if(fmap.ptr == NULL) + { + ERR("Could not open %s\n", entry->filename); + goto done; + } + + if(fmap.len < sizeof(magicMarker01)) + ERR("%s data is too short ("SZFMT" bytes)\n", entry->filename, fmap.len); + else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) + { + TRACE("Detected data set format v1\n"); + hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), + fmap.len-sizeof(magicMarker01), entry->filename + ); + } + else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), + fmap.len-sizeof(magicMarker00), entry->filename + ); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", entry->filename, (const char*)fmap.ptr); + UnmapFileMem(&fmap); + + if(!hrtf) + { + ERR("Failed to load %s\n", entry->filename); + goto done; + } + + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + + entry->handle = hrtf; + +done: + ATOMIC_FLAG_CLEAR(&LoadLock, almemory_order_seq_cst); + return hrtf; +} + void FreeHrtfs(void) { diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 009bddea..4e25dde3 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -18,6 +18,8 @@ #define HRTF_AMBI_MAX_CHANNELS 16 +struct HrtfEntry; + struct Hrtf { ALuint sampleRate; ALsizei irSize; @@ -29,17 +31,12 @@ struct Hrtf { const ALubyte *delays; }; -struct HrtfEntry { - struct HrtfEntry *next; - struct Hrtf *handle; - char filename[]; -}; - void FreeHrtfs(void); vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_EnumeratedHrtf *list); +struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays); diff --git a/Alc/panning.c b/Alc/panning.c index aa8175d4..bd550b32 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1151,8 +1151,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) { const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); - const struct Hrtf *hrtf = entry->hrtf->handle; - if(hrtf->sampleRate == device->Frequency) + const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); @@ -1162,8 +1162,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) { const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); - const struct Hrtf *hrtf = entry->hrtf->handle; - if(hrtf->sampleRate == device->Frequency) + const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3a26bff2..4807e07d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -637,7 +637,7 @@ typedef struct DirectHrtfState { typedef struct EnumeratedHrtf { al_string name; - const struct HrtfEntry *hrtf; + struct HrtfEntry *hrtf; } EnumeratedHrtf; TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf) -- cgit v1.2.3 From 37f666fbabad7db69a0604e4d38181d79c0dbc05 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 5 Apr 2017 12:46:02 -0700 Subject: Fix an incorrect message --- Alc/hrtf.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 4394cf56..47db6bcf 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -633,21 +633,24 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) } #undef MATCH_FNAME - TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); - goto skip_load; + break; } loaded_entry = loaded_entry->next; } - loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) - ); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = NULL; - strcpy(loaded_entry->filename, alstr_get_cstr(filename)); - LoadedHrtfs = loaded_entry; + if(!loaded_entry) + { + TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); + + loaded_entry = al_calloc(DEF_ALIGN, + offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) + ); + loaded_entry->next = LoadedHrtfs; + loaded_entry->handle = NULL; + strcpy(loaded_entry->filename, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; + } -skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ name = strrchr(alstr_get_cstr(filename), '/'); -- cgit v1.2.3 From 94f514ae5a0392f5f01f2b479d1d858af688ae24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Apr 2017 01:35:09 -0700 Subject: Load embedded HRTF entries as-needed --- Alc/hrtf.c | 117 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 47db6bcf..35be4dc3 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -688,7 +688,7 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer * for input instead of opening the given filename. */ -static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const ALubyte *data, size_t datalen, const_al_string filename) +static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, size_t residx) { EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; struct HrtfEntry *loaded_entry; @@ -712,54 +712,27 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const ALubyte *data, si } #undef MATCH_FNAME - TRACE("Skipping load of already-loaded file %s\n", alstr_get_cstr(filename)); - goto skip_load; + break; } loaded_entry = loaded_entry->next; } - TRACE("Loading %s...\n", alstr_get_cstr(filename)); - if(datalen < sizeof(magicMarker01)) + if(!loaded_entry) { - ERR("%s data is too short ("SZFMT" bytes)\n", alstr_get_cstr(filename), datalen); - return; - } + size_t namelen = alstr_length(filename)+32; - if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01((const ALubyte*)data+sizeof(magicMarker01), - datalen-sizeof(magicMarker01), alstr_get_cstr(filename) - ); - } - else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00((const ALubyte*)data+sizeof(magicMarker00), - datalen-sizeof(magicMarker00), alstr_get_cstr(filename) - ); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)data); + TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); - if(!hrtf) - { - ERR("Failed to load %s\n", alstr_get_cstr(filename)); - return; + loaded_entry = al_calloc(DEF_ALIGN, + offsetof(struct HrtfEntry, filename[namelen]) + ); + loaded_entry->next = LoadedHrtfs; + loaded_entry->handle = hrtf; + snprintf(loaded_entry->filename, namelen, "!"SZFMT"_%s", + residx, alstr_get_cstr(filename)); + LoadedHrtfs = loaded_entry; } - loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) - ); - loaded_entry->next = LoadedHrtfs; - loaded_entry->handle = hrtf; - strcpy(loaded_entry->filename, alstr_get_cstr(filename)); - LoadedHrtfs = loaded_entry; - - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - -skip_load: /* TODO: Get a human-readable name from the HRTF data (possibly coming in a * format update). */ name = strrchr(alstr_get_cstr(filename), '/'); @@ -957,14 +930,14 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) if(rdata != NULL && rsize > 0) { alstr_copy_cstr(&ename, "Built-In 44100hz"); - AddBuiltInEntry(&list, rdata, rsize, ename); + AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR); } rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize); if(rdata != NULL && rsize > 0) { alstr_copy_cstr(&ename, "Built-In 48000hz"); - AddBuiltInEntry(&list, rdata, rsize, ename); + AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR); } alstr_reset(&ename); } @@ -1003,6 +976,11 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) static ATOMIC_FLAG LoadLock = ATOMIC_FLAG_INIT; struct Hrtf *hrtf = NULL; struct FileMapping fmap; + const ALubyte *rdata; + const char *name; + size_t residx; + size_t rsize; + char ch; while(ATOMIC_FLAG_TEST_AND_SET(&LoadLock, almemory_order_seq_cst)) althrd_yield(); @@ -1013,37 +991,60 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) goto done; } - TRACE("Loading %s...\n", entry->filename); - fmap = MapFileToMem(entry->filename); - if(fmap.ptr == NULL) + fmap.ptr = NULL; + fmap.len = 0; + if(sscanf(entry->filename, "!"SZFMT"%c", &residx, &ch) == 2 && ch == '_') { - ERR("Could not open %s\n", entry->filename); - goto done; + name = strchr(entry->filename, ch)+1; + + TRACE("Loading %s...\n", name); + rdata = GetResource(residx, &rsize); + if(rdata == NULL || rsize == 0) + { + ERR("Could not get resource "SZFMT", %s\n", residx, name); + goto done; + } + } + else + { + name = entry->filename; + + TRACE("Loading %s...\n", entry->filename); + fmap = MapFileToMem(entry->filename); + if(fmap.ptr == NULL) + { + ERR("Could not open %s\n", entry->filename); + goto done; + } + + rdata = fmap.ptr; + rsize = fmap.len; } - if(fmap.len < sizeof(magicMarker01)) - ERR("%s data is too short ("SZFMT" bytes)\n", entry->filename, fmap.len); - else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) + if(rsize < sizeof(magicMarker01)) + ERR("%s data is too short ("SZFMT" bytes)\n", name, rsize); + else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), - fmap.len-sizeof(magicMarker01), entry->filename + hrtf = LoadHrtf01(rdata+sizeof(magicMarker01), + rsize-sizeof(magicMarker01), name ); } - else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) + else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), - fmap.len-sizeof(magicMarker00), entry->filename + hrtf = LoadHrtf00(rdata+sizeof(magicMarker00), + rsize-sizeof(magicMarker00), name ); } else - ERR("Invalid header in %s: \"%.8s\"\n", entry->filename, (const char*)fmap.ptr); - UnmapFileMem(&fmap); + ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata); + if(fmap.ptr) + UnmapFileMem(&fmap); if(!hrtf) { - ERR("Failed to load %s\n", entry->filename); + ERR("Failed to load %s\n", name); goto done; } -- cgit v1.2.3 From 338d61f9072bfb811266012c2a9c0a290cf353d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Apr 2017 13:00:29 -0700 Subject: Reference count HRTFs and unload them when unused --- Alc/ALc.c | 11 ++++++++++- Alc/hrtf.c | 49 ++++++++++++++++++++++++++++++++++++++++++----- Alc/hrtf.h | 5 +++++ Alc/panning.c | 32 +++++++++++++++++++++++++++++-- OpenAL32/Include/alMain.h | 2 +- 5 files changed, 90 insertions(+), 9 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ed2c5e8e..0cc36cad 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2049,7 +2049,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) { - const struct Hrtf *hrtf = NULL; + struct Hrtf *hrtf = NULL; if(VECTOR_SIZE(device->HrtfList) == 0) { VECTOR_DEINIT(device->HrtfList); @@ -2068,6 +2068,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FmtChans = DevFmtStereo; device->Frequency = hrtf->sampleRate; device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; + if(device->HrtfHandle) + Hrtf_DecRef(device->HrtfHandle); + device->HrtfHandle = hrtf; } else { @@ -2338,6 +2341,9 @@ static ALCvoid FreeDevice(ALCdevice *device) AL_STRING_DEINIT(device->HrtfName); FreeHrtfList(&device->HrtfList); + if(device->HrtfHandle) + Hrtf_DecRef(device->HrtfHandle); + device->HrtfHandle = NULL; al_free(device->Hrtf); device->Hrtf = NULL; @@ -3755,6 +3761,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Bs2b = NULL; device->Uhj_Encoder = NULL; device->Hrtf = NULL; + device->HrtfHandle = NULL; VECTOR_INIT(device->HrtfList); AL_STRING_INIT(device->HrtfName); device->Render_Mode = NormalRender; @@ -4062,6 +4069,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Type = Capture; device->Hrtf = NULL; + device->HrtfHandle = NULL; VECTOR_INIT(device->HrtfList); AL_STRING_INIT(device->HrtfName); @@ -4272,6 +4280,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Flags = 0; device->Hrtf = NULL; + device->HrtfHandle = NULL; VECTOR_INIT(device->HrtfList); AL_STRING_INIT(device->HrtfName); device->Bs2b = NULL; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 35be4dc3..32a6357e 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -59,6 +59,7 @@ static const ALchar magicMarker01[8] = "MinPHR01"; * directional sounds. */ static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/; +static ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT; static struct HrtfEntry *LoadedHrtfs = NULL; @@ -272,6 +273,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount ALfloat *_coeffs; ALsizei i; + InitRef(&Hrtf->ref, 0); Hrtf->sampleRate = rate; Hrtf->irSize = irSize; Hrtf->evCount = evCount; @@ -973,7 +975,6 @@ void FreeHrtfList(vector_EnumeratedHrtf *list) struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) { - static ATOMIC_FLAG LoadLock = ATOMIC_FLAG_INIT; struct Hrtf *hrtf = NULL; struct FileMapping fmap; const ALubyte *rdata; @@ -982,12 +983,13 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) size_t rsize; char ch; - while(ATOMIC_FLAG_TEST_AND_SET(&LoadLock, almemory_order_seq_cst)) + while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) althrd_yield(); if(entry->handle) { hrtf = entry->handle; + Hrtf_IncRef(hrtf); goto done; } @@ -1047,18 +1049,55 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry) ERR("Failed to load %s\n", name); goto done; } + entry->handle = hrtf; + Hrtf_IncRef(hrtf); TRACE("Loaded HRTF support for format: %s %uhz\n", DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); - entry->handle = hrtf; - done: - ATOMIC_FLAG_CLEAR(&LoadLock, almemory_order_seq_cst); + ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); return hrtf; } +void Hrtf_IncRef(struct Hrtf *hrtf) +{ + uint ref = IncrementRef(&hrtf->ref); + TRACEREF("%p increasing refcount to %u\n", hrtf, ref); +} + +void Hrtf_DecRef(struct Hrtf *hrtf) +{ + struct HrtfEntry *Hrtf; + uint ref = DecrementRef(&hrtf->ref); + TRACEREF("%p decreasing refcount to %u\n", hrtf, ref); + if(ref == 0) + { + while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst)) + althrd_yield(); + + Hrtf = LoadedHrtfs; + while(Hrtf != NULL) + { + /* Need to double-check that it's still unused, as another device + * could've reacquired this HRTF after its reference went to 0 and + * before the lock was taken. + */ + if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0) + { + al_free(Hrtf->handle); + Hrtf->handle = NULL; + TRACE("Unloaded unused HRTF %s\n", Hrtf->filename); + } + Hrtf = Hrtf->next; + } + + ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst); + } +} + + void FreeHrtfs(void) { struct HrtfEntry *Hrtf = LoadedHrtfs; diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 4e25dde3..3ec3e19e 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -6,6 +6,7 @@ #include "alMain.h" #include "alstring.h" +#include "atomic.h" #define HRTFDELAY_BITS (20) @@ -21,6 +22,8 @@ struct HrtfEntry; struct Hrtf { + RefCount ref; + ALuint sampleRate; ALsizei irSize; ALubyte evCount; @@ -37,6 +40,8 @@ void FreeHrtfs(void); vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname); void FreeHrtfList(vector_EnumeratedHrtf *list); struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry); +void Hrtf_IncRef(struct Hrtf *hrtf); +void Hrtf_DecRef(struct Hrtf *hrtf); void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays); diff --git a/Alc/panning.c b/Alc/panning.c index bd550b32..8a8840fb 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -997,6 +997,8 @@ static void InitUhjPanning(ALCdevice *device) void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) { + /* Hold the HRTF the device last used, in case it's used again. */ + struct Hrtf *old_hrtf = device->HrtfHandle; const char *mode; bool headphones; int bs2blevel; @@ -1028,6 +1030,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf const char *devname, *layout = NULL; AmbDecConf conf, *pconf = NULL; + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; if(hrtf_appreq == Hrtf_Enable) device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; @@ -1151,29 +1156,49 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList)) { const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id); - const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); } + else if(hrtf) + Hrtf_DecRef(hrtf); + } + + /* Reuse the old HRTF if its compatible and any desired HRTF isn't + * compatible. + */ + if(!device->HrtfHandle && old_hrtf) + { + if(old_hrtf->sampleRate == device->Frequency) + { + device->HrtfHandle = old_hrtf; + old_hrtf = NULL; + } } for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) { const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); - const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); + struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf); if(hrtf && hrtf->sampleRate == device->Frequency) { device->HrtfHandle = hrtf; alstr_copy(&device->HrtfName, entry->name); } + else if(hrtf) + Hrtf_DecRef(hrtf); } if(device->HrtfHandle) { bool hoa_mode; + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; + device->Render_Mode = HrtfRender; if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { @@ -1211,6 +1236,9 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; no_hrtf: + if(old_hrtf) + Hrtf_DecRef(old_hrtf); + old_hrtf = NULL; TRACE("HRTF disabled\n"); device->Render_Mode = StereoPair; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4807e07d..7add9310 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -702,7 +702,7 @@ struct ALCdevice_struct /* HRTF state and info */ DirectHrtfState *Hrtf; al_string HrtfName; - const struct Hrtf *HrtfHandle; + struct Hrtf *HrtfHandle; vector_EnumeratedHrtf HrtfList; ALCenum HrtfStatus; -- cgit v1.2.3 From 70a097bf59741dca44069ef139a22d2b7e0a9a07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 03:21:40 -0700 Subject: Clean up a comment --- Alc/panning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 8a8840fb..63ff618e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1166,7 +1166,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf Hrtf_DecRef(hrtf); } - /* Reuse the old HRTF if its compatible and any desired HRTF isn't + /* Reuse the old HRTF if it's compatible and any desired HRTF wasn't * compatible. */ if(!device->HrtfHandle && old_hrtf) -- cgit v1.2.3 From 710bbde09c45cf32e94e815f43ce48fd80c9d77b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 03:33:03 -0700 Subject: Ensure SDL_AUDIO_BITSIZE is defined for older SDL2 versions --- examples/alloopback.c | 7 +++++++ examples/alstream.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/examples/alloopback.c b/examples/alloopback.c index 95ac433f..16553f9b 100644 --- a/examples/alloopback.c +++ b/examples/alloopback.c @@ -38,6 +38,13 @@ #include "common/alhelpers.h" +#ifndef SDL_AUDIO_MASK_BITSIZE +#define SDL_AUDIO_MASK_BITSIZE (0xFF) +#endif +#ifndef SDL_AUDIO_BITSIZE +#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE) +#endif + #ifndef M_PI #define M_PI (3.14159265358979323846) #endif diff --git a/examples/alstream.c b/examples/alstream.c index d13899d0..68115e8d 100644 --- a/examples/alstream.c +++ b/examples/alstream.c @@ -39,6 +39,13 @@ #include "common/alhelpers.h" +#ifndef SDL_AUDIO_MASK_BITSIZE +#define SDL_AUDIO_MASK_BITSIZE (0xFF) +#endif +#ifndef SDL_AUDIO_BITSIZE +#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE) +#endif + /* 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. */ -- cgit v1.2.3 From 36f7dda1caafaef886ccd520ec3216c2689a062e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 03:57:40 -0700 Subject: Remove another reference to the sinc8 resampler --- Alc/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 88dbde88..69e52a6e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -156,7 +156,7 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) /* The sinc resampler makes use of a Kaiser window to limit the needed sample - * points to 4 and 8, respectively. + * points to 4. */ #ifndef M_PI -- cgit v1.2.3 From b551291840ee0b670fb54c41ec385702d51604d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 06:40:42 -0700 Subject: Allocate temp storage for delays when loading HRTFs --- Alc/hrtf.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 32a6357e..8c6df0d6 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -317,7 +317,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - const ALubyte *delays = NULL; + ALubyte *delays = NULL; ALuint i, j; if(datalen < 9) @@ -416,6 +416,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * if(!failed) { coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); + delays = malloc(sizeof(delays[0])*irCount); if(coeffs == NULL) { ERR("Out of memory.\n"); @@ -446,11 +447,10 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * } } - delays = data; - data += irCount; - datalen -= irCount; for(i = 0;i < irCount;i++) { + delays[i] = *(data++); + datalen -= 1; if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); @@ -466,6 +466,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * free(azCount); free(evOffset); free(coeffs); + free(delays); return Hrtf; } @@ -479,7 +480,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * const ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - const ALubyte *delays = NULL; + ALubyte *delays = NULL; ALuint i, j; if(datalen < 6) @@ -556,6 +557,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * } coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); + delays = malloc(sizeof(delays[0])*irCount); if(coeffs == NULL) { ERR("Out of memory.\n"); @@ -588,11 +590,10 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * } } - delays = data; - data += irCount; - datalen -= irCount; for(i = 0;i < irCount;i++) { + delays[i] = *(data++); + datalen -= 1; if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); @@ -607,9 +608,11 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * free(evOffset); free(coeffs); + free(delays); return Hrtf; } + static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) { EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL }; -- cgit v1.2.3 From e267f6b88eaf69d1ea03d9ac62a7c8ea866f5384 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 08:02:13 -0700 Subject: Don't explicitly restore the old HRTF when initializing panning Otherwise it won't store the name in the device. --- Alc/panning.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 63ff618e..dcdcf36d 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1166,18 +1166,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf Hrtf_DecRef(hrtf); } - /* Reuse the old HRTF if it's compatible and any desired HRTF wasn't - * compatible. - */ - if(!device->HrtfHandle && old_hrtf) - { - if(old_hrtf->sampleRate == device->Frequency) - { - device->HrtfHandle = old_hrtf; - old_hrtf = NULL; - } - } - for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++) { const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i); -- cgit v1.2.3 From 8f2e4d46ec2de3c813438c363919a3da6aab7a4f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 08:46:50 -0700 Subject: Store the HRTF coeffs as a stereo pair This will make it easier to handle HRTF data sets that have separate left and right ear responses. Will need an mhr version update to take advantage of that. --- Alc/hrtf.c | 152 +++++++++++++++++++++++++++++++++++++++---------------------- Alc/hrtf.h | 4 +- 2 files changed, 100 insertions(+), 56 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 8c6df0d6..0fbd34ee 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -88,8 +88,8 @@ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az) */ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays) { - ALsizei evidx, azidx, lidx, ridx; - ALsizei azcount, evoffset; + ALsizei evidx, azidx, idx; + ALsizei evoffset; ALfloat dirfact; ALsizei i; @@ -97,32 +97,29 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /* Claculate elevation index. */ evidx = CalcEvIndex(Hrtf->evCount, elevation); - azcount = Hrtf->azCount[evidx]; evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index. */ azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth); /* Calculate the HRIR indices for left and right channels. */ - lidx = evoffset + azidx; - ridx = evoffset + ((azcount-azidx) % azcount); + idx = evoffset + azidx; /* Calculate the HRIR delays. */ - delays[0] = fastf2i(Hrtf->delays[lidx]*dirfact + 0.5f); - delays[1] = fastf2i(Hrtf->delays[ridx]*dirfact + 0.5f); + delays[0] = fastf2i(Hrtf->delays[idx][0]*dirfact + 0.5f); + delays[1] = fastf2i(Hrtf->delays[idx][1]*dirfact + 0.5f); /* Calculate the sample offsets for the HRIR indices. */ - lidx *= Hrtf->irSize; - ridx *= Hrtf->irSize; + idx *= Hrtf->irSize; /* Calculate the normalized and attenuated HRIR coefficients. */ i = 0; - coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact); - coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact); + coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[idx+i][0], dirfact); + coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[idx+i][1], dirfact); for(i = 1;i < Hrtf->irSize;i++) { - coeffs[i][0] = Hrtf->coeffs[lidx+i] * dirfact; - coeffs[i][1] = Hrtf->coeffs[ridx+i] * dirfact; + coeffs[i][0] = Hrtf->coeffs[idx+i][0] * dirfact; + coeffs[i][1] = Hrtf->coeffs[idx+i][1] * dirfact; } } @@ -135,7 +132,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize */ #define NUM_BANDS 2 BandSplitter splitter; - ALsizei lidx[HRTF_AMBI_MAX_CHANNELS], ridx[HRTF_AMBI_MAX_CHANNELS]; + ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; @@ -160,29 +157,27 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ - lidx[c] = evoffset + azidx; - ridx[c] = evoffset + ((azcount-azidx) % azcount); + idx[c] = evoffset + azidx; - min_delay = mini(min_delay, mini(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]])); + min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } memset(temps, 0, sizeof(temps)); bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); for(c = 0;c < AmbiCount;c++) { - const ALfloat *fir; - ALsizei delay; + const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; + ALubyte delay; /* Add to the left output coefficients with the specified delay. */ - fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize]; - delay = Hrtf->delays[lidx[c]] - min_delay; + delay = Hrtf->delays[idx[c]][0] - min_delay; if(NUM_BANDS == 1) { for(i = 0;i < NumChannels;++i) { ALsizei j = delay, k = 0; while(j < HRIR_LENGTH && k < Hrtf->irSize) - state->Chan[i].Coeffs[j++][0] += fir[k++] * AmbiMatrix[c][0][i]; + state->Chan[i].Coeffs[j++][0] += fir[k++][0] * AmbiMatrix[c][0][i]; } } else @@ -190,7 +185,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize /* Band-split left HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i]; + temps[2][i] = fir[i][0]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); for(i = 0;i < NumChannels;++i) @@ -206,15 +201,14 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); /* Add to the right output coefficients with the specified delay. */ - fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize]; - delay = Hrtf->delays[ridx[c]] - min_delay; + delay = Hrtf->delays[idx[c]][1] - min_delay; if(NUM_BANDS == 1) { for(i = 0;i < NumChannels;++i) { ALsizei j = delay, k = 0; while(j < HRIR_LENGTH && k < Hrtf->irSize) - state->Chan[i].Coeffs[j++][1] += fir[k++] * AmbiMatrix[c][0][i]; + state->Chan[i].Coeffs[j++][1] += fir[k++][1] * AmbiMatrix[c][0][i]; } } else @@ -222,7 +216,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize /* Band-split right HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) - temps[2][i] = fir[i]; + temps[2][i] = fir[i][1]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); for(i = 0;i < NumChannels;++i) @@ -246,7 +240,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount, const ALubyte *azCount, const ALushort *evOffset, - const ALshort *coeffs, const ALubyte *delays, + const ALfloat (*coeffs)[2], const ALubyte (*delays)[2], const char *filename) { struct Hrtf *Hrtf; @@ -256,7 +250,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount total += sizeof(Hrtf->azCount[0])*evCount; total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */ total += sizeof(Hrtf->evOffset[0])*evCount; - total = RoundUp(total, sizeof(ALfloat)); /* Align for float fields */ + total = RoundUp(total, 16); /* Align for coefficients using SIMD */ total += sizeof(Hrtf->coeffs[0])*irSize*irCount; total += sizeof(Hrtf->delays[0])*irCount; @@ -269,8 +263,8 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount char *base = (char*)Hrtf; ALushort *_evOffset; ALubyte *_azCount; - ALubyte *_delays; - ALfloat *_coeffs; + ALubyte (*_delays)[2]; + ALfloat (*_coeffs)[2]; ALsizei i; InitRef(&Hrtf->ref, 0); @@ -286,19 +280,26 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset; offset += sizeof(_evOffset[0])*evCount; - offset = RoundUp(offset, sizeof(ALfloat)); /* Align for float fields */ - _coeffs = (ALfloat*)(base + offset); Hrtf->coeffs = _coeffs; + offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ + _coeffs = (ALfloat(*)[2])(base + offset); Hrtf->coeffs = _coeffs; offset += sizeof(_coeffs[0])*irSize*irCount; - _delays = (ALubyte*)(base + offset); Hrtf->delays = _delays; + _delays = (ALubyte(*)[2])(base + offset); Hrtf->delays = _delays; offset += sizeof(_delays[0])*irCount; /* Copy input data to storage. */ for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; for(i = 0;i < irSize*irCount;i++) - _coeffs[i] = coeffs[i] / 32768.0f; - for(i = 0;i < irCount;i++) _delays[i] = delays[i]; + { + _coeffs[i][0] = coeffs[i][0]; + _coeffs[i][1] = coeffs[i][1]; + } + for(i = 0;i < irCount;i++) + { + _delays[i][0] = delays[i][0]; + _delays[i][1] = delays[i][1]; + } assert(offset == total); } @@ -311,14 +312,15 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; + ALuint rate = 0; + ALushort irCount = 0; ALushort irSize = 0; ALubyte evCount = 0; ALubyte *azCount = NULL; ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - ALubyte *delays = NULL; - ALuint i, j; + ALfloat (*coeffs)[2] = NULL; + ALubyte (*delays)[2] = NULL; + ALsizei i, j; if(datalen < 9) { @@ -441,27 +443,48 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * { for(j = 0;j < irSize;j++) { - coeffs[i+j] = *(data++); - coeffs[i+j] |= *(data++)<<8; + ALshort coeff; + coeff = *(data++); + coeff |= *(data++)<<8; datalen -= 2; + coeffs[i+j][0] = coeff / 32768.0f; } } for(i = 0;i < irCount;i++) { - delays[i] = *(data++); + delays[i][0] = *(data++); datalen -= 1; - if(delays[i] > maxDelay) + if(delays[i][0] > maxDelay) { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay); failed = AL_TRUE; } } } if(!failed) + { + /* Mirror the left ear responses to the right ear. */ + for(i = 0;i < evCount;i++) + { + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(j = 0;j < azcount;j++) + { + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); + ALsizei k; + + for(k = 0;k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount, evOffset, coeffs, delays, filename); + } free(azCount); free(evOffset); @@ -475,13 +498,15 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; - ALubyte irSize = 0, evCount = 0; + ALuint rate = 0; + ALushort irCount = 0; + ALushort irSize = 0; + ALubyte evCount = 0; const ALubyte *azCount = NULL; ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - ALubyte *delays = NULL; - ALuint i, j; + ALfloat (*coeffs)[2] = NULL; + ALubyte (*delays)[2] = NULL; + ALsizei i, j; if(datalen < 6) { @@ -586,25 +611,44 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * coeff = *(data++); coeff |= *(data++)<<8; datalen -= 2; - coeffs[i+j] = coeff; + coeffs[i+j][0] = coeff / 32768.0f; } } for(i = 0;i < irCount;i++) { - delays[i] = *(data++); + delays[i][0] = *(data++); datalen -= 1; - if(delays[i] > maxDelay) + if(delays[i][0] > maxDelay) { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay); failed = AL_TRUE; } } } if(!failed) + { + /* Mirror the left ear responses to the right ear. */ + for(i = 0;i < evCount;i++) + { + ALushort evoffset = evOffset[i]; + ALubyte azcount = azCount[i]; + for(j = 0;j < azcount;j++) + { + ALsizei lidx = evoffset + j; + ALsizei ridx = evoffset + ((azcount-j) % azcount); + ALsizei k; + + for(k = 0;k < irSize;k++) + coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0]; + delays[ridx][1] = delays[lidx][0]; + } + } + Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount, evOffset, coeffs, delays, filename); + } free(evOffset); free(coeffs); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 3ec3e19e..186ba3b2 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -30,8 +30,8 @@ struct Hrtf { const ALubyte *azCount; const ALushort *evOffset; - const ALfloat *coeffs; - const ALubyte *delays; + const ALfloat (*coeffs)[2]; + const ALubyte (*delays)[2]; }; -- cgit v1.2.3 From 7fd88086f67c6dd1fd006178c9d1a3457837ccd3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 09:49:06 -0700 Subject: Make sure malloc succeeded for 'delays' --- Alc/hrtf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 0fbd34ee..577946d8 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -419,7 +419,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * { coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL) + if(coeffs == NULL || delays == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; @@ -583,7 +583,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL) + if(coeffs == NULL || delays == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; -- cgit v1.2.3 From 5e9f5693a4e28ab08028b05e77684cad6ddd185b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Apr 2017 11:49:24 -0700 Subject: Combine a couple loops --- Alc/hrtf.c | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 577946d8..52806b17 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -167,17 +167,25 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize for(c = 0;c < AmbiCount;c++) { const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; - ALubyte delay; + ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; + ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; + + max_length = maxi(max_length, + mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) + ); - /* Add to the left output coefficients with the specified delay. */ - delay = Hrtf->delays[idx[c]][0] - min_delay; if(NUM_BANDS == 1) { for(i = 0;i < NumChannels;++i) { - ALsizei j = delay, k = 0; - while(j < HRIR_LENGTH && k < Hrtf->irSize) - state->Chan[i].Coeffs[j++][0] += fir[k++][0] * AmbiMatrix[c][0][i]; + ALsizei lidx = ldelay, ridx = rdelay; + ALsizei j = 0; + while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) + { + state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][0][i]; + state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][0][i]; + j++; + } } } else @@ -188,48 +196,36 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize temps[2][i] = fir[i][0]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + /* Apply left ear response with delay. */ for(i = 0;i < NumChannels;++i) { for(b = 0;b < NUM_BANDS;b++) { - ALsizei j = delay, k = 0; - while(j < HRIR_LENGTH) - state->Chan[i].Coeffs[j++][0] += temps[b][k++] * AmbiMatrix[c][b][i]; + ALsizei lidx = ldelay; + ALsizei j = 0; + while(lidx < HRIR_LENGTH) + state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][b][i]; } } - } - max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); - /* Add to the right output coefficients with the specified delay. */ - delay = Hrtf->delays[idx[c]][1] - min_delay; - if(NUM_BANDS == 1) - { - for(i = 0;i < NumChannels;++i) - { - ALsizei j = delay, k = 0; - while(j < HRIR_LENGTH && k < Hrtf->irSize) - state->Chan[i].Coeffs[j++][1] += fir[k++][1] * AmbiMatrix[c][0][i]; - } - } - else - { /* Band-split right HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) temps[2][i] = fir[i][1]; bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH); + /* Apply right ear response with delay. */ for(i = 0;i < NumChannels;++i) { for(b = 0;b < NUM_BANDS;b++) { - ALsizei j = delay, k = 0; - while(j < HRIR_LENGTH) - state->Chan[i].Coeffs[j++][1] += temps[b][k++] * AmbiMatrix[c][b][i]; + ALsizei ridx = rdelay; + ALsizei j = 0; + while(ridx < HRIR_LENGTH) + state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][b][i]; } } } - max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH)); } TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); -- cgit v1.2.3 From f1a5b6b6681b1c9950266f2e6bec22dcba6cba97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Apr 2017 03:00:53 -0700 Subject: Overwrite the old search path with the new one --- Alc/hrtf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 52806b17..23817d66 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -941,7 +941,7 @@ vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) vector_al_string flist; size_t i; - alstr_append_range(&pname, pathlist, end); + alstr_copy_range(&pname, pathlist, end); flist = SearchDataFiles(".mhr", alstr_get_cstr(pname)); for(i = 0;i < VECTOR_SIZE(flist);i++) -- cgit v1.2.3 From 1f64f9d016790797ecd81e00f0392b34abdddcb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Apr 2017 10:01:04 -0700 Subject: Try to write the full configured buffer length with PulseAudio This basically ignores tlength even if it's smaller than what was requested. It keeps up-to-date with minreq changes too now, in case that happens. --- Alc/backends/pulseaudio.c | 52 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 79ca38e5..0eda2abd 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -626,6 +626,11 @@ static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) 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); + /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new + * buffer attributes? Changing UpdateSize will change the ALC_REFRESH + * property, which probably shouldn't change between device resets. But + * leaving it alone means ALC_REFRESH will be off. + */ } static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata) @@ -797,7 +802,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr) ALCpulsePlayback *self = ptr; ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; ALuint buffer_size; - ALint update_size; size_t frame_size; ssize_t len; @@ -806,18 +810,30 @@ static int ALCpulsePlayback_mixerProc(void *ptr) 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, self->attr.tlength); - update_size = minu(update_size, buffer_size/2); - do { - len = pa_stream_writable_size(self->stream) - self->attr.tlength + - buffer_size; - if(len < update_size) + buffer_size = device->UpdateSize * device->NumUpdates * frame_size; + + while(!self->killNow && device->Connected) + { + len = pa_stream_writable_size(self->stream); + if(len < 0) { - if(pa_stream_is_corked(self->stream) == 1) + ERR("Failed to get writable size: %ld", (long)len); + aluHandleDisconnect(device); + break; + } + + /* Make sure we're going to write at least 2 'periods' (minreqs), in + * case the server increased it since starting playback. + */ + buffer_size = maxu(buffer_size, self->attr.minreq*2); + + /* NOTE: This assumes pa_stream_writable_size returns between 0 and + * tlength, else there will be more latency than intended. + */ + len = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size; + if(len < self->attr.minreq) + { + if(pa_stream_is_corked(self->stream)) { pa_operation *o; o = pa_stream_cork(self->stream, 0, NULL, NULL); @@ -826,11 +842,12 @@ static int ALCpulsePlayback_mixerProc(void *ptr) pa_threaded_mainloop_wait(self->loop); continue; } - len -= len%update_size; + len -= len%self->attr.minreq; while(len > 0) { size_t newlen = len; + int ret; void *buf; pa_free_cb_t free_func = NULL; @@ -842,10 +859,15 @@ static int ALCpulsePlayback_mixerProc(void *ptr) aluMixData(device, buf, newlen/frame_size); - pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); + ret = pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); + if(ret != PA_OK) + { + ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); + break; + } len -= newlen; } - } while(!self->killNow && device->Connected); + } pa_threaded_mainloop_unlock(self->loop); return 0; -- cgit v1.2.3 From 5ef7d8fe6248bccc8edf895afece8e1b44b0f4ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Apr 2017 12:27:30 -0700 Subject: Clean up some formatting --- Alc/backends/pulseaudio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 0eda2abd..26557ea8 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1067,8 +1067,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) self->attr.maxlength = -1; self->stream = ALCpulsePlayback_connectStream(alstr_get_cstr(self->device_name), - self->loop, self->context, flags, - &self->attr, &self->spec, &chanmap); + self->loop, self->context, flags, &self->attr, &self->spec, &chanmap + ); if(!self->stream) { pa_threaded_mainloop_unlock(self->loop); @@ -1542,9 +1542,9 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); - self->stream = ALCpulseCapture_connectStream(pulse_name, self->loop, self->context, - flags, &self->attr, &self->spec, - &chanmap); + self->stream = ALCpulseCapture_connectStream(pulse_name, + self->loop, self->context, flags, &self->attr, &self->spec, &chanmap + ); if(!self->stream) { pa_threaded_mainloop_unlock(self->loop); -- cgit v1.2.3 From 319d0971986309d7882a9be42a5aef7dc612945d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 8 Apr 2017 13:43:19 -0700 Subject: Pre-compute the sinc4 resampler coefficient table --- Alc/bsinc.c | 4100 ++++++++++++++++++++++++++++++++++++++++++++++++ Alc/mixer.c | 92 -- Alc/mixer_neon.c | 8 +- Alc/mixer_sse3.c | 8 +- Alc/mixer_sse41.c | 8 +- OpenAL32/Include/alu.h | 7 +- utils/bsincgen.c | 40 +- 7 files changed, 4154 insertions(+), 109 deletions(-) diff --git a/Alc/bsinc.c b/Alc/bsinc.c index f795120f..ad83c42b 100644 --- a/Alc/bsinc.c +++ b/Alc/bsinc.c @@ -979,3 +979,4103 @@ alignas(16) const ALfloat bsincTab[18840] = /* 12,14 */ -3.311614162e-04f, +9.124383184e-04f, -9.731965741e-04f, -9.055999228e-04f, +3.928365474e-03f, -4.572939653e-03f, +1.133926469e-03f, +3.134198780e-03f, -4.073990388e-03f, +1.902468489e-03f, +1.684748882e-04f, -6.042449626e-04f, /* 12,15 */ -3.212754781e-04f, +8.205283947e-04f, -6.994376016e-04f, -1.285631838e-03f, +4.064044128e-03f, -4.167864669e-03f, +3.806742210e-04f, +3.684471854e-03f, -4.112050532e-03f, +1.619691310e-03f, +4.291307465e-04f, -7.165252154e-04f }; + +alignas(16) const ALfloat sinc4Tab[4096][4] = +{ + { +1.972846707e-17f, +1.000000000e+00f, +1.972846707e-17f, -7.947592825e-19f }, + { -1.234844220e-04f, +9.999998638e-01f, +1.236324705e-04f, -2.493930525e-06f }, + { -2.468208365e-04f, +9.999994551e-01f, +2.474130305e-04f, -4.998192808e-06f }, + { -3.700092848e-04f, +9.999987739e-01f, +3.713417210e-04f, -7.512801591e-06f }, + { -4.930498082e-04f, +9.999978203e-01f, +4.954185828e-04f, -1.003777162e-05f }, + { -6.159424479e-04f, +9.999965942e-01f, +6.196436566e-04f, -1.257311763e-05f }, + { -7.386872455e-04f, +9.999950956e-01f, +7.440169831e-04f, -1.511885438e-05f }, + { -8.612842424e-04f, +9.999933246e-01f, +8.685386028e-04f, -1.767499661e-05f }, + { -9.837334803e-04f, +9.999912812e-01f, +9.932085563e-04f, -2.024155907e-05f }, + { -1.106035001e-03f, +9.999889652e-01f, +1.118026884e-03f, -2.281855651e-05f }, + { -1.228188846e-03f, +9.999863768e-01f, +1.242993626e-03f, -2.540600368e-05f }, + { -1.350195058e-03f, +9.999835160e-01f, +1.368108822e-03f, -2.800391533e-05f }, + { -1.472053677e-03f, +9.999803827e-01f, +1.493372514e-03f, -3.061230620e-05f }, + { -1.593764748e-03f, +9.999769770e-01f, +1.618784740e-03f, -3.323119106e-05f }, + { -1.715328311e-03f, +9.999732988e-01f, +1.744345541e-03f, -3.586058466e-05f }, + { -1.836744408e-03f, +9.999693481e-01f, +1.870054956e-03f, -3.850050175e-05f }, + { -1.958013083e-03f, +9.999651250e-01f, +1.995913026e-03f, -4.115095708e-05f }, + { -2.079134377e-03f, +9.999606295e-01f, +2.121919790e-03f, -4.381196542e-05f }, + { -2.200108333e-03f, +9.999558615e-01f, +2.248075287e-03f, -4.648354151e-05f }, + { -2.320934994e-03f, +9.999508211e-01f, +2.374379558e-03f, -4.916570012e-05f }, + { -2.441614402e-03f, +9.999455083e-01f, +2.500832641e-03f, -5.185845600e-05f }, + { -2.562146601e-03f, +9.999399230e-01f, +2.627434576e-03f, -5.456182391e-05f }, + { -2.682531632e-03f, +9.999340653e-01f, +2.754185402e-03f, -5.727581862e-05f }, + { -2.802769538e-03f, +9.999279352e-01f, +2.881085158e-03f, -6.000045487e-05f }, + { -2.922860364e-03f, +9.999215326e-01f, +3.008133883e-03f, -6.273574744e-05f }, + { -3.042804151e-03f, +9.999148577e-01f, +3.135331617e-03f, -6.548171107e-05f }, + { -3.162600944e-03f, +9.999079103e-01f, +3.262678397e-03f, -6.823836055e-05f }, + { -3.282250785e-03f, +9.999006906e-01f, +3.390174264e-03f, -7.100571061e-05f }, + { -3.401753717e-03f, +9.998931984e-01f, +3.517819255e-03f, -7.378377604e-05f }, + { -3.521109785e-03f, +9.998854338e-01f, +3.645613409e-03f, -7.657257158e-05f }, + { -3.640319031e-03f, +9.998773969e-01f, +3.773556765e-03f, -7.937211202e-05f }, + { -3.759381500e-03f, +9.998690875e-01f, +3.901649361e-03f, -8.218241209e-05f }, + { -3.878297235e-03f, +9.998605058e-01f, +4.029891236e-03f, -8.500348659e-05f }, + { -3.997066279e-03f, +9.998516517e-01f, +4.158282427e-03f, -8.783535025e-05f }, + { -4.115688677e-03f, +9.998425252e-01f, +4.286822973e-03f, -9.067801786e-05f }, + { -4.234164473e-03f, +9.998331264e-01f, +4.415512912e-03f, -9.353150418e-05f }, + { -4.352493710e-03f, +9.998234552e-01f, +4.544352281e-03f, -9.639582397e-05f }, + { -4.470676433e-03f, +9.998135116e-01f, +4.673341119e-03f, -9.927099199e-05f }, + { -4.588712686e-03f, +9.998032957e-01f, +4.802479464e-03f, -1.021570230e-04f }, + { -4.706602513e-03f, +9.997928075e-01f, +4.931767353e-03f, -1.050539318e-04f }, + { -4.824345959e-03f, +9.997820469e-01f, +5.061204824e-03f, -1.079617332e-04f }, + { -4.941943068e-03f, +9.997710141e-01f, +5.190791913e-03f, -1.108804418e-04f }, + { -5.059393885e-03f, +9.997597089e-01f, +5.320528660e-03f, -1.138100725e-04f }, + { -5.176698454e-03f, +9.997481313e-01f, +5.450415101e-03f, -1.167506400e-04f }, + { -5.293856820e-03f, +9.997362815e-01f, +5.580451273e-03f, -1.197021592e-04f }, + { -5.410869028e-03f, +9.997241594e-01f, +5.710637213e-03f, -1.226646447e-04f }, + { -5.527735122e-03f, +9.997117650e-01f, +5.840972959e-03f, -1.256381113e-04f }, + { -5.644455148e-03f, +9.996990983e-01f, +5.971458547e-03f, -1.286225739e-04f }, + { -5.761029151e-03f, +9.996861593e-01f, +6.102094014e-03f, -1.316180471e-04f }, + { -5.877457176e-03f, +9.996729481e-01f, +6.232879398e-03f, -1.346245458e-04f }, + { -5.993739268e-03f, +9.996594646e-01f, +6.363814734e-03f, -1.376420846e-04f }, + { -6.109875472e-03f, +9.996457089e-01f, +6.494900059e-03f, -1.406706784e-04f }, + { -6.225865834e-03f, +9.996316809e-01f, +6.626135411e-03f, -1.437103420e-04f }, + { -6.341710400e-03f, +9.996173807e-01f, +6.757520824e-03f, -1.467610900e-04f }, + { -6.457409214e-03f, +9.996028083e-01f, +6.889056337e-03f, -1.498229373e-04f }, + { -6.572962323e-03f, +9.995879637e-01f, +7.020741983e-03f, -1.528958987e-04f }, + { -6.688369772e-03f, +9.995728468e-01f, +7.152577801e-03f, -1.559799888e-04f }, + { -6.803631606e-03f, +9.995574578e-01f, +7.284563826e-03f, -1.590752225e-04f }, + { -6.918747873e-03f, +9.995417966e-01f, +7.416700094e-03f, -1.621816145e-04f }, + { -7.033718618e-03f, +9.995258632e-01f, +7.548986640e-03f, -1.652991797e-04f }, + { -7.148543887e-03f, +9.995096577e-01f, +7.681423501e-03f, -1.684279326e-04f }, + { -7.263223725e-03f, +9.994931800e-01f, +7.814010713e-03f, -1.715678882e-04f }, + { -7.377758181e-03f, +9.994764302e-01f, +7.946748310e-03f, -1.747190612e-04f }, + { -7.492147298e-03f, +9.994594082e-01f, +8.079636328e-03f, -1.778814663e-04f }, + { -7.606391125e-03f, +9.994421141e-01f, +8.212674803e-03f, -1.810551183e-04f }, + { -7.720489707e-03f, +9.994245479e-01f, +8.345863769e-03f, -1.842400320e-04f }, + { -7.834443092e-03f, +9.994067096e-01f, +8.479203263e-03f, -1.874362221e-04f }, + { -7.948251325e-03f, +9.993885992e-01f, +8.612693320e-03f, -1.906437034e-04f }, + { -8.061914453e-03f, +9.993702168e-01f, +8.746333973e-03f, -1.938624906e-04f }, + { -8.175432524e-03f, +9.993515622e-01f, +8.880125258e-03f, -1.970925985e-04f }, + { -8.288805583e-03f, +9.993326357e-01f, +9.014067211e-03f, -2.003340419e-04f }, + { -8.402033679e-03f, +9.993134371e-01f, +9.148159865e-03f, -2.035868356e-04f }, + { -8.515116858e-03f, +9.992939664e-01f, +9.282403256e-03f, -2.068509942e-04f }, + { -8.628055168e-03f, +9.992742238e-01f, +9.416797418e-03f, -2.101265325e-04f }, + { -8.740848654e-03f, +9.992542091e-01f, +9.551342385e-03f, -2.134134654e-04f }, + { -8.853497366e-03f, +9.992339225e-01f, +9.686038192e-03f, -2.167118075e-04f }, + { -8.966001349e-03f, +9.992133639e-01f, +9.820884872e-03f, -2.200215735e-04f }, + { -9.078360653e-03f, +9.991925333e-01f, +9.955882461e-03f, -2.233427784e-04f }, + { -9.190575323e-03f, +9.991714307e-01f, +1.009103099e-02f, -2.266754367e-04f }, + { -9.302645409e-03f, +9.991500563e-01f, +1.022633050e-02f, -2.300195634e-04f }, + { -9.414570956e-03f, +9.991284099e-01f, +1.036178102e-02f, -2.333751730e-04f }, + { -9.526352014e-03f, +9.991064916e-01f, +1.049738258e-02f, -2.367422804e-04f }, + { -9.637988631e-03f, +9.990843014e-01f, +1.063313522e-02f, -2.401209002e-04f }, + { -9.749480853e-03f, +9.990618393e-01f, +1.076903897e-02f, -2.435110474e-04f }, + { -9.860828729e-03f, +9.990391053e-01f, +1.090509386e-02f, -2.469127365e-04f }, + { -9.972032308e-03f, +9.990160995e-01f, +1.104129994e-02f, -2.503259824e-04f }, + { -1.008309164e-02f, +9.989928219e-01f, +1.117765722e-02f, -2.537507998e-04f }, + { -1.019400677e-02f, +9.989692724e-01f, +1.131416575e-02f, -2.571872034e-04f }, + { -1.030477774e-02f, +9.989454512e-01f, +1.145082556e-02f, -2.606352080e-04f }, + { -1.041540461e-02f, +9.989213581e-01f, +1.158763668e-02f, -2.640948284e-04f }, + { -1.052588743e-02f, +9.988969933e-01f, +1.172459914e-02f, -2.675660791e-04f }, + { -1.063622623e-02f, +9.988723567e-01f, +1.186171298e-02f, -2.710489751e-04f }, + { -1.074642108e-02f, +9.988474483e-01f, +1.199897823e-02f, -2.745435310e-04f }, + { -1.085647202e-02f, +9.988222682e-01f, +1.213639492e-02f, -2.780497616e-04f }, + { -1.096637910e-02f, +9.987968164e-01f, +1.227396308e-02f, -2.815676816e-04f }, + { -1.107614236e-02f, +9.987710929e-01f, +1.241168275e-02f, -2.850973058e-04f }, + { -1.118576186e-02f, +9.987450978e-01f, +1.254955397e-02f, -2.886386488e-04f }, + { -1.129523765e-02f, +9.987188309e-01f, +1.268757675e-02f, -2.921917254e-04f }, + { -1.140456977e-02f, +9.986922924e-01f, +1.282575114e-02f, -2.957565503e-04f }, + { -1.151375828e-02f, +9.986654823e-01f, +1.296407716e-02f, -2.993331383e-04f }, + { -1.162280322e-02f, +9.986384006e-01f, +1.310255485e-02f, -3.029215041e-04f }, + { -1.173170465e-02f, +9.986110473e-01f, +1.324118424e-02f, -3.065216624e-04f }, + { -1.184046260e-02f, +9.985834223e-01f, +1.337996537e-02f, -3.101336280e-04f }, + { -1.194907714e-02f, +9.985555259e-01f, +1.351889825e-02f, -3.137574155e-04f }, + { -1.205754831e-02f, +9.985273578e-01f, +1.365798293e-02f, -3.173930397e-04f }, + { -1.216587616e-02f, +9.984989183e-01f, +1.379721944e-02f, -3.210405152e-04f }, + { -1.227406075e-02f, +9.984702072e-01f, +1.393660781e-02f, -3.246998569e-04f }, + { -1.238210211e-02f, +9.984412247e-01f, +1.407614806e-02f, -3.283710794e-04f }, + { -1.249000030e-02f, +9.984119707e-01f, +1.421584024e-02f, -3.320541975e-04f }, + { -1.259775538e-02f, +9.983824452e-01f, +1.435568436e-02f, -3.357492258e-04f }, + { -1.270536739e-02f, +9.983526483e-01f, +1.449568047e-02f, -3.394561791e-04f }, + { -1.281283638e-02f, +9.983225800e-01f, +1.463582860e-02f, -3.431750720e-04f }, + { -1.292016240e-02f, +9.982922403e-01f, +1.477612876e-02f, -3.469059193e-04f }, + { -1.302734550e-02f, +9.982616292e-01f, +1.491658101e-02f, -3.506487357e-04f }, + { -1.313438573e-02f, +9.982307467e-01f, +1.505718535e-02f, -3.544035359e-04f }, + { -1.324128315e-02f, +9.981995929e-01f, +1.519794184e-02f, -3.581703346e-04f }, + { -1.334803780e-02f, +9.981681678e-01f, +1.533885049e-02f, -3.619491465e-04f }, + { -1.345464973e-02f, +9.981364714e-01f, +1.547991134e-02f, -3.657399862e-04f }, + { -1.356111900e-02f, +9.981045038e-01f, +1.562112441e-02f, -3.695428686e-04f }, + { -1.366744566e-02f, +9.980722648e-01f, +1.576248975e-02f, -3.733578082e-04f }, + { -1.377362975e-02f, +9.980397546e-01f, +1.590400737e-02f, -3.771848197e-04f }, + { -1.387967133e-02f, +9.980069732e-01f, +1.604567730e-02f, -3.810239179e-04f }, + { -1.398557045e-02f, +9.979739207e-01f, +1.618749959e-02f, -3.848751175e-04f }, + { -1.409132716e-02f, +9.979405969e-01f, +1.632947425e-02f, -3.887384331e-04f }, + { -1.419694151e-02f, +9.979070020e-01f, +1.647160132e-02f, -3.926138794e-04f }, + { -1.430241355e-02f, +9.978731359e-01f, +1.661388082e-02f, -3.965014710e-04f }, + { -1.440774333e-02f, +9.978389988e-01f, +1.675631280e-02f, -4.004012227e-04f }, + { -1.451293091e-02f, +9.978045905e-01f, +1.689889726e-02f, -4.043131492e-04f }, + { -1.461797634e-02f, +9.977699112e-01f, +1.704163425e-02f, -4.082372651e-04f }, + { -1.472287966e-02f, +9.977349608e-01f, +1.718452380e-02f, -4.121735850e-04f }, + { -1.482764093e-02f, +9.976997395e-01f, +1.732756592e-02f, -4.161221238e-04f }, + { -1.493226021e-02f, +9.976642471e-01f, +1.747076066e-02f, -4.200828959e-04f }, + { -1.503673754e-02f, +9.976284837e-01f, +1.761410804e-02f, -4.240559161e-04f }, + { -1.514107297e-02f, +9.975924494e-01f, +1.775760809e-02f, -4.280411991e-04f }, + { -1.524526657e-02f, +9.975561442e-01f, +1.790126083e-02f, -4.320387594e-04f }, + { -1.534931837e-02f, +9.975195680e-01f, +1.804506631e-02f, -4.360486119e-04f }, + { -1.545322843e-02f, +9.974827210e-01f, +1.818902453e-02f, -4.400707710e-04f }, + { -1.555699680e-02f, +9.974456031e-01f, +1.833313554e-02f, -4.441052515e-04f }, + { -1.566062355e-02f, +9.974082143e-01f, +1.847739937e-02f, -4.481520680e-04f }, + { -1.576410871e-02f, +9.973705548e-01f, +1.862181603e-02f, -4.522112352e-04f }, + { -1.586745234e-02f, +9.973326244e-01f, +1.876638556e-02f, -4.562827677e-04f }, + { -1.597065449e-02f, +9.972944233e-01f, +1.891110799e-02f, -4.603666801e-04f }, + { -1.607371522e-02f, +9.972559515e-01f, +1.905598334e-02f, -4.644629872e-04f }, + { -1.617663458e-02f, +9.972172089e-01f, +1.920101164e-02f, -4.685717034e-04f }, + { -1.627941262e-02f, +9.971781956e-01f, +1.934619292e-02f, -4.726928435e-04f }, + { -1.638204939e-02f, +9.971389117e-01f, +1.949152721e-02f, -4.768264221e-04f }, + { -1.648454495e-02f, +9.970993571e-01f, +1.963701453e-02f, -4.809724538e-04f }, + { -1.658689935e-02f, +9.970595319e-01f, +1.978265492e-02f, -4.851309533e-04f }, + { -1.668911265e-02f, +9.970194362e-01f, +1.992844839e-02f, -4.893019351e-04f }, + { -1.679118489e-02f, +9.969790698e-01f, +2.007439498e-02f, -4.934854139e-04f }, + { -1.689311613e-02f, +9.969384329e-01f, +2.022049471e-02f, -4.976814042e-04f }, + { -1.699490642e-02f, +9.968975255e-01f, +2.036674762e-02f, -5.018899208e-04f }, + { -1.709655581e-02f, +9.968563476e-01f, +2.051315372e-02f, -5.061109782e-04f }, + { -1.719806437e-02f, +9.968148993e-01f, +2.065971304e-02f, -5.103445911e-04f }, + { -1.729943214e-02f, +9.967731805e-01f, +2.080642562e-02f, -5.145907739e-04f }, + { -1.740065918e-02f, +9.967311913e-01f, +2.095329147e-02f, -5.188495414e-04f }, + { -1.750174553e-02f, +9.966889317e-01f, +2.110031063e-02f, -5.231209082e-04f }, + { -1.760269126e-02f, +9.966464017e-01f, +2.124748312e-02f, -5.274048887e-04f }, + { -1.770349642e-02f, +9.966036014e-01f, +2.139480896e-02f, -5.317014977e-04f }, + { -1.780416106e-02f, +9.965605309e-01f, +2.154228819e-02f, -5.360107497e-04f }, + { -1.790468523e-02f, +9.965171900e-01f, +2.168992083e-02f, -5.403326592e-04f }, + { -1.800506899e-02f, +9.964735789e-01f, +2.183770690e-02f, -5.446672410e-04f }, + { -1.810531240e-02f, +9.964296976e-01f, +2.198564643e-02f, -5.490145094e-04f }, + { -1.820541550e-02f, +9.963855461e-01f, +2.213373945e-02f, -5.533744792e-04f }, + { -1.830537836e-02f, +9.963411244e-01f, +2.228198598e-02f, -5.577471650e-04f }, + { -1.840520102e-02f, +9.962964326e-01f, +2.243038605e-02f, -5.621325811e-04f }, + { -1.850488354e-02f, +9.962514707e-01f, +2.257893968e-02f, -5.665307423e-04f }, + { -1.860442598e-02f, +9.962062387e-01f, +2.272764690e-02f, -5.709416631e-04f }, + { -1.870382839e-02f, +9.961607366e-01f, +2.287650774e-02f, -5.753653581e-04f }, + { -1.880309082e-02f, +9.961149645e-01f, +2.302552221e-02f, -5.798018418e-04f }, + { -1.890221333e-02f, +9.960689225e-01f, +2.317469035e-02f, -5.842511287e-04f }, + { -1.900119597e-02f, +9.960226105e-01f, +2.332401218e-02f, -5.887132334e-04f }, + { -1.910003880e-02f, +9.959760285e-01f, +2.347348772e-02f, -5.931881705e-04f }, + { -1.919874188e-02f, +9.959291766e-01f, +2.362311700e-02f, -5.976759545e-04f }, + { -1.929730525e-02f, +9.958820549e-01f, +2.377290004e-02f, -6.021765999e-04f }, + { -1.939572898e-02f, +9.958346633e-01f, +2.392283688e-02f, -6.066901213e-04f }, + { -1.949401312e-02f, +9.957870019e-01f, +2.407292752e-02f, -6.112165332e-04f }, + { -1.959215772e-02f, +9.957390708e-01f, +2.422317200e-02f, -6.157558500e-04f }, + { -1.969016283e-02f, +9.956908698e-01f, +2.437357035e-02f, -6.203080865e-04f }, + { -1.978802853e-02f, +9.956423992e-01f, +2.452412258e-02f, -6.248732570e-04f }, + { -1.988575485e-02f, +9.955936589e-01f, +2.467482872e-02f, -6.294513760e-04f }, + { -1.998334185e-02f, +9.955446489e-01f, +2.482568879e-02f, -6.340424582e-04f }, + { -2.008078960e-02f, +9.954953692e-01f, +2.497670282e-02f, -6.386465180e-04f }, + { -2.017809815e-02f, +9.954458200e-01f, +2.512787083e-02f, -6.432635698e-04f }, + { -2.027526754e-02f, +9.953960012e-01f, +2.527919285e-02f, -6.478936283e-04f }, + { -2.037229785e-02f, +9.953459129e-01f, +2.543066889e-02f, -6.525367078e-04f }, + { -2.046918912e-02f, +9.952955551e-01f, +2.558229899e-02f, -6.571928229e-04f }, + { -2.056594140e-02f, +9.952449278e-01f, +2.573408316e-02f, -6.618619881e-04f }, + { -2.066255477e-02f, +9.951940310e-01f, +2.588602143e-02f, -6.665442179e-04f }, + { -2.075902926e-02f, +9.951428649e-01f, +2.603811383e-02f, -6.712395266e-04f }, + { -2.085536494e-02f, +9.950914294e-01f, +2.619036036e-02f, -6.759479289e-04f }, + { -2.095156187e-02f, +9.950397245e-01f, +2.634276107e-02f, -6.806694392e-04f }, + { -2.104762010e-02f, +9.949877504e-01f, +2.649531596e-02f, -6.854040719e-04f }, + { -2.114353968e-02f, +9.949355069e-01f, +2.664802507e-02f, -6.901518415e-04f }, + { -2.123932068e-02f, +9.948829943e-01f, +2.680088842e-02f, -6.949127625e-04f }, + { -2.133496314e-02f, +9.948302124e-01f, +2.695390602e-02f, -6.996868493e-04f }, + { -2.143046713e-02f, +9.947771613e-01f, +2.710707790e-02f, -7.044741164e-04f }, + { -2.152583271e-02f, +9.947238411e-01f, +2.726040409e-02f, -7.092745782e-04f }, + { -2.162105992e-02f, +9.946702518e-01f, +2.741388460e-02f, -7.140882492e-04f }, + { -2.171614883e-02f, +9.946163934e-01f, +2.756751946e-02f, -7.189151437e-04f }, + { -2.181109950e-02f, +9.945622660e-01f, +2.772130869e-02f, -7.237552763e-04f }, + { -2.190591197e-02f, +9.945078696e-01f, +2.787525232e-02f, -7.286086614e-04f }, + { -2.200058631e-02f, +9.944532042e-01f, +2.802935035e-02f, -7.334753133e-04f }, + { -2.209512257e-02f, +9.943982699e-01f, +2.818360282e-02f, -7.383552465e-04f }, + { -2.218952082e-02f, +9.943430666e-01f, +2.833800975e-02f, -7.432484754e-04f }, + { -2.228378110e-02f, +9.942875945e-01f, +2.849257115e-02f, -7.481550144e-04f }, + { -2.237790348e-02f, +9.942318536e-01f, +2.864728706e-02f, -7.530748780e-04f }, + { -2.247188802e-02f, +9.941758439e-01f, +2.880215748e-02f, -7.580080805e-04f }, + { -2.256573476e-02f, +9.941195654e-01f, +2.895718245e-02f, -7.629546363e-04f }, + { -2.265944377e-02f, +9.940630182e-01f, +2.911236198e-02f, -7.679145598e-04f }, + { -2.275301511e-02f, +9.940062023e-01f, +2.926769610e-02f, -7.728878654e-04f }, + { -2.284644883e-02f, +9.939491178e-01f, +2.942318481e-02f, -7.778745675e-04f }, + { -2.293974499e-02f, +9.938917647e-01f, +2.957882816e-02f, -7.828746805e-04f }, + { -2.303290364e-02f, +9.938341429e-01f, +2.973462615e-02f, -7.878882187e-04f }, + { -2.312592486e-02f, +9.937762527e-01f, +2.989057881e-02f, -7.929151965e-04f }, + { -2.321880869e-02f, +9.937180939e-01f, +3.004668616e-02f, -7.979556282e-04f }, + { -2.331155519e-02f, +9.936596666e-01f, +3.020294821e-02f, -8.030095283e-04f }, + { -2.340416442e-02f, +9.936009710e-01f, +3.035936500e-02f, -8.080769110e-04f }, + { -2.349663644e-02f, +9.935420069e-01f, +3.051593653e-02f, -8.131577908e-04f }, + { -2.358897131e-02f, +9.934827745e-01f, +3.067266283e-02f, -8.182521819e-04f }, + { -2.368116908e-02f, +9.934232738e-01f, +3.082954391e-02f, -8.233600987e-04f }, + { -2.377322981e-02f, +9.933635047e-01f, +3.098657981e-02f, -8.284815556e-04f }, + { -2.386515357e-02f, +9.933034675e-01f, +3.114377053e-02f, -8.336165668e-04f }, + { -2.395694040e-02f, +9.932431620e-01f, +3.130111610e-02f, -8.387651466e-04f }, + { -2.404859038e-02f, +9.931825884e-01f, +3.145861654e-02f, -8.439273095e-04f }, + { -2.414010355e-02f, +9.931217466e-01f, +3.161627187e-02f, -8.491030697e-04f }, + { -2.423147998e-02f, +9.930606368e-01f, +3.177408210e-02f, -8.542924415e-04f }, + { -2.432271972e-02f, +9.929992589e-01f, +3.193204725e-02f, -8.594954392e-04f }, + { -2.441382283e-02f, +9.929376130e-01f, +3.209016735e-02f, -8.647120771e-04f }, + { -2.450478938e-02f, +9.928756991e-01f, +3.224844242e-02f, -8.699423695e-04f }, + { -2.459561942e-02f, +9.928135173e-01f, +3.240687246e-02f, -8.751863308e-04f }, + { -2.468631300e-02f, +9.927510676e-01f, +3.256545750e-02f, -8.804439750e-04f }, + { -2.477687020e-02f, +9.926883501e-01f, +3.272419757e-02f, -8.857153167e-04f }, + { -2.486729107e-02f, +9.926253647e-01f, +3.288309267e-02f, -8.910003699e-04f }, + { -2.495757566e-02f, +9.925621116e-01f, +3.304214283e-02f, -8.962991490e-04f }, + { -2.504772404e-02f, +9.924985907e-01f, +3.320134807e-02f, -9.016116683e-04f }, + { -2.513773626e-02f, +9.924348021e-01f, +3.336070839e-02f, -9.069379419e-04f }, + { -2.522761239e-02f, +9.923707459e-01f, +3.352022383e-02f, -9.122779842e-04f }, + { -2.531735249e-02f, +9.923064221e-01f, +3.367989440e-02f, -9.176318093e-04f }, + { -2.540695661e-02f, +9.922418307e-01f, +3.383972011e-02f, -9.229994316e-04f }, + { -2.549642481e-02f, +9.921769718e-01f, +3.399970099e-02f, -9.283808652e-04f }, + { -2.558575716e-02f, +9.921118453e-01f, +3.415983706e-02f, -9.337761243e-04f }, + { -2.567495371e-02f, +9.920464515e-01f, +3.432012832e-02f, -9.391852233e-04f }, + { -2.576401452e-02f, +9.919807902e-01f, +3.448057480e-02f, -9.446081762e-04f }, + { -2.585293966e-02f, +9.919148616e-01f, +3.464117652e-02f, -9.500449974e-04f }, + { -2.594172918e-02f, +9.918486656e-01f, +3.480193349e-02f, -9.554957009e-04f }, + { -2.603038315e-02f, +9.917822024e-01f, +3.496284573e-02f, -9.609603011e-04f }, + { -2.611890161e-02f, +9.917154719e-01f, +3.512391325e-02f, -9.664388120e-04f }, + { -2.620728464e-02f, +9.916484743e-01f, +3.528513608e-02f, -9.719312480e-04f }, + { -2.629553230e-02f, +9.915812094e-01f, +3.544651423e-02f, -9.774376231e-04f }, + { -2.638364463e-02f, +9.915136775e-01f, +3.560804772e-02f, -9.829579515e-04f }, + { -2.647162171e-02f, +9.914458785e-01f, +3.576973656e-02f, -9.884922474e-04f }, + { -2.655946360e-02f, +9.913778125e-01f, +3.593158078e-02f, -9.940405249e-04f }, + { -2.664717035e-02f, +9.913094795e-01f, +3.609358038e-02f, -9.996027983e-04f }, + { -2.673474203e-02f, +9.912408796e-01f, +3.625573538e-02f, -1.005179082e-03f }, + { -2.682217869e-02f, +9.911720128e-01f, +3.641804581e-02f, -1.010769389e-03f }, + { -2.690948040e-02f, +9.911028791e-01f, +3.658051167e-02f, -1.016373735e-03f }, + { -2.699664722e-02f, +9.910334786e-01f, +3.674313298e-02f, -1.021992133e-03f }, + { -2.708367921e-02f, +9.909638114e-01f, +3.690590976e-02f, -1.027624597e-03f }, + { -2.717057642e-02f, +9.908938774e-01f, +3.706884203e-02f, -1.033271142e-03f }, + { -2.725733893e-02f, +9.908236768e-01f, +3.723192979e-02f, -1.038931782e-03f }, + { -2.734396678e-02f, +9.907532095e-01f, +3.739517307e-02f, -1.044606531e-03f }, + { -2.743046005e-02f, +9.906824756e-01f, +3.755857188e-02f, -1.050295402e-03f }, + { -2.751681879e-02f, +9.906114753e-01f, +3.772212623e-02f, -1.055998411e-03f }, + { -2.760304307e-02f, +9.905402084e-01f, +3.788583615e-02f, -1.061715570e-03f }, + { -2.768913294e-02f, +9.904686751e-01f, +3.804970164e-02f, -1.067446895e-03f }, + { -2.777508847e-02f, +9.903968753e-01f, +3.821372273e-02f, -1.073192399e-03f }, + { -2.786090972e-02f, +9.903248092e-01f, +3.837789942e-02f, -1.078952096e-03f }, + { -2.794659675e-02f, +9.902524768e-01f, +3.854223173e-02f, -1.084726001e-03f }, + { -2.803214962e-02f, +9.901798782e-01f, +3.870671968e-02f, -1.090514127e-03f }, + { -2.811756839e-02f, +9.901070133e-01f, +3.887136328e-02f, -1.096316489e-03f }, + { -2.820285313e-02f, +9.900338822e-01f, +3.903616254e-02f, -1.102133100e-03f }, + { -2.828800389e-02f, +9.899604850e-01f, +3.920111748e-02f, -1.107963974e-03f }, + { -2.837302075e-02f, +9.898868218e-01f, +3.936622812e-02f, -1.113809126e-03f }, + { -2.845790375e-02f, +9.898128925e-01f, +3.953149447e-02f, -1.119668570e-03f }, + { -2.854265296e-02f, +9.897386972e-01f, +3.969691653e-02f, -1.125542319e-03f }, + { -2.862726845e-02f, +9.896642360e-01f, +3.986249434e-02f, -1.131430388e-03f }, + { -2.871175028e-02f, +9.895895088e-01f, +4.002822789e-02f, -1.137332791e-03f }, + { -2.879609850e-02f, +9.895145159e-01f, +4.019411721e-02f, -1.143249541e-03f }, + { -2.888031318e-02f, +9.894392571e-01f, +4.036016230e-02f, -1.149180652e-03f }, + { -2.896439439e-02f, +9.893637326e-01f, +4.052636319e-02f, -1.155126140e-03f }, + { -2.904834218e-02f, +9.892879424e-01f, +4.069271988e-02f, -1.161086016e-03f }, + { -2.913215661e-02f, +9.892118865e-01f, +4.085923238e-02f, -1.167060297e-03f }, + { -2.921583776e-02f, +9.891355651e-01f, +4.102590072e-02f, -1.173048994e-03f }, + { -2.929938568e-02f, +9.890589780e-01f, +4.119272490e-02f, -1.179052123e-03f }, + { -2.938280043e-02f, +9.889821255e-01f, +4.135970494e-02f, -1.185069698e-03f }, + { -2.946608208e-02f, +9.889050075e-01f, +4.152684085e-02f, -1.191101731e-03f }, + { -2.954923069e-02f, +9.888276241e-01f, +4.169413264e-02f, -1.197148238e-03f }, + { -2.963224632e-02f, +9.887499753e-01f, +4.186158033e-02f, -1.203209232e-03f }, + { -2.971512904e-02f, +9.886720613e-01f, +4.202918393e-02f, -1.209284727e-03f }, + { -2.979787891e-02f, +9.885938819e-01f, +4.219694344e-02f, -1.215374737e-03f }, + { -2.988049599e-02f, +9.885154374e-01f, +4.236485889e-02f, -1.221479275e-03f }, + { -2.996298034e-02f, +9.884367276e-01f, +4.253293028e-02f, -1.227598357e-03f }, + { -3.004533202e-02f, +9.883577528e-01f, +4.270115763e-02f, -1.233731995e-03f }, + { -3.012755111e-02f, +9.882785129e-01f, +4.286954095e-02f, -1.239880203e-03f }, + { -3.020963766e-02f, +9.881990080e-01f, +4.303808025e-02f, -1.246042996e-03f }, + { -3.029159174e-02f, +9.881192381e-01f, +4.320677555e-02f, -1.252220388e-03f }, + { -3.037341341e-02f, +9.880392034e-01f, +4.337562684e-02f, -1.258412391e-03f }, + { -3.045510273e-02f, +9.879589037e-01f, +4.354463416e-02f, -1.264619020e-03f }, + { -3.053665977e-02f, +9.878783393e-01f, +4.371379750e-02f, -1.270840289e-03f }, + { -3.061808459e-02f, +9.877975101e-01f, +4.388311688e-02f, -1.277076211e-03f }, + { -3.069937725e-02f, +9.877164161e-01f, +4.405259231e-02f, -1.283326801e-03f }, + { -3.078053782e-02f, +9.876350576e-01f, +4.422222380e-02f, -1.289592072e-03f }, + { -3.086156636e-02f, +9.875534344e-01f, +4.439201136e-02f, -1.295872038e-03f }, + { -3.094246293e-02f, +9.874715467e-01f, +4.456195501e-02f, -1.302166714e-03f }, + { -3.102322761e-02f, +9.873893944e-01f, +4.473205475e-02f, -1.308476111e-03f }, + { -3.110386044e-02f, +9.873069778e-01f, +4.490231060e-02f, -1.314800245e-03f }, + { -3.118436150e-02f, +9.872242967e-01f, +4.507272256e-02f, -1.321139130e-03f }, + { -3.126473085e-02f, +9.871413513e-01f, +4.524329065e-02f, -1.327492778e-03f }, + { -3.134496856e-02f, +9.870581415e-01f, +4.541401487e-02f, -1.333861204e-03f }, + { -3.142507468e-02f, +9.869746676e-01f, +4.558489524e-02f, -1.340244422e-03f }, + { -3.150504929e-02f, +9.868909295e-01f, +4.575593177e-02f, -1.346642444e-03f }, + { -3.158489244e-02f, +9.868069272e-01f, +4.592712446e-02f, -1.353055286e-03f }, + { -3.166460421e-02f, +9.867226608e-01f, +4.609847333e-02f, -1.359482960e-03f }, + { -3.174418465e-02f, +9.866381305e-01f, +4.626997838e-02f, -1.365925481e-03f }, + { -3.182363382e-02f, +9.865533361e-01f, +4.644163964e-02f, -1.372382862e-03f }, + { -3.190295181e-02f, +9.864682779e-01f, +4.661345709e-02f, -1.378855117e-03f }, + { -3.198213866e-02f, +9.863829557e-01f, +4.678543077e-02f, -1.385342260e-03f }, + { -3.206119444e-02f, +9.862973698e-01f, +4.695756066e-02f, -1.391844303e-03f }, + { -3.214011922e-02f, +9.862115201e-01f, +4.712984679e-02f, -1.398361262e-03f }, + { -3.221891307e-02f, +9.861254067e-01f, +4.730228917e-02f, -1.404893149e-03f }, + { -3.229757604e-02f, +9.860390297e-01f, +4.747488779e-02f, -1.411439979e-03f }, + { -3.237610820e-02f, +9.859523890e-01f, +4.764764268e-02f, -1.418001764e-03f }, + { -3.245450962e-02f, +9.858654848e-01f, +4.782055384e-02f, -1.424578519e-03f }, + { -3.253278036e-02f, +9.857783172e-01f, +4.799362127e-02f, -1.431170257e-03f }, + { -3.261092049e-02f, +9.856908861e-01f, +4.816684499e-02f, -1.437776992e-03f }, + { -3.268893007e-02f, +9.856031917e-01f, +4.834022501e-02f, -1.444398738e-03f }, + { -3.276680917e-02f, +9.855152339e-01f, +4.851376133e-02f, -1.451035507e-03f }, + { -3.284455785e-02f, +9.854270129e-01f, +4.868745396e-02f, -1.457687314e-03f }, + { -3.292217617e-02f, +9.853385286e-01f, +4.886130292e-02f, -1.464354173e-03f }, + { -3.299966421e-02f, +9.852497812e-01f, +4.903530820e-02f, -1.471036096e-03f }, + { -3.307702203e-02f, +9.851607708e-01f, +4.920946982e-02f, -1.477733098e-03f }, + { -3.315424969e-02f, +9.850714973e-01f, +4.938378778e-02f, -1.484445192e-03f }, + { -3.323134726e-02f, +9.849819608e-01f, +4.955826209e-02f, -1.491172391e-03f }, + { -3.330831480e-02f, +9.848921614e-01f, +4.973289276e-02f, -1.497914710e-03f }, + { -3.338515239e-02f, +9.848020991e-01f, +4.990767980e-02f, -1.504672161e-03f }, + { -3.346186007e-02f, +9.847117740e-01f, +5.008262322e-02f, -1.511444759e-03f }, + { -3.353843793e-02f, +9.846211862e-01f, +5.025772301e-02f, -1.518232516e-03f }, + { -3.361488603e-02f, +9.845303356e-01f, +5.043297919e-02f, -1.525035446e-03f }, + { -3.369120443e-02f, +9.844392225e-01f, +5.060839177e-02f, -1.531853564e-03f }, + { -3.376739320e-02f, +9.843478467e-01f, +5.078396076e-02f, -1.538686881e-03f }, + { -3.384345240e-02f, +9.842562085e-01f, +5.095968615e-02f, -1.545535412e-03f }, + { -3.391938210e-02f, +9.841643077e-01f, +5.113556795e-02f, -1.552399171e-03f }, + { -3.399518237e-02f, +9.840721446e-01f, +5.131160618e-02f, -1.559278170e-03f }, + { -3.407085327e-02f, +9.839797191e-01f, +5.148780084e-02f, -1.566172424e-03f }, + { -3.414639488e-02f, +9.838870314e-01f, +5.166415193e-02f, -1.573081945e-03f }, + { -3.422180724e-02f, +9.837940814e-01f, +5.184065947e-02f, -1.580006747e-03f }, + { -3.429709044e-02f, +9.837008692e-01f, +5.201732345e-02f, -1.586946844e-03f }, + { -3.437224453e-02f, +9.836073950e-01f, +5.219414389e-02f, -1.593902249e-03f }, + { -3.444726959e-02f, +9.835136587e-01f, +5.237112079e-02f, -1.600872975e-03f }, + { -3.452216568e-02f, +9.834196603e-01f, +5.254825415e-02f, -1.607859036e-03f }, + { -3.459693287e-02f, +9.833254001e-01f, +5.272554398e-02f, -1.614860445e-03f }, + { -3.467157122e-02f, +9.832308780e-01f, +5.290299029e-02f, -1.621877216e-03f }, + { -3.474608080e-02f, +9.831360941e-01f, +5.308059308e-02f, -1.628909362e-03f }, + { -3.482046167e-02f, +9.830410484e-01f, +5.325835236e-02f, -1.635956896e-03f }, + { -3.489471391e-02f, +9.829457410e-01f, +5.343626813e-02f, -1.643019832e-03f }, + { -3.496883758e-02f, +9.828501720e-01f, +5.361434040e-02f, -1.650098183e-03f }, + { -3.504283275e-02f, +9.827543414e-01f, +5.379256918e-02f, -1.657191962e-03f }, + { -3.511669948e-02f, +9.826582494e-01f, +5.397095446e-02f, -1.664301183e-03f }, + { -3.519043784e-02f, +9.825618958e-01f, +5.414949625e-02f, -1.671425859e-03f }, + { -3.526404790e-02f, +9.824652809e-01f, +5.432819456e-02f, -1.678566004e-03f }, + { -3.533752973e-02f, +9.823684047e-01f, +5.450704939e-02f, -1.685721630e-03f }, + { -3.541088338e-02f, +9.822712671e-01f, +5.468606075e-02f, -1.692892751e-03f }, + { -3.548410894e-02f, +9.821738684e-01f, +5.486522863e-02f, -1.700079381e-03f }, + { -3.555720646e-02f, +9.820762086e-01f, +5.504455306e-02f, -1.707281532e-03f }, + { -3.563017602e-02f, +9.819782876e-01f, +5.522403402e-02f, -1.714499218e-03f }, + { -3.570301768e-02f, +9.818801056e-01f, +5.540367152e-02f, -1.721732452e-03f }, + { -3.577573150e-02f, +9.817816627e-01f, +5.558346557e-02f, -1.728981247e-03f }, + { -3.584831757e-02f, +9.816829589e-01f, +5.576341617e-02f, -1.736245617e-03f }, + { -3.592077593e-02f, +9.815839943e-01f, +5.594352333e-02f, -1.743525575e-03f }, + { -3.599310667e-02f, +9.814847688e-01f, +5.612378704e-02f, -1.750821133e-03f }, + { -3.606530984e-02f, +9.813852827e-01f, +5.630420731e-02f, -1.758132306e-03f }, + { -3.613738552e-02f, +9.812855360e-01f, +5.648478415e-02f, -1.765459107e-03f }, + { -3.620933378e-02f, +9.811855286e-01f, +5.666551755e-02f, -1.772801548e-03f }, + { -3.628115468e-02f, +9.810852607e-01f, +5.684640752e-02f, -1.780159642e-03f }, + { -3.635284829e-02f, +9.809847324e-01f, +5.702745407e-02f, -1.787533404e-03f }, + { -3.642441467e-02f, +9.808839437e-01f, +5.720865720e-02f, -1.794922846e-03f }, + { -3.649585390e-02f, +9.807828947e-01f, +5.739001690e-02f, -1.802327981e-03f }, + { -3.656716604e-02f, +9.806815854e-01f, +5.757153318e-02f, -1.809748823e-03f }, + { -3.663835117e-02f, +9.805800159e-01f, +5.775320605e-02f, -1.817185384e-03f }, + { -3.670940934e-02f, +9.804781863e-01f, +5.793503550e-02f, -1.824637677e-03f }, + { -3.678034064e-02f, +9.803760966e-01f, +5.811702155e-02f, -1.832105717e-03f }, + { -3.685114512e-02f, +9.802737469e-01f, +5.829916418e-02f, -1.839589515e-03f }, + { -3.692182285e-02f, +9.801711372e-01f, +5.848146341e-02f, -1.847089085e-03f }, + { -3.699237391e-02f, +9.800682677e-01f, +5.866391923e-02f, -1.854604440e-03f }, + { -3.706279835e-02f, +9.799651384e-01f, +5.884653165e-02f, -1.862135594e-03f }, + { -3.713309626e-02f, +9.798617493e-01f, +5.902930066e-02f, -1.869682558e-03f }, + { -3.720326769e-02f, +9.797581006e-01f, +5.921222628e-02f, -1.877245347e-03f }, + { -3.727331272e-02f, +9.796541922e-01f, +5.939530849e-02f, -1.884823973e-03f }, + { -3.734323142e-02f, +9.795500243e-01f, +5.957854731e-02f, -1.892418449e-03f }, + { -3.741302385e-02f, +9.794455969e-01f, +5.976194274e-02f, -1.900028788e-03f }, + { -3.748269008e-02f, +9.793409101e-01f, +5.994549476e-02f, -1.907655004e-03f }, + { -3.755223018e-02f, +9.792359640e-01f, +6.012920340e-02f, -1.915297108e-03f }, + { -3.762164423e-02f, +9.791307585e-01f, +6.031306864e-02f, -1.922955116e-03f }, + { -3.769093228e-02f, +9.790252939e-01f, +6.049709048e-02f, -1.930629038e-03f }, + { -3.776009441e-02f, +9.789195701e-01f, +6.068126894e-02f, -1.938318888e-03f }, + { -3.782913069e-02f, +9.788135872e-01f, +6.086560401e-02f, -1.946024680e-03f }, + { -3.789804118e-02f, +9.787073453e-01f, +6.105009568e-02f, -1.953746425e-03f }, + { -3.796682595e-02f, +9.786008444e-01f, +6.123474396e-02f, -1.961484138e-03f }, + { -3.803548508e-02f, +9.784940847e-01f, +6.141954886e-02f, -1.969237830e-03f }, + { -3.810401864e-02f, +9.783870661e-01f, +6.160451036e-02f, -1.977007515e-03f }, + { -3.817242668e-02f, +9.782797888e-01f, +6.178962847e-02f, -1.984793206e-03f }, + { -3.824070929e-02f, +9.781722528e-01f, +6.197490319e-02f, -1.992594915e-03f }, + { -3.830886653e-02f, +9.780644583e-01f, +6.216033452e-02f, -2.000412656e-03f }, + { -3.837689847e-02f, +9.779564051e-01f, +6.234592246e-02f, -2.008246441e-03f }, + { -3.844480518e-02f, +9.778480935e-01f, +6.253166701e-02f, -2.016096283e-03f }, + { -3.851258673e-02f, +9.777395235e-01f, +6.271756817e-02f, -2.023962196e-03f }, + { -3.858024318e-02f, +9.776306952e-01f, +6.290362593e-02f, -2.031844191e-03f }, + { -3.864777462e-02f, +9.775216086e-01f, +6.308984030e-02f, -2.039742281e-03f }, + { -3.871518110e-02f, +9.774122638e-01f, +6.327621127e-02f, -2.047656480e-03f }, + { -3.878246270e-02f, +9.773026608e-01f, +6.346273885e-02f, -2.055586801e-03f }, + { -3.884961949e-02f, +9.771927998e-01f, +6.364942303e-02f, -2.063533255e-03f }, + { -3.891665153e-02f, +9.770826809e-01f, +6.383626381e-02f, -2.071495856e-03f }, + { -3.898355890e-02f, +9.769723040e-01f, +6.402326120e-02f, -2.079474617e-03f }, + { -3.905034167e-02f, +9.768616692e-01f, +6.421041518e-02f, -2.087469549e-03f }, + { -3.911699991e-02f, +9.767507766e-01f, +6.439772576e-02f, -2.095480667e-03f }, + { -3.918353368e-02f, +9.766396264e-01f, +6.458519293e-02f, -2.103507983e-03f }, + { -3.924994306e-02f, +9.765282185e-01f, +6.477281670e-02f, -2.111551509e-03f }, + { -3.931622812e-02f, +9.764165530e-01f, +6.496059705e-02f, -2.119611258e-03f }, + { -3.938238892e-02f, +9.763046301e-01f, +6.514853400e-02f, -2.127687243e-03f }, + { -3.944842554e-02f, +9.761924497e-01f, +6.533662753e-02f, -2.135779477e-03f }, + { -3.951433805e-02f, +9.760800119e-01f, +6.552487765e-02f, -2.143887971e-03f }, + { -3.958012651e-02f, +9.759673169e-01f, +6.571328435e-02f, -2.152012740e-03f }, + { -3.964579101e-02f, +9.758543646e-01f, +6.590184763e-02f, -2.160153795e-03f }, + { -3.971133160e-02f, +9.757411552e-01f, +6.609056749e-02f, -2.168311149e-03f }, + { -3.977674836e-02f, +9.756276888e-01f, +6.627944392e-02f, -2.176484815e-03f }, + { -3.984204137e-02f, +9.755139653e-01f, +6.646847692e-02f, -2.184674805e-03f }, + { -3.990721068e-02f, +9.753999849e-01f, +6.665766648e-02f, -2.192881133e-03f }, + { -3.997225637e-02f, +9.752857476e-01f, +6.684701262e-02f, -2.201103809e-03f }, + { -4.003717851e-02f, +9.751712536e-01f, +6.703651531e-02f, -2.209342848e-03f }, + { -4.010197718e-02f, +9.750565028e-01f, +6.722617456e-02f, -2.217598262e-03f }, + { -4.016665244e-02f, +9.749414954e-01f, +6.741599037e-02f, -2.225870062e-03f }, + { -4.023120436e-02f, +9.748262314e-01f, +6.760596272e-02f, -2.234158263e-03f }, + { -4.029563302e-02f, +9.747107110e-01f, +6.779609163e-02f, -2.242462875e-03f }, + { -4.035993848e-02f, +9.745949341e-01f, +6.798637707e-02f, -2.250783913e-03f }, + { -4.042412082e-02f, +9.744789009e-01f, +6.817681906e-02f, -2.259121387e-03f }, + { -4.048818011e-02f, +9.743626113e-01f, +6.836741758e-02f, -2.267475312e-03f }, + { -4.055211641e-02f, +9.742460656e-01f, +6.855817263e-02f, -2.275845698e-03f }, + { -4.061592981e-02f, +9.741292638e-01f, +6.874908421e-02f, -2.284232560e-03f }, + { -4.067962036e-02f, +9.740122059e-01f, +6.894015231e-02f, -2.292635908e-03f }, + { -4.074318815e-02f, +9.738948920e-01f, +6.913137692e-02f, -2.301055756e-03f }, + { -4.080663324e-02f, +9.737773222e-01f, +6.932275805e-02f, -2.309492116e-03f }, + { -4.086995570e-02f, +9.736594966e-01f, +6.951429569e-02f, -2.317945001e-03f }, + { -4.093315561e-02f, +9.735414153e-01f, +6.970598983e-02f, -2.326414422e-03f }, + { -4.099623304e-02f, +9.734230782e-01f, +6.989784046e-02f, -2.334900392e-03f }, + { -4.105918805e-02f, +9.733044855e-01f, +7.008984759e-02f, -2.343402924e-03f }, + { -4.112202073e-02f, +9.731856373e-01f, +7.028201121e-02f, -2.351922030e-03f }, + { -4.118473113e-02f, +9.730665337e-01f, +7.047433131e-02f, -2.360457723e-03f }, + { -4.124731934e-02f, +9.729471746e-01f, +7.066680788e-02f, -2.369010014e-03f }, + { -4.130978543e-02f, +9.728275603e-01f, +7.085944093e-02f, -2.377578915e-03f }, + { -4.137212946e-02f, +9.727076907e-01f, +7.105223044e-02f, -2.386164441e-03f }, + { -4.143435151e-02f, +9.725875660e-01f, +7.124517640e-02f, -2.394766601e-03f }, + { -4.149645164e-02f, +9.724671862e-01f, +7.143827882e-02f, -2.403385410e-03f }, + { -4.155842994e-02f, +9.723465513e-01f, +7.163153769e-02f, -2.412020878e-03f }, + { -4.162028648e-02f, +9.722256616e-01f, +7.182495300e-02f, -2.420673020e-03f }, + { -4.168202131e-02f, +9.721045170e-01f, +7.201852474e-02f, -2.429341845e-03f }, + { -4.174363453e-02f, +9.719831176e-01f, +7.221225291e-02f, -2.438027368e-03f }, + { -4.180512620e-02f, +9.718614635e-01f, +7.240613750e-02f, -2.446729599e-03f }, + { -4.186649638e-02f, +9.717395548e-01f, +7.260017851e-02f, -2.455448552e-03f }, + { -4.192774516e-02f, +9.716173916e-01f, +7.279437592e-02f, -2.464184239e-03f }, + { -4.198887261e-02f, +9.714949738e-01f, +7.298872973e-02f, -2.472936671e-03f }, + { -4.204987879e-02f, +9.713723017e-01f, +7.318323994e-02f, -2.481705861e-03f }, + { -4.211076378e-02f, +9.712493753e-01f, +7.337790653e-02f, -2.490491821e-03f }, + { -4.217152766e-02f, +9.711261947e-01f, +7.357272950e-02f, -2.499294563e-03f }, + { -4.223217049e-02f, +9.710027598e-01f, +7.376770885e-02f, -2.508114099e-03f }, + { -4.229269235e-02f, +9.708790709e-01f, +7.396284455e-02f, -2.516950442e-03f }, + { -4.235309331e-02f, +9.707551280e-01f, +7.415813662e-02f, -2.525803603e-03f }, + { -4.241337343e-02f, +9.706309312e-01f, +7.435358503e-02f, -2.534673595e-03f }, + { -4.247353281e-02f, +9.705064805e-01f, +7.454918978e-02f, -2.543560430e-03f }, + { -4.253357150e-02f, +9.703817761e-01f, +7.474495086e-02f, -2.552464119e-03f }, + { -4.259348958e-02f, +9.702568180e-01f, +7.494086827e-02f, -2.561384675e-03f }, + { -4.265328712e-02f, +9.701316062e-01f, +7.513694200e-02f, -2.570322110e-03f }, + { -4.271296420e-02f, +9.700061410e-01f, +7.533317203e-02f, -2.579276435e-03f }, + { -4.277252088e-02f, +9.698804222e-01f, +7.552955836e-02f, -2.588247664e-03f }, + { -4.283195724e-02f, +9.697544501e-01f, +7.572610098e-02f, -2.597235807e-03f }, + { -4.289127336e-02f, +9.696282248e-01f, +7.592279989e-02f, -2.606240877e-03f }, + { -4.295046931e-02f, +9.695017462e-01f, +7.611965506e-02f, -2.615262886e-03f }, + { -4.300954515e-02f, +9.693750144e-01f, +7.631666650e-02f, -2.624301846e-03f }, + { -4.306850096e-02f, +9.692480296e-01f, +7.651383420e-02f, -2.633357769e-03f }, + { -4.312733682e-02f, +9.691207919e-01f, +7.671115814e-02f, -2.642430666e-03f }, + { -4.318605280e-02f, +9.689933012e-01f, +7.690863832e-02f, -2.651520549e-03f }, + { -4.324464897e-02f, +9.688655578e-01f, +7.710627472e-02f, -2.660627431e-03f }, + { -4.330312541e-02f, +9.687375615e-01f, +7.730406734e-02f, -2.669751324e-03f }, + { -4.336148218e-02f, +9.686093127e-01f, +7.750201617e-02f, -2.678892238e-03f }, + { -4.341971936e-02f, +9.684808113e-01f, +7.770012120e-02f, -2.688050187e-03f }, + { -4.347783703e-02f, +9.683520574e-01f, +7.789838241e-02f, -2.697225181e-03f }, + { -4.353583525e-02f, +9.682230510e-01f, +7.809679980e-02f, -2.706417234e-03f }, + { -4.359371410e-02f, +9.680937924e-01f, +7.829537336e-02f, -2.715626355e-03f }, + { -4.365147366e-02f, +9.679642815e-01f, +7.849410308e-02f, -2.724852558e-03f }, + { -4.370911400e-02f, +9.678345184e-01f, +7.869298894e-02f, -2.734095855e-03f }, + { -4.376663518e-02f, +9.677045033e-01f, +7.889203094e-02f, -2.743356256e-03f }, + { -4.382403729e-02f, +9.675742361e-01f, +7.909122907e-02f, -2.752633774e-03f }, + { -4.388132040e-02f, +9.674437171e-01f, +7.929058330e-02f, -2.761928420e-03f }, + { -4.393848458e-02f, +9.673129462e-01f, +7.949009365e-02f, -2.771240206e-03f }, + { -4.399552991e-02f, +9.671819235e-01f, +7.968976008e-02f, -2.780569145e-03f }, + { -4.405245646e-02f, +9.670506492e-01f, +7.988958260e-02f, -2.789915247e-03f }, + { -4.410926430e-02f, +9.669191233e-01f, +8.008956119e-02f, -2.799278524e-03f }, + { -4.416595350e-02f, +9.667873459e-01f, +8.028969584e-02f, -2.808658988e-03f }, + { -4.422252415e-02f, +9.666553170e-01f, +8.048998653e-02f, -2.818056650e-03f }, + { -4.427897631e-02f, +9.665230369e-01f, +8.069043326e-02f, -2.827471523e-03f }, + { -4.433531006e-02f, +9.663905054e-01f, +8.089103602e-02f, -2.836903618e-03f }, + { -4.439152547e-02f, +9.662577228e-01f, +8.109179479e-02f, -2.846352946e-03f }, + { -4.444762262e-02f, +9.661246891e-01f, +8.129270955e-02f, -2.855819519e-03f }, + { -4.450360157e-02f, +9.659914044e-01f, +8.149378031e-02f, -2.865303349e-03f }, + { -4.455946242e-02f, +9.658578688e-01f, +8.169500704e-02f, -2.874804447e-03f }, + { -4.461520522e-02f, +9.657240824e-01f, +8.189638974e-02f, -2.884322825e-03f }, + { -4.467083005e-02f, +9.655900451e-01f, +8.209792838e-02f, -2.893858495e-03f }, + { -4.472633699e-02f, +9.654557573e-01f, +8.229962297e-02f, -2.903411467e-03f }, + { -4.478172612e-02f, +9.653212188e-01f, +8.250147348e-02f, -2.912981754e-03f }, + { -4.483699749e-02f, +9.651864298e-01f, +8.270347990e-02f, -2.922569366e-03f }, + { -4.489215120e-02f, +9.650513905e-01f, +8.290564223e-02f, -2.932174316e-03f }, + { -4.494718732e-02f, +9.649161008e-01f, +8.310796044e-02f, -2.941796615e-03f }, + { -4.500210591e-02f, +9.647805608e-01f, +8.331043452e-02f, -2.951436274e-03f }, + { -4.505690705e-02f, +9.646447707e-01f, +8.351306447e-02f, -2.961093304e-03f }, + { -4.511159083e-02f, +9.645087305e-01f, +8.371585026e-02f, -2.970767718e-03f }, + { -4.516615730e-02f, +9.643724404e-01f, +8.391879188e-02f, -2.980459527e-03f }, + { -4.522060655e-02f, +9.642359003e-01f, +8.412188933e-02f, -2.990168741e-03f }, + { -4.527493866e-02f, +9.640991104e-01f, +8.432514258e-02f, -2.999895373e-03f }, + { -4.532915369e-02f, +9.639620708e-01f, +8.452855162e-02f, -3.009639433e-03f }, + { -4.538325172e-02f, +9.638247816e-01f, +8.473211644e-02f, -3.019400934e-03f }, + { -4.543723283e-02f, +9.636872427e-01f, +8.493583703e-02f, -3.029179886e-03f }, + { -4.549109708e-02f, +9.635494545e-01f, +8.513971336e-02f, -3.038976300e-03f }, + { -4.554484457e-02f, +9.634114168e-01f, +8.534374543e-02f, -3.048790189e-03f }, + { -4.559847535e-02f, +9.632731298e-01f, +8.554793322e-02f, -3.058621563e-03f }, + { -4.565198951e-02f, +9.631345937e-01f, +8.575227672e-02f, -3.068470433e-03f }, + { -4.570538712e-02f, +9.629958084e-01f, +8.595677591e-02f, -3.078336812e-03f }, + { -4.575866826e-02f, +9.628567741e-01f, +8.616143077e-02f, -3.088220709e-03f }, + { -4.581183299e-02f, +9.627174908e-01f, +8.636624129e-02f, -3.098122137e-03f }, + { -4.586488140e-02f, +9.625779587e-01f, +8.657120747e-02f, -3.108041106e-03f }, + { -4.591781356e-02f, +9.624381778e-01f, +8.677632927e-02f, -3.117977628e-03f }, + { -4.597062955e-02f, +9.622981482e-01f, +8.698160668e-02f, -3.127931713e-03f }, + { -4.602332944e-02f, +9.621578700e-01f, +8.718703970e-02f, -3.137903374e-03f }, + { -4.607591330e-02f, +9.620173433e-01f, +8.739262830e-02f, -3.147892621e-03f }, + { -4.612838122e-02f, +9.618765682e-01f, +8.759837247e-02f, -3.157899465e-03f }, + { -4.618073326e-02f, +9.617355447e-01f, +8.780427220e-02f, -3.167923918e-03f }, + { -4.623296951e-02f, +9.615942731e-01f, +8.801032746e-02f, -3.177965990e-03f }, + { -4.628509003e-02f, +9.614527532e-01f, +8.821653824e-02f, -3.188025693e-03f }, + { -4.633709491e-02f, +9.613109853e-01f, +8.842290452e-02f, -3.198103037e-03f }, + { -4.638898421e-02f, +9.611689695e-01f, +8.862942629e-02f, -3.208198035e-03f }, + { -4.644075802e-02f, +9.610267057e-01f, +8.883610354e-02f, -3.218310696e-03f }, + { -4.649241641e-02f, +9.608841941e-01f, +8.904293624e-02f, -3.228441031e-03f }, + { -4.654395945e-02f, +9.607414349e-01f, +8.924992437e-02f, -3.238589053e-03f }, + { -4.659538723e-02f, +9.605984280e-01f, +8.945706793e-02f, -3.248754771e-03f }, + { -4.664669981e-02f, +9.604551736e-01f, +8.966436689e-02f, -3.258938197e-03f }, + { -4.669789727e-02f, +9.603116718e-01f, +8.987182124e-02f, -3.269139342e-03f }, + { -4.674897969e-02f, +9.601679226e-01f, +9.007943096e-02f, -3.279358217e-03f }, + { -4.679994715e-02f, +9.600239261e-01f, +9.028719604e-02f, -3.289594832e-03f }, + { -4.685079971e-02f, +9.598796825e-01f, +9.049511645e-02f, -3.299849199e-03f }, + { -4.690153746e-02f, +9.597351919e-01f, +9.070319217e-02f, -3.310121328e-03f }, + { -4.695216048e-02f, +9.595904542e-01f, +9.091142320e-02f, -3.320411230e-03f }, + { -4.700266883e-02f, +9.594454696e-01f, +9.111980950e-02f, -3.330718916e-03f }, + { -4.705306259e-02f, +9.593002383e-01f, +9.132835108e-02f, -3.341044398e-03f }, + { -4.710334184e-02f, +9.591547602e-01f, +9.153704790e-02f, -3.351387685e-03f }, + { -4.715350666e-02f, +9.590090355e-01f, +9.174589994e-02f, -3.361748789e-03f }, + { -4.720355712e-02f, +9.588630643e-01f, +9.195490720e-02f, -3.372127720e-03f }, + { -4.725349330e-02f, +9.587168467e-01f, +9.216406964e-02f, -3.382524489e-03f }, + { -4.730331527e-02f, +9.585703827e-01f, +9.237338726e-02f, -3.392939107e-03f }, + { -4.735302311e-02f, +9.584236724e-01f, +9.258286004e-02f, -3.403371585e-03f }, + { -4.740261690e-02f, +9.582767160e-01f, +9.279248795e-02f, -3.413821934e-03f }, + { -4.745209672e-02f, +9.581295136e-01f, +9.300227097e-02f, -3.424290163e-03f }, + { -4.750146263e-02f, +9.579820651e-01f, +9.321220909e-02f, -3.434776284e-03f }, + { -4.755071471e-02f, +9.578343708e-01f, +9.342230229e-02f, -3.445280308e-03f }, + { -4.759985305e-02f, +9.576864307e-01f, +9.363255055e-02f, -3.455802245e-03f }, + { -4.764887772e-02f, +9.575382449e-01f, +9.384295385e-02f, -3.466342106e-03f }, + { -4.769778879e-02f, +9.573898135e-01f, +9.405351217e-02f, -3.476899901e-03f }, + { -4.774658634e-02f, +9.572411365e-01f, +9.426422548e-02f, -3.487475641e-03f }, + { -4.779527045e-02f, +9.570922142e-01f, +9.447509378e-02f, -3.498069337e-03f }, + { -4.784384120e-02f, +9.569430465e-01f, +9.468611704e-02f, -3.508680999e-03f }, + { -4.789229866e-02f, +9.567936336e-01f, +9.489729524e-02f, -3.519310638e-03f }, + { -4.794064290e-02f, +9.566439756e-01f, +9.510862835e-02f, -3.529958264e-03f }, + { -4.798887401e-02f, +9.564940726e-01f, +9.532011637e-02f, -3.540623888e-03f }, + { -4.803699206e-02f, +9.563439245e-01f, +9.553175927e-02f, -3.551307520e-03f }, + { -4.808499713e-02f, +9.561935317e-01f, +9.574355703e-02f, -3.562009171e-03f }, + { -4.813288929e-02f, +9.560428941e-01f, +9.595550962e-02f, -3.572728851e-03f }, + { -4.818066862e-02f, +9.558920118e-01f, +9.616761703e-02f, -3.583466571e-03f }, + { -4.822833521e-02f, +9.557408849e-01f, +9.637987924e-02f, -3.594222342e-03f }, + { -4.827588911e-02f, +9.555895136e-01f, +9.659229622e-02f, -3.604996173e-03f }, + { -4.832333042e-02f, +9.554378979e-01f, +9.680486796e-02f, -3.615788075e-03f }, + { -4.837065921e-02f, +9.552860379e-01f, +9.701759443e-02f, -3.626598058e-03f }, + { -4.841787556e-02f, +9.551339337e-01f, +9.723047561e-02f, -3.637426133e-03f }, + { -4.846497954e-02f, +9.549815854e-01f, +9.744351149e-02f, -3.648272311e-03f }, + { -4.851197123e-02f, +9.548289931e-01f, +9.765670203e-02f, -3.659136601e-03f }, + { -4.855885071e-02f, +9.546761570e-01f, +9.787004721e-02f, -3.670019013e-03f }, + { -4.860561805e-02f, +9.545230770e-01f, +9.808354703e-02f, -3.680919559e-03f }, + { -4.865227334e-02f, +9.543697533e-01f, +9.829720144e-02f, -3.691838248e-03f }, + { -4.869881664e-02f, +9.542161860e-01f, +9.851101044e-02f, -3.702775091e-03f }, + { -4.874524804e-02f, +9.540623752e-01f, +9.872497399e-02f, -3.713730097e-03f }, + { -4.879156762e-02f, +9.539083209e-01f, +9.893909208e-02f, -3.724703278e-03f }, + { -4.883777544e-02f, +9.537540234e-01f, +9.915336469e-02f, -3.735694643e-03f }, + { -4.888387160e-02f, +9.535994826e-01f, +9.936779178e-02f, -3.746704203e-03f }, + { -4.892985616e-02f, +9.534446987e-01f, +9.958237334e-02f, -3.757731967e-03f }, + { -4.897572920e-02f, +9.532896717e-01f, +9.979710935e-02f, -3.768777946e-03f }, + { -4.902149080e-02f, +9.531344018e-01f, +1.000119998e-01f, -3.779842151e-03f }, + { -4.906714105e-02f, +9.529788891e-01f, +1.002270446e-01f, -3.790924590e-03f }, + { -4.911268001e-02f, +9.528231336e-01f, +1.004422438e-01f, -3.802025274e-03f }, + { -4.915810776e-02f, +9.526671355e-01f, +1.006575974e-01f, -3.813144214e-03f }, + { -4.920342438e-02f, +9.525108949e-01f, +1.008731053e-01f, -3.824281419e-03f }, + { -4.924862995e-02f, +9.523544118e-01f, +1.010887674e-01f, -3.835436900e-03f }, + { -4.929372455e-02f, +9.521976863e-01f, +1.013045839e-01f, -3.846610666e-03f }, + { -4.933870825e-02f, +9.520407186e-01f, +1.015205546e-01f, -3.857802728e-03f }, + { -4.938358114e-02f, +9.518835087e-01f, +1.017366796e-01f, -3.869013095e-03f }, + { -4.942834328e-02f, +9.517260568e-01f, +1.019529588e-01f, -3.880241778e-03f }, + { -4.947299476e-02f, +9.515683630e-01f, +1.021693921e-01f, -3.891488786e-03f }, + { -4.951753566e-02f, +9.514104273e-01f, +1.023859797e-01f, -3.902754129e-03f }, + { -4.956196605e-02f, +9.512522498e-01f, +1.026027213e-01f, -3.914037818e-03f }, + { -4.960628601e-02f, +9.510938306e-01f, +1.028196171e-01f, -3.925339862e-03f }, + { -4.965049562e-02f, +9.509351700e-01f, +1.030366669e-01f, -3.936660271e-03f }, + { -4.969459496e-02f, +9.507762678e-01f, +1.032538708e-01f, -3.947999054e-03f }, + { -4.973858410e-02f, +9.506171243e-01f, +1.034712288e-01f, -3.959356223e-03f }, + { -4.978246313e-02f, +9.504577395e-01f, +1.036887408e-01f, -3.970731786e-03f }, + { -4.982623211e-02f, +9.502981136e-01f, +1.039064067e-01f, -3.982125754e-03f }, + { -4.986989114e-02f, +9.501382466e-01f, +1.041242266e-01f, -3.993538136e-03f }, + { -4.991344028e-02f, +9.499781386e-01f, +1.043422005e-01f, -4.004968942e-03f }, + { -4.995687962e-02f, +9.498177898e-01f, +1.045603282e-01f, -4.016418182e-03f }, + { -5.000020923e-02f, +9.496572003e-01f, +1.047786099e-01f, -4.027885865e-03f }, + { -5.004342920e-02f, +9.494963700e-01f, +1.049970454e-01f, -4.039372002e-03f }, + { -5.008653959e-02f, +9.493352993e-01f, +1.052156347e-01f, -4.050876601e-03f }, + { -5.012954049e-02f, +9.491739880e-01f, +1.054343779e-01f, -4.062399673e-03f }, + { -5.017243198e-02f, +9.490124364e-01f, +1.056532748e-01f, -4.073941228e-03f }, + { -5.021521414e-02f, +9.488506446e-01f, +1.058723254e-01f, -4.085501274e-03f }, + { -5.025788704e-02f, +9.486886126e-01f, +1.060915299e-01f, -4.097079822e-03f }, + { -5.030045076e-02f, +9.485263405e-01f, +1.063108880e-01f, -4.108676881e-03f }, + { -5.034290538e-02f, +9.483638285e-01f, +1.065303997e-01f, -4.120292461e-03f }, + { -5.038525098e-02f, +9.482010767e-01f, +1.067500652e-01f, -4.131926571e-03f }, + { -5.042748764e-02f, +9.480380851e-01f, +1.069698842e-01f, -4.143579220e-03f }, + { -5.046961543e-02f, +9.478748538e-01f, +1.071898568e-01f, -4.155250420e-03f }, + { -5.051163444e-02f, +9.477113830e-01f, +1.074099830e-01f, -4.166940178e-03f }, + { -5.055354474e-02f, +9.475476728e-01f, +1.076302628e-01f, -4.178648505e-03f }, + { -5.059534642e-02f, +9.473837233e-01f, +1.078506960e-01f, -4.190375409e-03f }, + { -5.063703954e-02f, +9.472195345e-01f, +1.080712828e-01f, -4.202120901e-03f }, + { -5.067862420e-02f, +9.470551065e-01f, +1.082920229e-01f, -4.213884989e-03f }, + { -5.072010046e-02f, +9.468904396e-01f, +1.085129166e-01f, -4.225667684e-03f }, + { -5.076146841e-02f, +9.467255337e-01f, +1.087339636e-01f, -4.237468994e-03f }, + { -5.080272812e-02f, +9.465603890e-01f, +1.089551640e-01f, -4.249288929e-03f }, + { -5.084387968e-02f, +9.463950056e-01f, +1.091765177e-01f, -4.261127499e-03f }, + { -5.088492316e-02f, +9.462293836e-01f, +1.093980247e-01f, -4.272984712e-03f }, + { -5.092585865e-02f, +9.460635230e-01f, +1.096196851e-01f, -4.284860578e-03f }, + { -5.096668621e-02f, +9.458974241e-01f, +1.098414987e-01f, -4.296755107e-03f }, + { -5.100740594e-02f, +9.457310868e-01f, +1.100634655e-01f, -4.308668306e-03f }, + { -5.104801790e-02f, +9.455645113e-01f, +1.102855855e-01f, -4.320600187e-03f }, + { -5.108852219e-02f, +9.453976978e-01f, +1.105078587e-01f, -4.332550758e-03f }, + { -5.112891887e-02f, +9.452306462e-01f, +1.107302850e-01f, -4.344520028e-03f }, + { -5.116920802e-02f, +9.450633568e-01f, +1.109528645e-01f, -4.356508006e-03f }, + { -5.120938973e-02f, +9.448958296e-01f, +1.111755970e-01f, -4.368514702e-03f }, + { -5.124946408e-02f, +9.447280647e-01f, +1.113984826e-01f, -4.380540125e-03f }, + { -5.128943114e-02f, +9.445600623e-01f, +1.116215212e-01f, -4.392584284e-03f }, + { -5.132929099e-02f, +9.443918223e-01f, +1.118447128e-01f, -4.404647188e-03f }, + { -5.136904371e-02f, +9.442233450e-01f, +1.120680573e-01f, -4.416728846e-03f }, + { -5.140868939e-02f, +9.440546305e-01f, +1.122915548e-01f, -4.428829267e-03f }, + { -5.144822810e-02f, +9.438856788e-01f, +1.125152052e-01f, -4.440948461e-03f }, + { -5.148765991e-02f, +9.437164901e-01f, +1.127390085e-01f, -4.453086436e-03f }, + { -5.152698491e-02f, +9.435470644e-01f, +1.129629646e-01f, -4.465243201e-03f }, + { -5.156620319e-02f, +9.433774019e-01f, +1.131870735e-01f, -4.477418765e-03f }, + { -5.160531481e-02f, +9.432075026e-01f, +1.134113352e-01f, -4.489613138e-03f }, + { -5.164431986e-02f, +9.430373667e-01f, +1.136357497e-01f, -4.501826329e-03f }, + { -5.168321841e-02f, +9.428669944e-01f, +1.138603169e-01f, -4.514058345e-03f }, + { -5.172201055e-02f, +9.426963856e-01f, +1.140850368e-01f, -4.526309197e-03f }, + { -5.176069636e-02f, +9.425255405e-01f, +1.143099093e-01f, -4.538578892e-03f }, + { -5.179927591e-02f, +9.423544592e-01f, +1.145349345e-01f, -4.550867441e-03f }, + { -5.183774929e-02f, +9.421831418e-01f, +1.147601122e-01f, -4.563174852e-03f }, + { -5.187611657e-02f, +9.420115885e-01f, +1.149854425e-01f, -4.575501133e-03f }, + { -5.191437783e-02f, +9.418397993e-01f, +1.152109254e-01f, -4.587846293e-03f }, + { -5.195253316e-02f, +9.416677743e-01f, +1.154365607e-01f, -4.600210342e-03f }, + { -5.199058263e-02f, +9.414955136e-01f, +1.156623486e-01f, -4.612593288e-03f }, + { -5.202852632e-02f, +9.413230174e-01f, +1.158882888e-01f, -4.624995140e-03f }, + { -5.206636432e-02f, +9.411502858e-01f, +1.161143815e-01f, -4.637415906e-03f }, + { -5.210409670e-02f, +9.409773188e-01f, +1.163406265e-01f, -4.649855595e-03f }, + { -5.214172354e-02f, +9.408041166e-01f, +1.165670239e-01f, -4.662314217e-03f }, + { -5.217924493e-02f, +9.406306792e-01f, +1.167935736e-01f, -4.674791779e-03f }, + { -5.221666093e-02f, +9.404570069e-01f, +1.170202755e-01f, -4.687288290e-03f }, + { -5.225397164e-02f, +9.402830997e-01f, +1.172471298e-01f, -4.699803759e-03f }, + { -5.229117713e-02f, +9.401089576e-01f, +1.174741362e-01f, -4.712338195e-03f }, + { -5.232827748e-02f, +9.399345809e-01f, +1.177012947e-01f, -4.724891606e-03f }, + { -5.236527277e-02f, +9.397599696e-01f, +1.179286055e-01f, -4.737464000e-03f }, + { -5.240216308e-02f, +9.395851238e-01f, +1.181560683e-01f, -4.750055387e-03f }, + { -5.243894849e-02f, +9.394100437e-01f, +1.183836832e-01f, -4.762665774e-03f }, + { -5.247562909e-02f, +9.392347294e-01f, +1.186114502e-01f, -4.775295171e-03f }, + { -5.251220495e-02f, +9.390591808e-01f, +1.188393692e-01f, -4.787943585e-03f }, + { -5.254867615e-02f, +9.388833983e-01f, +1.190674401e-01f, -4.800611026e-03f }, + { -5.258504277e-02f, +9.387073818e-01f, +1.192956630e-01f, -4.813297501e-03f }, + { -5.262130489e-02f, +9.385311316e-01f, +1.195240378e-01f, -4.826003020e-03f }, + { -5.265746259e-02f, +9.383546476e-01f, +1.197525644e-01f, -4.838727590e-03f }, + { -5.269351596e-02f, +9.381779301e-01f, +1.199812429e-01f, -4.851471219e-03f }, + { -5.272946506e-02f, +9.380009790e-01f, +1.202100732e-01f, -4.864233917e-03f }, + { -5.276531000e-02f, +9.378237946e-01f, +1.204390553e-01f, -4.877015692e-03f }, + { -5.280105083e-02f, +9.376463769e-01f, +1.206681891e-01f, -4.889816551e-03f }, + { -5.283668764e-02f, +9.374687261e-01f, +1.208974746e-01f, -4.902636504e-03f }, + { -5.287222052e-02f, +9.372908423e-01f, +1.211269118e-01f, -4.915475558e-03f }, + { -5.290764955e-02f, +9.371127255e-01f, +1.213565006e-01f, -4.928333721e-03f }, + { -5.294297479e-02f, +9.369343759e-01f, +1.215862410e-01f, -4.941211003e-03f }, + { -5.297819635e-02f, +9.367557936e-01f, +1.218161330e-01f, -4.954107411e-03f }, + { -5.301331428e-02f, +9.365769788e-01f, +1.220461765e-01f, -4.967022953e-03f }, + { -5.304832868e-02f, +9.363979314e-01f, +1.222763714e-01f, -4.979957637e-03f }, + { -5.308323963e-02f, +9.362186517e-01f, +1.225067179e-01f, -4.992911472e-03f }, + { -5.311804720e-02f, +9.360391397e-01f, +1.227372157e-01f, -5.005884466e-03f }, + { -5.315275148e-02f, +9.358593955e-01f, +1.229678649e-01f, -5.018876627e-03f }, + { -5.318735255e-02f, +9.356794194e-01f, +1.231986655e-01f, -5.031887963e-03f }, + { -5.322185049e-02f, +9.354992113e-01f, +1.234296174e-01f, -5.044918481e-03f }, + { -5.325624537e-02f, +9.353187714e-01f, +1.236607205e-01f, -5.057968191e-03f }, + { -5.329053728e-02f, +9.351380998e-01f, +1.238919749e-01f, -5.071037100e-03f }, + { -5.332472630e-02f, +9.349571966e-01f, +1.241233805e-01f, -5.084125216e-03f }, + { -5.335881251e-02f, +9.347760620e-01f, +1.243549372e-01f, -5.097232546e-03f }, + { -5.339279600e-02f, +9.345946960e-01f, +1.245866451e-01f, -5.110359100e-03f }, + { -5.342667683e-02f, +9.344130987e-01f, +1.248185041e-01f, -5.123504885e-03f }, + { -5.346045510e-02f, +9.342312704e-01f, +1.250505141e-01f, -5.136669908e-03f }, + { -5.349413088e-02f, +9.340492110e-01f, +1.252826751e-01f, -5.149854178e-03f }, + { -5.352770425e-02f, +9.338669207e-01f, +1.255149871e-01f, -5.163057703e-03f }, + { -5.356117530e-02f, +9.336843996e-01f, +1.257474501e-01f, -5.176280490e-03f }, + { -5.359454410e-02f, +9.335016478e-01f, +1.259800639e-01f, -5.189522547e-03f }, + { -5.362781074e-02f, +9.333186655e-01f, +1.262128286e-01f, -5.202783882e-03f }, + { -5.366097530e-02f, +9.331354527e-01f, +1.264457441e-01f, -5.216064503e-03f }, + { -5.369403785e-02f, +9.329520096e-01f, +1.266788105e-01f, -5.229364417e-03f }, + { -5.372699848e-02f, +9.327683363e-01f, +1.269120275e-01f, -5.242683633e-03f }, + { -5.375985728e-02f, +9.325844328e-01f, +1.271453953e-01f, -5.256022157e-03f }, + { -5.379261431e-02f, +9.324002994e-01f, +1.273789138e-01f, -5.269379998e-03f }, + { -5.382526966e-02f, +9.322159361e-01f, +1.276125829e-01f, -5.282757164e-03f }, + { -5.385782342e-02f, +9.320313430e-01f, +1.278464026e-01f, -5.296153661e-03f }, + { -5.389027566e-02f, +9.318465203e-01f, +1.280803728e-01f, -5.309569498e-03f }, + { -5.392262647e-02f, +9.316614680e-01f, +1.283144936e-01f, -5.323004682e-03f }, + { -5.395487592e-02f, +9.314761864e-01f, +1.285487648e-01f, -5.336459220e-03f }, + { -5.398702410e-02f, +9.312906754e-01f, +1.287831865e-01f, -5.349933121e-03f }, + { -5.401907109e-02f, +9.311049353e-01f, +1.290177586e-01f, -5.363426391e-03f }, + { -5.405101697e-02f, +9.309189660e-01f, +1.292524811e-01f, -5.376939039e-03f }, + { -5.408286181e-02f, +9.307327679e-01f, +1.294873538e-01f, -5.390471071e-03f }, + { -5.411460571e-02f, +9.305463408e-01f, +1.297223769e-01f, -5.404022496e-03f }, + { -5.414624875e-02f, +9.303596851e-01f, +1.299575502e-01f, -5.417593320e-03f }, + { -5.417779099e-02f, +9.301728008e-01f, +1.301928737e-01f, -5.431183551e-03f }, + { -5.420923253e-02f, +9.299856879e-01f, +1.304283474e-01f, -5.444793197e-03f }, + { -5.424057345e-02f, +9.297983467e-01f, +1.306639711e-01f, -5.458422264e-03f }, + { -5.427181382e-02f, +9.296107773e-01f, +1.308997450e-01f, -5.472070761e-03f }, + { -5.430295374e-02f, +9.294229797e-01f, +1.311356689e-01f, -5.485738694e-03f }, + { -5.433399327e-02f, +9.292349540e-01f, +1.313717428e-01f, -5.499426070e-03f }, + { -5.436493251e-02f, +9.290467005e-01f, +1.316079667e-01f, -5.513132898e-03f }, + { -5.439577153e-02f, +9.288582192e-01f, +1.318443405e-01f, -5.526859184e-03f }, + { -5.442651041e-02f, +9.286695102e-01f, +1.320808642e-01f, -5.540604935e-03f }, + { -5.445714924e-02f, +9.284805736e-01f, +1.323175377e-01f, -5.554370159e-03f }, + { -5.448768810e-02f, +9.282914097e-01f, +1.325543610e-01f, -5.568154863e-03f }, + { -5.451812706e-02f, +9.281020184e-01f, +1.327913341e-01f, -5.581959054e-03f }, + { -5.454846622e-02f, +9.279123998e-01f, +1.330284568e-01f, -5.595782739e-03f }, + { -5.457870565e-02f, +9.277225543e-01f, +1.332657293e-01f, -5.609625925e-03f }, + { -5.460884543e-02f, +9.275324817e-01f, +1.335031514e-01f, -5.623488619e-03f }, + { -5.463888565e-02f, +9.273421823e-01f, +1.337407230e-01f, -5.637370829e-03f }, + { -5.466882638e-02f, +9.271516562e-01f, +1.339784442e-01f, -5.651272561e-03f }, + { -5.469866771e-02f, +9.269609034e-01f, +1.342163150e-01f, -5.665193823e-03f }, + { -5.472840972e-02f, +9.267699242e-01f, +1.344543351e-01f, -5.679134621e-03f }, + { -5.475805249e-02f, +9.265787186e-01f, +1.346925048e-01f, -5.693094963e-03f }, + { -5.478759611e-02f, +9.263872867e-01f, +1.349308237e-01f, -5.707074854e-03f }, + { -5.481704064e-02f, +9.261956287e-01f, +1.351692920e-01f, -5.721074303e-03f }, + { -5.484638619e-02f, +9.260037447e-01f, +1.354079097e-01f, -5.735093317e-03f }, + { -5.487563282e-02f, +9.258116348e-01f, +1.356466765e-01f, -5.749131901e-03f }, + { -5.490478063e-02f, +9.256192991e-01f, +1.358855926e-01f, -5.763190063e-03f }, + { -5.493382968e-02f, +9.254267378e-01f, +1.361246578e-01f, -5.777267810e-03f }, + { -5.496278007e-02f, +9.252339509e-01f, +1.363638722e-01f, -5.791365148e-03f }, + { -5.499163187e-02f, +9.250409386e-01f, +1.366032356e-01f, -5.805482085e-03f }, + { -5.502038517e-02f, +9.248477010e-01f, +1.368427480e-01f, -5.819618626e-03f }, + { -5.504904005e-02f, +9.246542383e-01f, +1.370824095e-01f, -5.833774780e-03f }, + { -5.507759658e-02f, +9.244605504e-01f, +1.373222199e-01f, -5.847950552e-03f }, + { -5.510605486e-02f, +9.242666377e-01f, +1.375621792e-01f, -5.862145949e-03f }, + { -5.513441497e-02f, +9.240725001e-01f, +1.378022873e-01f, -5.876360977e-03f }, + { -5.516267698e-02f, +9.238781378e-01f, +1.380425443e-01f, -5.890595645e-03f }, + { -5.519084097e-02f, +9.236835509e-01f, +1.382829500e-01f, -5.904849957e-03f }, + { -5.521890704e-02f, +9.234887396e-01f, +1.385235045e-01f, -5.919123921e-03f }, + { -5.524687526e-02f, +9.232937039e-01f, +1.387642076e-01f, -5.933417543e-03f }, + { -5.527474572e-02f, +9.230984441e-01f, +1.390050594e-01f, -5.947730830e-03f }, + { -5.530251848e-02f, +9.229029601e-01f, +1.392460598e-01f, -5.962063788e-03f }, + { -5.533019365e-02f, +9.227072522e-01f, +1.394872087e-01f, -5.976416423e-03f }, + { -5.535777130e-02f, +9.225113204e-01f, +1.397285061e-01f, -5.990788743e-03f }, + { -5.538525151e-02f, +9.223151649e-01f, +1.399699520e-01f, -6.005180754e-03f }, + { -5.541263436e-02f, +9.221187858e-01f, +1.402115463e-01f, -6.019592461e-03f }, + { -5.543991994e-02f, +9.219221832e-01f, +1.404532889e-01f, -6.034023872e-03f }, + { -5.546710832e-02f, +9.217253573e-01f, +1.406951799e-01f, -6.048474993e-03f }, + { -5.549419960e-02f, +9.215283081e-01f, +1.409372192e-01f, -6.062945830e-03f }, + { -5.552119385e-02f, +9.213310358e-01f, +1.411794066e-01f, -6.077436389e-03f }, + { -5.554809115e-02f, +9.211335405e-01f, +1.414217423e-01f, -6.091946678e-03f }, + { -5.557489159e-02f, +9.209358223e-01f, +1.416642261e-01f, -6.106476701e-03f }, + { -5.560159525e-02f, +9.207378813e-01f, +1.419068580e-01f, -6.121026465e-03f }, + { -5.562820221e-02f, +9.205397178e-01f, +1.421496379e-01f, -6.135595977e-03f }, + { -5.565471255e-02f, +9.203413317e-01f, +1.423925658e-01f, -6.150185242e-03f }, + { -5.568112636e-02f, +9.201427233e-01f, +1.426356417e-01f, -6.164794268e-03f }, + { -5.570744371e-02f, +9.199438926e-01f, +1.428788655e-01f, -6.179423059e-03f }, + { -5.573366470e-02f, +9.197448398e-01f, +1.431222371e-01f, -6.194071622e-03f }, + { -5.575978940e-02f, +9.195455649e-01f, +1.433657566e-01f, -6.208739964e-03f }, + { -5.578581789e-02f, +9.193460682e-01f, +1.436094238e-01f, -6.223428090e-03f }, + { -5.581175026e-02f, +9.191463497e-01f, +1.438532387e-01f, -6.238136006e-03f }, + { -5.583758659e-02f, +9.189464096e-01f, +1.440972013e-01f, -6.252863718e-03f }, + { -5.586332696e-02f, +9.187462479e-01f, +1.443413115e-01f, -6.267611233e-03f }, + { -5.588897145e-02f, +9.185458649e-01f, +1.445855693e-01f, -6.282378556e-03f }, + { -5.591452015e-02f, +9.183452606e-01f, +1.448299746e-01f, -6.297165693e-03f }, + { -5.593997314e-02f, +9.181444351e-01f, +1.450745274e-01f, -6.311972650e-03f }, + { -5.596533050e-02f, +9.179433886e-01f, +1.453192276e-01f, -6.326799433e-03f }, + { -5.599059231e-02f, +9.177421213e-01f, +1.455640752e-01f, -6.341646048e-03f }, + { -5.601575866e-02f, +9.175406331e-01f, +1.458090702e-01f, -6.356512501e-03f }, + { -5.604082963e-02f, +9.173389243e-01f, +1.460542124e-01f, -6.371398797e-03f }, + { -5.606580530e-02f, +9.171369950e-01f, +1.462995018e-01f, -6.386304943e-03f }, + { -5.609068575e-02f, +9.169348454e-01f, +1.465449385e-01f, -6.401230944e-03f }, + { -5.611547107e-02f, +9.167324754e-01f, +1.467905223e-01f, -6.416176806e-03f }, + { -5.614016133e-02f, +9.165298853e-01f, +1.470362531e-01f, -6.431142534e-03f }, + { -5.616475663e-02f, +9.163270752e-01f, +1.472821311e-01f, -6.446128134e-03f }, + { -5.618925704e-02f, +9.161240451e-01f, +1.475281560e-01f, -6.461133612e-03f }, + { -5.621366265e-02f, +9.159207954e-01f, +1.477743278e-01f, -6.476158974e-03f }, + { -5.623797353e-02f, +9.157173259e-01f, +1.480206466e-01f, -6.491204225e-03f }, + { -5.626218978e-02f, +9.155136370e-01f, +1.482671122e-01f, -6.506269371e-03f }, + { -5.628631147e-02f, +9.153097287e-01f, +1.485137245e-01f, -6.521354417e-03f }, + { -5.631033869e-02f, +9.151056011e-01f, +1.487604837e-01f, -6.536459369e-03f }, + { -5.633427152e-02f, +9.149012543e-01f, +1.490073895e-01f, -6.551584232e-03f }, + { -5.635811004e-02f, +9.146966886e-01f, +1.492544420e-01f, -6.566729012e-03f }, + { -5.638185433e-02f, +9.144919040e-01f, +1.495016410e-01f, -6.581893714e-03f }, + { -5.640550448e-02f, +9.142869006e-01f, +1.497489866e-01f, -6.597078344e-03f }, + { -5.642906057e-02f, +9.140816786e-01f, +1.499964787e-01f, -6.612282907e-03f }, + { -5.645252268e-02f, +9.138762381e-01f, +1.502441173e-01f, -6.627507408e-03f }, + { -5.647589090e-02f, +9.136705792e-01f, +1.504919022e-01f, -6.642751853e-03f }, + { -5.649916531e-02f, +9.134647021e-01f, +1.507398335e-01f, -6.658016248e-03f }, + { -5.652234599e-02f, +9.132586068e-01f, +1.509879110e-01f, -6.673300597e-03f }, + { -5.654543302e-02f, +9.130522936e-01f, +1.512361348e-01f, -6.688604905e-03f }, + { -5.656842649e-02f, +9.128457625e-01f, +1.514845048e-01f, -6.703929179e-03f }, + { -5.659132648e-02f, +9.126390136e-01f, +1.517330210e-01f, -6.719273423e-03f }, + { -5.661413307e-02f, +9.124320471e-01f, +1.519816832e-01f, -6.734637642e-03f }, + { -5.663684634e-02f, +9.122248632e-01f, +1.522304914e-01f, -6.750021842e-03f }, + { -5.665946638e-02f, +9.120174619e-01f, +1.524794457e-01f, -6.765426027e-03f }, + { -5.668199328e-02f, +9.118098434e-01f, +1.527285458e-01f, -6.780850204e-03f }, + { -5.670442710e-02f, +9.116020078e-01f, +1.529777918e-01f, -6.796294376e-03f }, + { -5.672676795e-02f, +9.113939552e-01f, +1.532271837e-01f, -6.811758549e-03f }, + { -5.674901589e-02f, +9.111856858e-01f, +1.534767213e-01f, -6.827242728e-03f }, + { -5.677117101e-02f, +9.109771996e-01f, +1.537264047e-01f, -6.842746919e-03f }, + { -5.679323340e-02f, +9.107684969e-01f, +1.539762337e-01f, -6.858271125e-03f }, + { -5.681520314e-02f, +9.105595777e-01f, +1.542262084e-01f, -6.873815352e-03f }, + { -5.683708031e-02f, +9.103504422e-01f, +1.544763286e-01f, -6.889379605e-03f }, + { -5.685886499e-02f, +9.101410905e-01f, +1.547265943e-01f, -6.904963889e-03f }, + { -5.688055727e-02f, +9.099315228e-01f, +1.549770055e-01f, -6.920568209e-03f }, + { -5.690215723e-02f, +9.097217391e-01f, +1.552275620e-01f, -6.936192569e-03f }, + { -5.692366496e-02f, +9.095117396e-01f, +1.554782640e-01f, -6.951836974e-03f }, + { -5.694508053e-02f, +9.093015244e-01f, +1.557291112e-01f, -6.967501430e-03f }, + { -5.696640402e-02f, +9.090910937e-01f, +1.559801037e-01f, -6.983185940e-03f }, + { -5.698763554e-02f, +9.088804476e-01f, +1.562312413e-01f, -6.998890510e-03f }, + { -5.700877514e-02f, +9.086695861e-01f, +1.564825241e-01f, -7.014615145e-03f }, + { -5.702982292e-02f, +9.084585096e-01f, +1.567339520e-01f, -7.030359849e-03f }, + { -5.705077897e-02f, +9.082472180e-01f, +1.569855249e-01f, -7.046124626e-03f }, + { -5.707164336e-02f, +9.080357115e-01f, +1.572372428e-01f, -7.061909482e-03f }, + { -5.709241618e-02f, +9.078239902e-01f, +1.574891056e-01f, -7.077714420e-03f }, + { -5.711309750e-02f, +9.076120543e-01f, +1.577411133e-01f, -7.093539446e-03f }, + { -5.713368743e-02f, +9.073999039e-01f, +1.579932657e-01f, -7.109384565e-03f }, + { -5.715418602e-02f, +9.071875391e-01f, +1.582455630e-01f, -7.125249780e-03f }, + { -5.717459338e-02f, +9.069749601e-01f, +1.584980049e-01f, -7.141135096e-03f }, + { -5.719490958e-02f, +9.067621670e-01f, +1.587505915e-01f, -7.157040517e-03f }, + { -5.721513471e-02f, +9.065491599e-01f, +1.590033227e-01f, -7.172966049e-03f }, + { -5.723526885e-02f, +9.063359389e-01f, +1.592561984e-01f, -7.188911695e-03f }, + { -5.725531208e-02f, +9.061225043e-01f, +1.595092186e-01f, -7.204877460e-03f }, + { -5.727526448e-02f, +9.059088560e-01f, +1.597623832e-01f, -7.220863348e-03f }, + { -5.729512615e-02f, +9.056949943e-01f, +1.600156922e-01f, -7.236869364e-03f }, + { -5.731489716e-02f, +9.054809193e-01f, +1.602691455e-01f, -7.252895512e-03f }, + { -5.733457759e-02f, +9.052666311e-01f, +1.605227430e-01f, -7.268941796e-03f }, + { -5.735416753e-02f, +9.050521298e-01f, +1.607764848e-01f, -7.285008220e-03f }, + { -5.737366706e-02f, +9.048374156e-01f, +1.610303707e-01f, -7.301094788e-03f }, + { -5.739307627e-02f, +9.046224887e-01f, +1.612844007e-01f, -7.317201506e-03f }, + { -5.741239524e-02f, +9.044073490e-01f, +1.615385747e-01f, -7.333328376e-03f }, + { -5.743162405e-02f, +9.041919969e-01f, +1.617928927e-01f, -7.349475404e-03f }, + { -5.745076279e-02f, +9.039764323e-01f, +1.620473546e-01f, -7.365642593e-03f }, + { -5.746981153e-02f, +9.037606555e-01f, +1.623019604e-01f, -7.381829947e-03f }, + { -5.748877036e-02f, +9.035446666e-01f, +1.625567100e-01f, -7.398037471e-03f }, + { -5.750763937e-02f, +9.033284656e-01f, +1.628116034e-01f, -7.414265167e-03f }, + { -5.752641864e-02f, +9.031120528e-01f, +1.630666404e-01f, -7.430513042e-03f }, + { -5.754510825e-02f, +9.028954283e-01f, +1.633218211e-01f, -7.446781098e-03f }, + { -5.756370829e-02f, +9.026785922e-01f, +1.635771453e-01f, -7.463069339e-03f }, + { -5.758221883e-02f, +9.024615447e-01f, +1.638326131e-01f, -7.479377769e-03f }, + { -5.760063997e-02f, +9.022442858e-01f, +1.640882243e-01f, -7.495706392e-03f }, + { -5.761897178e-02f, +9.020268157e-01f, +1.643439789e-01f, -7.512055213e-03f }, + { -5.763721435e-02f, +9.018091345e-01f, +1.645998769e-01f, -7.528424234e-03f }, + { -5.765536777e-02f, +9.015912425e-01f, +1.648559182e-01f, -7.544813460e-03f }, + { -5.767343210e-02f, +9.013731396e-01f, +1.651121027e-01f, -7.561222894e-03f }, + { -5.769140745e-02f, +9.011548261e-01f, +1.653684303e-01f, -7.577652540e-03f }, + { -5.770929389e-02f, +9.009363021e-01f, +1.656249011e-01f, -7.594102403e-03f }, + { -5.772709151e-02f, +9.007175676e-01f, +1.658815150e-01f, -7.610572484e-03f }, + { -5.774480038e-02f, +9.004986230e-01f, +1.661382718e-01f, -7.627062789e-03f }, + { -5.776242060e-02f, +9.002794682e-01f, +1.663951716e-01f, -7.643573321e-03f }, + { -5.777995224e-02f, +9.000601034e-01f, +1.666522142e-01f, -7.660104084e-03f }, + { -5.779739540e-02f, +8.998405288e-01f, +1.669093997e-01f, -7.676655080e-03f }, + { -5.781475014e-02f, +8.996207445e-01f, +1.671667279e-01f, -7.693226314e-03f }, + { -5.783201657e-02f, +8.994007506e-01f, +1.674241988e-01f, -7.709817790e-03f }, + { -5.784919475e-02f, +8.991805472e-01f, +1.676818124e-01f, -7.726429509e-03f }, + { -5.786628478e-02f, +8.989601346e-01f, +1.679395686e-01f, -7.743061477e-03f }, + { -5.788328673e-02f, +8.987395128e-01f, +1.681974672e-01f, -7.759713697e-03f }, + { -5.790020070e-02f, +8.985186819e-01f, +1.684555084e-01f, -7.776386171e-03f }, + { -5.791702676e-02f, +8.982976422e-01f, +1.687136919e-01f, -7.793078904e-03f }, + { -5.793376500e-02f, +8.980763937e-01f, +1.689720178e-01f, -7.809791898e-03f }, + { -5.795041550e-02f, +8.978549365e-01f, +1.692304860e-01f, -7.826525157e-03f }, + { -5.796697834e-02f, +8.976332709e-01f, +1.694890963e-01f, -7.843278685e-03f }, + { -5.798345361e-02f, +8.974113969e-01f, +1.697478489e-01f, -7.860052484e-03f }, + { -5.799984140e-02f, +8.971893148e-01f, +1.700067435e-01f, -7.876846558e-03f }, + { -5.801614178e-02f, +8.969670245e-01f, +1.702657802e-01f, -7.893660909e-03f }, + { -5.803235484e-02f, +8.967445263e-01f, +1.705249588e-01f, -7.910495542e-03f }, + { -5.804848066e-02f, +8.965218203e-01f, +1.707842794e-01f, -7.927350459e-03f }, + { -5.806451933e-02f, +8.962989066e-01f, +1.710437419e-01f, -7.944225664e-03f }, + { -5.808047093e-02f, +8.960757854e-01f, +1.713033461e-01f, -7.961121159e-03f }, + { -5.809633554e-02f, +8.958524568e-01f, +1.715630920e-01f, -7.978036948e-03f }, + { -5.811211325e-02f, +8.956289209e-01f, +1.718229797e-01f, -7.994973033e-03f }, + { -5.812780414e-02f, +8.954051779e-01f, +1.720830089e-01f, -8.011929418e-03f }, + { -5.814340830e-02f, +8.951812279e-01f, +1.723431797e-01f, -8.028906105e-03f }, + { -5.815892580e-02f, +8.949570711e-01f, +1.726034920e-01f, -8.045903098e-03f }, + { -5.817435673e-02f, +8.947327076e-01f, +1.728639457e-01f, -8.062920399e-03f }, + { -5.818970119e-02f, +8.945081375e-01f, +1.731245407e-01f, -8.079958012e-03f }, + { -5.820495924e-02f, +8.942833610e-01f, +1.733852771e-01f, -8.097015938e-03f }, + { -5.822013097e-02f, +8.940583782e-01f, +1.736461547e-01f, -8.114094182e-03f }, + { -5.823521647e-02f, +8.938331892e-01f, +1.739071734e-01f, -8.131192745e-03f }, + { -5.825021582e-02f, +8.936077942e-01f, +1.741683333e-01f, -8.148311631e-03f }, + { -5.826512910e-02f, +8.933821934e-01f, +1.744296343e-01f, -8.165450843e-03f }, + { -5.827995640e-02f, +8.931563868e-01f, +1.746910762e-01f, -8.182610382e-03f }, + { -5.829469780e-02f, +8.929303746e-01f, +1.749526590e-01f, -8.199790252e-03f }, + { -5.830935339e-02f, +8.927041569e-01f, +1.752143827e-01f, -8.216990455e-03f }, + { -5.832392325e-02f, +8.924777339e-01f, +1.754762472e-01f, -8.234210994e-03f }, + { -5.833840746e-02f, +8.922511057e-01f, +1.757382524e-01f, -8.251451871e-03f }, + { -5.835280610e-02f, +8.920242725e-01f, +1.760003983e-01f, -8.268713090e-03f }, + { -5.836711927e-02f, +8.917972344e-01f, +1.762626848e-01f, -8.285994652e-03f }, + { -5.838134704e-02f, +8.915699915e-01f, +1.765251119e-01f, -8.303296561e-03f }, + { -5.839548949e-02f, +8.913425440e-01f, +1.767876794e-01f, -8.320618817e-03f }, + { -5.840954672e-02f, +8.911148920e-01f, +1.770503873e-01f, -8.337961425e-03f }, + { -5.842351880e-02f, +8.908870357e-01f, +1.773132356e-01f, -8.355324387e-03f }, + { -5.843740582e-02f, +8.906589751e-01f, +1.775762242e-01f, -8.372707704e-03f }, + { -5.845120786e-02f, +8.904307105e-01f, +1.778393529e-01f, -8.390111379e-03f }, + { -5.846492501e-02f, +8.902022419e-01f, +1.781026219e-01f, -8.407535414e-03f }, + { -5.847855735e-02f, +8.899735696e-01f, +1.783660309e-01f, -8.424979813e-03f }, + { -5.849210496e-02f, +8.897446936e-01f, +1.786295800e-01f, -8.442444576e-03f }, + { -5.850556793e-02f, +8.895156142e-01f, +1.788932690e-01f, -8.459929707e-03f }, + { -5.851894634e-02f, +8.892863313e-01f, +1.791570979e-01f, -8.477435207e-03f }, + { -5.853224028e-02f, +8.890568452e-01f, +1.794210666e-01f, -8.494961078e-03f }, + { -5.854544983e-02f, +8.888271561e-01f, +1.796851751e-01f, -8.512507324e-03f }, + { -5.855857506e-02f, +8.885972640e-01f, +1.799494234e-01f, -8.530073945e-03f }, + { -5.857161608e-02f, +8.883671691e-01f, +1.802138112e-01f, -8.547660944e-03f }, + { -5.858457295e-02f, +8.881368715e-01f, +1.804783386e-01f, -8.565268323e-03f }, + { -5.859744577e-02f, +8.879063714e-01f, +1.807430055e-01f, -8.582896084e-03f }, + { -5.861023462e-02f, +8.876756689e-01f, +1.810078118e-01f, -8.600544229e-03f }, + { -5.862293958e-02f, +8.874447642e-01f, +1.812727576e-01f, -8.618212759e-03f }, + { -5.863556073e-02f, +8.872136574e-01f, +1.815378426e-01f, -8.635901678e-03f }, + { -5.864809816e-02f, +8.869823487e-01f, +1.818030668e-01f, -8.653610986e-03f }, + { -5.866055196e-02f, +8.867508381e-01f, +1.820684302e-01f, -8.671340686e-03f }, + { -5.867292220e-02f, +8.865191259e-01f, +1.823339328e-01f, -8.689090780e-03f }, + { -5.868520898e-02f, +8.862872121e-01f, +1.825995743e-01f, -8.706861268e-03f }, + { -5.869741236e-02f, +8.860550970e-01f, +1.828653548e-01f, -8.724652154e-03f }, + { -5.870953245e-02f, +8.858227806e-01f, +1.831312743e-01f, -8.742463438e-03f }, + { -5.872156932e-02f, +8.855902631e-01f, +1.833973325e-01f, -8.760295123e-03f }, + { -5.873352306e-02f, +8.853575446e-01f, +1.836635296e-01f, -8.778147210e-03f }, + { -5.874539374e-02f, +8.851246253e-01f, +1.839298653e-01f, -8.796019700e-03f }, + { -5.875718146e-02f, +8.848915054e-01f, +1.841963397e-01f, -8.813912596e-03f }, + { -5.876888630e-02f, +8.846581849e-01f, +1.844629526e-01f, -8.831825899e-03f }, + { -5.878050834e-02f, +8.844246640e-01f, +1.847297040e-01f, -8.849759611e-03f }, + { -5.879204767e-02f, +8.841909429e-01f, +1.849965939e-01f, -8.867713732e-03f }, + { -5.880350436e-02f, +8.839570217e-01f, +1.852636221e-01f, -8.885688265e-03f }, + { -5.881487851e-02f, +8.837229005e-01f, +1.855307886e-01f, -8.903683211e-03f }, + { -5.882617019e-02f, +8.834885795e-01f, +1.857980933e-01f, -8.921698572e-03f }, + { -5.883737950e-02f, +8.832540589e-01f, +1.860655362e-01f, -8.939734348e-03f }, + { -5.884850651e-02f, +8.830193387e-01f, +1.863331172e-01f, -8.957790542e-03f }, + { -5.885955131e-02f, +8.827844191e-01f, +1.866008361e-01f, -8.975867154e-03f }, + { -5.887051398e-02f, +8.825493003e-01f, +1.868686931e-01f, -8.993964185e-03f }, + { -5.888139461e-02f, +8.823139824e-01f, +1.871366879e-01f, -9.012081638e-03f }, + { -5.889219328e-02f, +8.820784655e-01f, +1.874048205e-01f, -9.030219514e-03f }, + { -5.890291007e-02f, +8.818427498e-01f, +1.876730909e-01f, -9.048377812e-03f }, + { -5.891354507e-02f, +8.816068354e-01f, +1.879414989e-01f, -9.066556536e-03f }, + { -5.892409837e-02f, +8.813707226e-01f, +1.882100446e-01f, -9.084755685e-03f }, + { -5.893457003e-02f, +8.811344113e-01f, +1.884787277e-01f, -9.102975262e-03f }, + { -5.894496016e-02f, +8.808979018e-01f, +1.887475484e-01f, -9.121215266e-03f }, + { -5.895526884e-02f, +8.806611943e-01f, +1.890165064e-01f, -9.139475700e-03f }, + { -5.896549614e-02f, +8.804242888e-01f, +1.892856017e-01f, -9.157756564e-03f }, + { -5.897564215e-02f, +8.801871854e-01f, +1.895548343e-01f, -9.176057859e-03f }, + { -5.898570696e-02f, +8.799498845e-01f, +1.898242041e-01f, -9.194379586e-03f }, + { -5.899569065e-02f, +8.797123860e-01f, +1.900937110e-01f, -9.212721746e-03f }, + { -5.900559330e-02f, +8.794746902e-01f, +1.903633550e-01f, -9.231084340e-03f }, + { -5.901541499e-02f, +8.792367971e-01f, +1.906331359e-01f, -9.249467369e-03f }, + { -5.902515582e-02f, +8.789987070e-01f, +1.909030537e-01f, -9.267870833e-03f }, + { -5.903481587e-02f, +8.787604199e-01f, +1.911731083e-01f, -9.286294734e-03f }, + { -5.904439521e-02f, +8.785219361e-01f, +1.914432997e-01f, -9.304739072e-03f }, + { -5.905389393e-02f, +8.782832556e-01f, +1.917136278e-01f, -9.323203848e-03f }, + { -5.906331213e-02f, +8.780443786e-01f, +1.919840925e-01f, -9.341689062e-03f }, + { -5.907264987e-02f, +8.778053053e-01f, +1.922546937e-01f, -9.360194716e-03f }, + { -5.908190725e-02f, +8.775660358e-01f, +1.925254314e-01f, -9.378720810e-03f }, + { -5.909108434e-02f, +8.773265703e-01f, +1.927963055e-01f, -9.397267344e-03f }, + { -5.910018124e-02f, +8.770869088e-01f, +1.930673159e-01f, -9.415834320e-03f }, + { -5.910919802e-02f, +8.768470516e-01f, +1.933384626e-01f, -9.434421737e-03f }, + { -5.911813478e-02f, +8.766069987e-01f, +1.936097455e-01f, -9.453029596e-03f }, + { -5.912699159e-02f, +8.763667504e-01f, +1.938811645e-01f, -9.471657898e-03f }, + { -5.913576853e-02f, +8.761263068e-01f, +1.941527195e-01f, -9.490306643e-03f }, + { -5.914446570e-02f, +8.758856680e-01f, +1.944244105e-01f, -9.508975831e-03f }, + { -5.915308317e-02f, +8.756448342e-01f, +1.946962373e-01f, -9.527665464e-03f }, + { -5.916162104e-02f, +8.754038055e-01f, +1.949682000e-01f, -9.546375540e-03f }, + { -5.917007938e-02f, +8.751625821e-01f, +1.952402985e-01f, -9.565106062e-03f }, + { -5.917845827e-02f, +8.749211640e-01f, +1.955125326e-01f, -9.583857028e-03f }, + { -5.918675781e-02f, +8.746795516e-01f, +1.957849023e-01f, -9.602628439e-03f }, + { -5.919497807e-02f, +8.744377448e-01f, +1.960574076e-01f, -9.621420295e-03f }, + { -5.920311914e-02f, +8.741957439e-01f, +1.963300483e-01f, -9.640232597e-03f }, + { -5.921118110e-02f, +8.739535491e-01f, +1.966028244e-01f, -9.659065344e-03f }, + { -5.921916404e-02f, +8.737111603e-01f, +1.968757357e-01f, -9.677918538e-03f }, + { -5.922706804e-02f, +8.734685779e-01f, +1.971487824e-01f, -9.696792177e-03f }, + { -5.923489319e-02f, +8.732258019e-01f, +1.974219642e-01f, -9.715686262e-03f }, + { -5.924263957e-02f, +8.729828325e-01f, +1.976952810e-01f, -9.734600793e-03f }, + { -5.925030726e-02f, +8.727396699e-01f, +1.979687329e-01f, -9.753535770e-03f }, + { -5.925789634e-02f, +8.724963141e-01f, +1.982423197e-01f, -9.772491192e-03f }, + { -5.926540690e-02f, +8.722527654e-01f, +1.985160414e-01f, -9.791467061e-03f }, + { -5.927283903e-02f, +8.720090239e-01f, +1.987898979e-01f, -9.810463375e-03f }, + { -5.928019281e-02f, +8.717650897e-01f, +1.990638891e-01f, -9.829480135e-03f }, + { -5.928746832e-02f, +8.715209630e-01f, +1.993380149e-01f, -9.848517340e-03f }, + { -5.929466565e-02f, +8.712766439e-01f, +1.996122753e-01f, -9.867574990e-03f }, + { -5.930178487e-02f, +8.710321326e-01f, +1.998866701e-01f, -9.886653086e-03f }, + { -5.930882608e-02f, +8.707874293e-01f, +2.001611994e-01f, -9.905751626e-03f }, + { -5.931578936e-02f, +8.705425340e-01f, +2.004358631e-01f, -9.924870610e-03f }, + { -5.932267479e-02f, +8.702974470e-01f, +2.007106609e-01f, -9.944010038e-03f }, + { -5.932948245e-02f, +8.700521683e-01f, +2.009855930e-01f, -9.963169910e-03f }, + { -5.933621243e-02f, +8.698066982e-01f, +2.012606592e-01f, -9.982350225e-03f }, + { -5.934286482e-02f, +8.695610368e-01f, +2.015358594e-01f, -1.000155098e-02f }, + { -5.934943969e-02f, +8.693151841e-01f, +2.018111936e-01f, -1.002077218e-02f }, + { -5.935593714e-02f, +8.690691405e-01f, +2.020866616e-01f, -1.004001383e-02f }, + { -5.936235724e-02f, +8.688229060e-01f, +2.023622635e-01f, -1.005927591e-02f }, + { -5.936870008e-02f, +8.685764808e-01f, +2.026379991e-01f, -1.007855843e-02f }, + { -5.937496574e-02f, +8.683298650e-01f, +2.029138683e-01f, -1.009786140e-02f }, + { -5.938115430e-02f, +8.680830587e-01f, +2.031898712e-01f, -1.011718480e-02f }, + { -5.938726586e-02f, +8.678360622e-01f, +2.034660075e-01f, -1.013652864e-02f }, + { -5.939330049e-02f, +8.675888756e-01f, +2.037422772e-01f, -1.015589292e-02f }, + { -5.939925828e-02f, +8.673414990e-01f, +2.040186803e-01f, -1.017527764e-02f }, + { -5.940513931e-02f, +8.670939326e-01f, +2.042952167e-01f, -1.019468279e-02f }, + { -5.941094367e-02f, +8.668461765e-01f, +2.045718862e-01f, -1.021410838e-02f }, + { -5.941667144e-02f, +8.665982309e-01f, +2.048486889e-01f, -1.023355441e-02f }, + { -5.942232269e-02f, +8.663500959e-01f, +2.051256246e-01f, -1.025302087e-02f }, + { -5.942789753e-02f, +8.661017718e-01f, +2.054026933e-01f, -1.027250776e-02f }, + { -5.943339603e-02f, +8.658532585e-01f, +2.056798948e-01f, -1.029201508e-02f }, + { -5.943881827e-02f, +8.656045563e-01f, +2.059572292e-01f, -1.031154284e-02f }, + { -5.944416434e-02f, +8.653556654e-01f, +2.062346962e-01f, -1.033109103e-02f }, + { -5.944943433e-02f, +8.651065858e-01f, +2.065122959e-01f, -1.035065964e-02f }, + { -5.945462831e-02f, +8.648573178e-01f, +2.067900282e-01f, -1.037024868e-02f }, + { -5.945974637e-02f, +8.646078615e-01f, +2.070678930e-01f, -1.038985815e-02f }, + { -5.946478859e-02f, +8.643582170e-01f, +2.073458902e-01f, -1.040948805e-02f }, + { -5.946975506e-02f, +8.641083845e-01f, +2.076240197e-01f, -1.042913837e-02f }, + { -5.947464586e-02f, +8.638583642e-01f, +2.079022815e-01f, -1.044880911e-02f }, + { -5.947946108e-02f, +8.636081562e-01f, +2.081806754e-01f, -1.046850028e-02f }, + { -5.948420080e-02f, +8.633577606e-01f, +2.084592015e-01f, -1.048821187e-02f }, + { -5.948886510e-02f, +8.631071776e-01f, +2.087378595e-01f, -1.050794387e-02f }, + { -5.949345407e-02f, +8.628564073e-01f, +2.090166495e-01f, -1.052769630e-02f }, + { -5.949796779e-02f, +8.626054500e-01f, +2.092955714e-01f, -1.054746914e-02f }, + { -5.950240634e-02f, +8.623543057e-01f, +2.095746250e-01f, -1.056726239e-02f }, + { -5.950676981e-02f, +8.621029746e-01f, +2.098538103e-01f, -1.058707606e-02f }, + { -5.951105828e-02f, +8.618514569e-01f, +2.101331273e-01f, -1.060691015e-02f }, + { -5.951527184e-02f, +8.615997527e-01f, +2.104125758e-01f, -1.062676464e-02f }, + { -5.951941056e-02f, +8.613478622e-01f, +2.106921557e-01f, -1.064663954e-02f }, + { -5.952347454e-02f, +8.610957855e-01f, +2.109718671e-01f, -1.066653486e-02f }, + { -5.952746386e-02f, +8.608435227e-01f, +2.112517097e-01f, -1.068645057e-02f }, + { -5.953137860e-02f, +8.605910741e-01f, +2.115316835e-01f, -1.070638669e-02f }, + { -5.953521884e-02f, +8.603384398e-01f, +2.118117885e-01f, -1.072634322e-02f }, + { -5.953898467e-02f, +8.600856199e-01f, +2.120920245e-01f, -1.074632015e-02f }, + { -5.954267617e-02f, +8.598326146e-01f, +2.123723915e-01f, -1.076631747e-02f }, + { -5.954629343e-02f, +8.595794240e-01f, +2.126528894e-01f, -1.078633519e-02f }, + { -5.954983652e-02f, +8.593260484e-01f, +2.129335181e-01f, -1.080637331e-02f }, + { -5.955330554e-02f, +8.590724878e-01f, +2.132142776e-01f, -1.082643182e-02f }, + { -5.955670057e-02f, +8.588187423e-01f, +2.134951677e-01f, -1.084651073e-02f }, + { -5.956002168e-02f, +8.585648123e-01f, +2.137761883e-01f, -1.086661002e-02f }, + { -5.956326897e-02f, +8.583106977e-01f, +2.140573395e-01f, -1.088672970e-02f }, + { -5.956644252e-02f, +8.580563988e-01f, +2.143386210e-01f, -1.090686977e-02f }, + { -5.956954241e-02f, +8.578019157e-01f, +2.146200329e-01f, -1.092703022e-02f }, + { -5.957256872e-02f, +8.575472486e-01f, +2.149015750e-01f, -1.094721106e-02f }, + { -5.957552154e-02f, +8.572923976e-01f, +2.151832473e-01f, -1.096741227e-02f }, + { -5.957840096e-02f, +8.570373629e-01f, +2.154650497e-01f, -1.098763386e-02f }, + { -5.958120705e-02f, +8.567821446e-01f, +2.157469820e-01f, -1.100787583e-02f }, + { -5.958393990e-02f, +8.565267430e-01f, +2.160290443e-01f, -1.102813817e-02f }, + { -5.958659959e-02f, +8.562711580e-01f, +2.163112364e-01f, -1.104842088e-02f }, + { -5.958918621e-02f, +8.560153900e-01f, +2.165935582e-01f, -1.106872396e-02f }, + { -5.959169984e-02f, +8.557594390e-01f, +2.168760097e-01f, -1.108904740e-02f }, + { -5.959414057e-02f, +8.555033052e-01f, +2.171585908e-01f, -1.110939121e-02f }, + { -5.959650847e-02f, +8.552469888e-01f, +2.174413013e-01f, -1.112975538e-02f }, + { -5.959880364e-02f, +8.549904899e-01f, +2.177241413e-01f, -1.115013991e-02f }, + { -5.960102614e-02f, +8.547338087e-01f, +2.180071107e-01f, -1.117054480e-02f }, + { -5.960317608e-02f, +8.544769453e-01f, +2.182902092e-01f, -1.119097004e-02f }, + { -5.960525353e-02f, +8.542198999e-01f, +2.185734369e-01f, -1.121141563e-02f }, + { -5.960725858e-02f, +8.539626726e-01f, +2.188567938e-01f, -1.123188157e-02f }, + { -5.960919130e-02f, +8.537052637e-01f, +2.191402796e-01f, -1.125236786e-02f }, + { -5.961105179e-02f, +8.534476731e-01f, +2.194238943e-01f, -1.127287449e-02f }, + { -5.961284013e-02f, +8.531899012e-01f, +2.197076378e-01f, -1.129340147e-02f }, + { -5.961455639e-02f, +8.529319481e-01f, +2.199915101e-01f, -1.131394878e-02f }, + { -5.961620067e-02f, +8.526738139e-01f, +2.202755110e-01f, -1.133451643e-02f }, + { -5.961777305e-02f, +8.524154987e-01f, +2.205596406e-01f, -1.135510441e-02f }, + { -5.961927360e-02f, +8.521570028e-01f, +2.208438986e-01f, -1.137571272e-02f }, + { -5.962070242e-02f, +8.518983262e-01f, +2.211282850e-01f, -1.139634135e-02f }, + { -5.962205959e-02f, +8.516394693e-01f, +2.214127997e-01f, -1.141699032e-02f }, + { -5.962334519e-02f, +8.513804320e-01f, +2.216974426e-01f, -1.143765960e-02f }, + { -5.962455930e-02f, +8.511212145e-01f, +2.219822138e-01f, -1.145834920e-02f }, + { -5.962570201e-02f, +8.508618171e-01f, +2.222671129e-01f, -1.147905912e-02f }, + { -5.962677341e-02f, +8.506022399e-01f, +2.225521401e-01f, -1.149978935e-02f }, + { -5.962777357e-02f, +8.503424830e-01f, +2.228372951e-01f, -1.152053989e-02f }, + { -5.962870257e-02f, +8.500825465e-01f, +2.231225780e-01f, -1.154131073e-02f }, + { -5.962956051e-02f, +8.498224307e-01f, +2.234079885e-01f, -1.156210188e-02f }, + { -5.963034747e-02f, +8.495621358e-01f, +2.236935267e-01f, -1.158291333e-02f }, + { -5.963106352e-02f, +8.493016617e-01f, +2.239791925e-01f, -1.160374507e-02f }, + { -5.963170876e-02f, +8.490410088e-01f, +2.242649857e-01f, -1.162459711e-02f }, + { -5.963228326e-02f, +8.487801771e-01f, +2.245509063e-01f, -1.164546944e-02f }, + { -5.963278711e-02f, +8.485191669e-01f, +2.248369542e-01f, -1.166636205e-02f }, + { -5.963322039e-02f, +8.482579783e-01f, +2.251231293e-01f, -1.168727495e-02f }, + { -5.963358319e-02f, +8.479966114e-01f, +2.254094315e-01f, -1.170820813e-02f }, + { -5.963387559e-02f, +8.477350664e-01f, +2.256958607e-01f, -1.172916159e-02f }, + { -5.963409767e-02f, +8.474733435e-01f, +2.259824169e-01f, -1.175013531e-02f }, + { -5.963424952e-02f, +8.472114428e-01f, +2.262690999e-01f, -1.177112931e-02f }, + { -5.963433122e-02f, +8.469493644e-01f, +2.265559097e-01f, -1.179214358e-02f }, + { -5.963434285e-02f, +8.466871086e-01f, +2.268428462e-01f, -1.181317810e-02f }, + { -5.963428449e-02f, +8.464246755e-01f, +2.271299092e-01f, -1.183423289e-02f }, + { -5.963415624e-02f, +8.461620653e-01f, +2.274170988e-01f, -1.185530793e-02f }, + { -5.963395817e-02f, +8.458992780e-01f, +2.277044148e-01f, -1.187640322e-02f }, + { -5.963369036e-02f, +8.456363139e-01f, +2.279918571e-01f, -1.189751876e-02f }, + { -5.963335291e-02f, +8.453731732e-01f, +2.282794257e-01f, -1.191865455e-02f }, + { -5.963294588e-02f, +8.451098559e-01f, +2.285671204e-01f, -1.193981057e-02f }, + { -5.963246938e-02f, +8.448463623e-01f, +2.288549412e-01f, -1.196098683e-02f }, + { -5.963192347e-02f, +8.445826924e-01f, +2.291428879e-01f, -1.198218333e-02f }, + { -5.963130824e-02f, +8.443188466e-01f, +2.294309606e-01f, -1.200340005e-02f }, + { -5.963062378e-02f, +8.440548248e-01f, +2.297191590e-01f, -1.202463700e-02f }, + { -5.962987017e-02f, +8.437906274e-01f, +2.300074831e-01f, -1.204589416e-02f }, + { -5.962904749e-02f, +8.435262543e-01f, +2.302959329e-01f, -1.206717155e-02f }, + { -5.962815583e-02f, +8.432617059e-01f, +2.305845082e-01f, -1.208846914e-02f }, + { -5.962719526e-02f, +8.429969822e-01f, +2.308732090e-01f, -1.210978695e-02f }, + { -5.962616588e-02f, +8.427320835e-01f, +2.311620351e-01f, -1.213112496e-02f }, + { -5.962506776e-02f, +8.424670098e-01f, +2.314509865e-01f, -1.215248317e-02f }, + { -5.962390099e-02f, +8.422017613e-01f, +2.317400630e-01f, -1.217386158e-02f }, + { -5.962266566e-02f, +8.419363383e-01f, +2.320292646e-01f, -1.219526018e-02f }, + { -5.962136183e-02f, +8.416707408e-01f, +2.323185913e-01f, -1.221667896e-02f }, + { -5.961998961e-02f, +8.414049690e-01f, +2.326080428e-01f, -1.223811793e-02f }, + { -5.961854906e-02f, +8.411390231e-01f, +2.328976192e-01f, -1.225957708e-02f }, + { -5.961704028e-02f, +8.408729033e-01f, +2.331873202e-01f, -1.228105640e-02f }, + { -5.961546335e-02f, +8.406066096e-01f, +2.334771460e-01f, -1.230255589e-02f }, + { -5.961381834e-02f, +8.403401423e-01f, +2.337670962e-01f, -1.232407555e-02f }, + { -5.961210535e-02f, +8.400735015e-01f, +2.340571709e-01f, -1.234561537e-02f }, + { -5.961032446e-02f, +8.398066874e-01f, +2.343473700e-01f, -1.236717535e-02f }, + { -5.960847575e-02f, +8.395397001e-01f, +2.346376934e-01f, -1.238875548e-02f }, + { -5.960655929e-02f, +8.392725398e-01f, +2.349281409e-01f, -1.241035575e-02f }, + { -5.960457519e-02f, +8.390052067e-01f, +2.352187125e-01f, -1.243197617e-02f }, + { -5.960252351e-02f, +8.387377009e-01f, +2.355094081e-01f, -1.245361672e-02f }, + { -5.960040434e-02f, +8.384700225e-01f, +2.358002277e-01f, -1.247527741e-02f }, + { -5.959821777e-02f, +8.382021718e-01f, +2.360911710e-01f, -1.249695823e-02f }, + { -5.959596388e-02f, +8.379341490e-01f, +2.363822381e-01f, -1.251865917e-02f }, + { -5.959364274e-02f, +8.376659540e-01f, +2.366734288e-01f, -1.254038023e-02f }, + { -5.959125445e-02f, +8.373975872e-01f, +2.369647431e-01f, -1.256212141e-02f }, + { -5.958879909e-02f, +8.371290487e-01f, +2.372561808e-01f, -1.258388269e-02f }, + { -5.958627674e-02f, +8.368603387e-01f, +2.375477418e-01f, -1.260566408e-02f }, + { -5.958368747e-02f, +8.365914572e-01f, +2.378394262e-01f, -1.262746557e-02f }, + { -5.958103139e-02f, +8.363224045e-01f, +2.381312337e-01f, -1.264928715e-02f }, + { -5.957830856e-02f, +8.360531808e-01f, +2.384231642e-01f, -1.267112882e-02f }, + { -5.957551907e-02f, +8.357837861e-01f, +2.387152178e-01f, -1.269299057e-02f }, + { -5.957266301e-02f, +8.355142207e-01f, +2.390073943e-01f, -1.271487241e-02f }, + { -5.956974045e-02f, +8.352444848e-01f, +2.392996936e-01f, -1.273677432e-02f }, + { -5.956675149e-02f, +8.349745784e-01f, +2.395921155e-01f, -1.275869629e-02f }, + { -5.956369619e-02f, +8.347045017e-01f, +2.398846601e-01f, -1.278063833e-02f }, + { -5.956057466e-02f, +8.344342550e-01f, +2.401773273e-01f, -1.280260043e-02f }, + { -5.955738696e-02f, +8.341638383e-01f, +2.404701168e-01f, -1.282458258e-02f }, + { -5.955413318e-02f, +8.338932518e-01f, +2.407630287e-01f, -1.284658477e-02f }, + { -5.955081340e-02f, +8.336224957e-01f, +2.410560629e-01f, -1.286860701e-02f }, + { -5.954742771e-02f, +8.333515702e-01f, +2.413492191e-01f, -1.289064929e-02f }, + { -5.954397620e-02f, +8.330804754e-01f, +2.416424975e-01f, -1.291271159e-02f }, + { -5.954045893e-02f, +8.328092115e-01f, +2.419358978e-01f, -1.293479392e-02f }, + { -5.953687600e-02f, +8.325377786e-01f, +2.422294200e-01f, -1.295689627e-02f }, + { -5.953322748e-02f, +8.322661770e-01f, +2.425230639e-01f, -1.297901864e-02f }, + { -5.952951347e-02f, +8.319944067e-01f, +2.428168296e-01f, -1.300116101e-02f }, + { -5.952573404e-02f, +8.317224679e-01f, +2.431107168e-01f, -1.302332339e-02f }, + { -5.952188928e-02f, +8.314503608e-01f, +2.434047255e-01f, -1.304550576e-02f }, + { -5.951797926e-02f, +8.311780856e-01f, +2.436988556e-01f, -1.306770813e-02f }, + { -5.951400408e-02f, +8.309056424e-01f, +2.439931070e-01f, -1.308993048e-02f }, + { -5.950996381e-02f, +8.306330313e-01f, +2.442874796e-01f, -1.311217281e-02f }, + { -5.950585853e-02f, +8.303602527e-01f, +2.445819733e-01f, -1.313443511e-02f }, + { -5.950168834e-02f, +8.300873065e-01f, +2.448765881e-01f, -1.315671739e-02f }, + { -5.949745330e-02f, +8.298141930e-01f, +2.451713237e-01f, -1.317901962e-02f }, + { -5.949315351e-02f, +8.295409124e-01f, +2.454661802e-01f, -1.320134181e-02f }, + { -5.948878905e-02f, +8.292674647e-01f, +2.457611574e-01f, -1.322368395e-02f }, + { -5.948436000e-02f, +8.289938502e-01f, +2.460562553e-01f, -1.324604604e-02f }, + { -5.947986644e-02f, +8.287200691e-01f, +2.463514737e-01f, -1.326842806e-02f }, + { -5.947530845e-02f, +8.284461214e-01f, +2.466468125e-01f, -1.329083001e-02f }, + { -5.947068612e-02f, +8.281720074e-01f, +2.469422717e-01f, -1.331325190e-02f }, + { -5.946599953e-02f, +8.278977272e-01f, +2.472378511e-01f, -1.333569370e-02f }, + { -5.946124877e-02f, +8.276232810e-01f, +2.475335507e-01f, -1.335815541e-02f }, + { -5.945643390e-02f, +8.273486689e-01f, +2.478293703e-01f, -1.338063703e-02f }, + { -5.945155503e-02f, +8.270738912e-01f, +2.481253099e-01f, -1.340313855e-02f }, + { -5.944661222e-02f, +8.267989479e-01f, +2.484213694e-01f, -1.342565996e-02f }, + { -5.944160557e-02f, +8.265238393e-01f, +2.487175486e-01f, -1.344820127e-02f }, + { -5.943653515e-02f, +8.262485655e-01f, +2.490138475e-01f, -1.347076245e-02f }, + { -5.943140104e-02f, +8.259731267e-01f, +2.493102660e-01f, -1.349334351e-02f }, + { -5.942620334e-02f, +8.256975230e-01f, +2.496068040e-01f, -1.351594444e-02f }, + { -5.942094212e-02f, +8.254217546e-01f, +2.499034613e-01f, -1.353856523e-02f }, + { -5.941561746e-02f, +8.251458217e-01f, +2.502002379e-01f, -1.356120587e-02f }, + { -5.941022944e-02f, +8.248697244e-01f, +2.504971337e-01f, -1.358386636e-02f }, + { -5.940477816e-02f, +8.245934629e-01f, +2.507941486e-01f, -1.360654670e-02f }, + { -5.939926369e-02f, +8.243170373e-01f, +2.510912825e-01f, -1.362924687e-02f }, + { -5.939368611e-02f, +8.240404479e-01f, +2.513885353e-01f, -1.365196686e-02f }, + { -5.938804550e-02f, +8.237636948e-01f, +2.516859068e-01f, -1.367470668e-02f }, + { -5.938234196e-02f, +8.234867781e-01f, +2.519833971e-01f, -1.369746632e-02f }, + { -5.937657555e-02f, +8.232096981e-01f, +2.522810059e-01f, -1.372024576e-02f }, + { -5.937074636e-02f, +8.229324548e-01f, +2.525787333e-01f, -1.374304500e-02f }, + { -5.936485448e-02f, +8.226550485e-01f, +2.528765790e-01f, -1.376586404e-02f }, + { -5.935889999e-02f, +8.223774794e-01f, +2.531745431e-01f, -1.378870286e-02f }, + { -5.935288297e-02f, +8.220997475e-01f, +2.534726253e-01f, -1.381156147e-02f }, + { -5.934680349e-02f, +8.218218531e-01f, +2.537708257e-01f, -1.383443984e-02f }, + { -5.934066165e-02f, +8.215437962e-01f, +2.540691440e-01f, -1.385733799e-02f }, + { -5.933445753e-02f, +8.212655772e-01f, +2.543675803e-01f, -1.388025589e-02f }, + { -5.932819120e-02f, +8.209871961e-01f, +2.546661344e-01f, -1.390319354e-02f }, + { -5.932186275e-02f, +8.207086532e-01f, +2.549648062e-01f, -1.392615094e-02f }, + { -5.931547226e-02f, +8.204299485e-01f, +2.552635955e-01f, -1.394912807e-02f }, + { -5.930901982e-02f, +8.201510823e-01f, +2.555625024e-01f, -1.397212493e-02f }, + { -5.930250550e-02f, +8.198720547e-01f, +2.558615267e-01f, -1.399514152e-02f }, + { -5.929592939e-02f, +8.195928658e-01f, +2.561606683e-01f, -1.401817782e-02f }, + { -5.928929157e-02f, +8.193135159e-01f, +2.564599271e-01f, -1.404123383e-02f }, + { -5.928259213e-02f, +8.190340052e-01f, +2.567593031e-01f, -1.406430953e-02f }, + { -5.927583113e-02f, +8.187543337e-01f, +2.570587960e-01f, -1.408740493e-02f }, + { -5.926900867e-02f, +8.184745017e-01f, +2.573584058e-01f, -1.411052002e-02f }, + { -5.926212483e-02f, +8.181945092e-01f, +2.576581325e-01f, -1.413365478e-02f }, + { -5.925517969e-02f, +8.179143566e-01f, +2.579579758e-01f, -1.415680921e-02f }, + { -5.924817333e-02f, +8.176340439e-01f, +2.582579358e-01f, -1.417998331e-02f }, + { -5.924110584e-02f, +8.173535714e-01f, +2.585580122e-01f, -1.420317705e-02f }, + { -5.923397729e-02f, +8.170729391e-01f, +2.588582051e-01f, -1.422639045e-02f }, + { -5.922678777e-02f, +8.167921473e-01f, +2.591585142e-01f, -1.424962348e-02f }, + { -5.921953735e-02f, +8.165111960e-01f, +2.594589396e-01f, -1.427287614e-02f }, + { -5.921222613e-02f, +8.162300856e-01f, +2.597594810e-01f, -1.429614843e-02f }, + { -5.920485418e-02f, +8.159488162e-01f, +2.600601385e-01f, -1.431944033e-02f }, + { -5.919742158e-02f, +8.156673878e-01f, +2.603609118e-01f, -1.434275184e-02f }, + { -5.918992842e-02f, +8.153858007e-01f, +2.606618010e-01f, -1.436608295e-02f }, + { -5.918237478e-02f, +8.151040551e-01f, +2.609628058e-01f, -1.438943365e-02f }, + { -5.917476074e-02f, +8.148221512e-01f, +2.612639263e-01f, -1.441280393e-02f }, + { -5.916708638e-02f, +8.145400890e-01f, +2.615651622e-01f, -1.443619379e-02f }, + { -5.915935179e-02f, +8.142578688e-01f, +2.618665135e-01f, -1.445960321e-02f }, + { -5.915155704e-02f, +8.139754907e-01f, +2.621679801e-01f, -1.448303220e-02f }, + { -5.914370221e-02f, +8.136929549e-01f, +2.624695618e-01f, -1.450648073e-02f }, + { -5.913578740e-02f, +8.134102615e-01f, +2.627712587e-01f, -1.452994881e-02f }, + { -5.912781267e-02f, +8.131274108e-01f, +2.630730705e-01f, -1.455343641e-02f }, + { -5.911977812e-02f, +8.128444029e-01f, +2.633749972e-01f, -1.457694355e-02f }, + { -5.911168382e-02f, +8.125612380e-01f, +2.636770386e-01f, -1.460047020e-02f }, + { -5.910352985e-02f, +8.122779162e-01f, +2.639791948e-01f, -1.462401636e-02f }, + { -5.909531630e-02f, +8.119944377e-01f, +2.642814655e-01f, -1.464758202e-02f }, + { -5.908704325e-02f, +8.117108027e-01f, +2.645838506e-01f, -1.467116717e-02f }, + { -5.907871078e-02f, +8.114270114e-01f, +2.648863501e-01f, -1.469477181e-02f }, + { -5.907031897e-02f, +8.111430638e-01f, +2.651889639e-01f, -1.471839591e-02f }, + { -5.906186790e-02f, +8.108589603e-01f, +2.654916918e-01f, -1.474203949e-02f }, + { -5.905335765e-02f, +8.105747008e-01f, +2.657945338e-01f, -1.476570252e-02f }, + { -5.904478831e-02f, +8.102902857e-01f, +2.660974897e-01f, -1.478938500e-02f }, + { -5.903615996e-02f, +8.100057151e-01f, +2.664005594e-01f, -1.481308692e-02f }, + { -5.902747268e-02f, +8.097209892e-01f, +2.667037429e-01f, -1.483680827e-02f }, + { -5.901872654e-02f, +8.094361081e-01f, +2.670070400e-01f, -1.486054904e-02f }, + { -5.900992164e-02f, +8.091510719e-01f, +2.673104506e-01f, -1.488430923e-02f }, + { -5.900105805e-02f, +8.088658810e-01f, +2.676139746e-01f, -1.490808882e-02f }, + { -5.899213585e-02f, +8.085805354e-01f, +2.679176120e-01f, -1.493188780e-02f }, + { -5.898315513e-02f, +8.082950352e-01f, +2.682213626e-01f, -1.495570618e-02f }, + { -5.897411596e-02f, +8.080093808e-01f, +2.685252263e-01f, -1.497954392e-02f }, + { -5.896501843e-02f, +8.077235722e-01f, +2.688292029e-01f, -1.500340104e-02f }, + { -5.895586262e-02f, +8.074376096e-01f, +2.691332925e-01f, -1.502727751e-02f }, + { -5.894664861e-02f, +8.071514932e-01f, +2.694374949e-01f, -1.505117334e-02f }, + { -5.893737648e-02f, +8.068652231e-01f, +2.697418099e-01f, -1.507508850e-02f }, + { -5.892804632e-02f, +8.065787996e-01f, +2.700462376e-01f, -1.509902300e-02f }, + { -5.891865819e-02f, +8.062922227e-01f, +2.703507777e-01f, -1.512297682e-02f }, + { -5.890921220e-02f, +8.060054928e-01f, +2.706554301e-01f, -1.514694995e-02f }, + { -5.889970841e-02f, +8.057186098e-01f, +2.709601949e-01f, -1.517094238e-02f }, + { -5.889014690e-02f, +8.054315741e-01f, +2.712650718e-01f, -1.519495411e-02f }, + { -5.888052777e-02f, +8.051443857e-01f, +2.715700607e-01f, -1.521898512e-02f }, + { -5.887085108e-02f, +8.048570449e-01f, +2.718751616e-01f, -1.524303541e-02f }, + { -5.886111692e-02f, +8.045695518e-01f, +2.721803743e-01f, -1.526710496e-02f }, + { -5.885132538e-02f, +8.042819066e-01f, +2.724856987e-01f, -1.529119377e-02f }, + { -5.884147653e-02f, +8.039941094e-01f, +2.727911348e-01f, -1.531530183e-02f }, + { -5.883157045e-02f, +8.037061604e-01f, +2.730966824e-01f, -1.533942912e-02f }, + { -5.882160722e-02f, +8.034180599e-01f, +2.734023414e-01f, -1.536357563e-02f }, + { -5.881158693e-02f, +8.031298079e-01f, +2.737081117e-01f, -1.538774137e-02f }, + { -5.880150966e-02f, +8.028414047e-01f, +2.740139932e-01f, -1.541192631e-02f }, + { -5.879137549e-02f, +8.025528503e-01f, +2.743199858e-01f, -1.543613045e-02f }, + { -5.878118449e-02f, +8.022641451e-01f, +2.746260894e-01f, -1.546035377e-02f }, + { -5.877093675e-02f, +8.019752891e-01f, +2.749323038e-01f, -1.548459628e-02f }, + { -5.876063235e-02f, +8.016862825e-01f, +2.752386291e-01f, -1.550885795e-02f }, + { -5.875027137e-02f, +8.013971255e-01f, +2.755450649e-01f, -1.553313878e-02f }, + { -5.873985390e-02f, +8.011078183e-01f, +2.758516114e-01f, -1.555743875e-02f }, + { -5.872938000e-02f, +8.008183610e-01f, +2.761582682e-01f, -1.558175787e-02f }, + { -5.871884977e-02f, +8.005287538e-01f, +2.764650354e-01f, -1.560609611e-02f }, + { -5.870826329e-02f, +8.002389969e-01f, +2.767719129e-01f, -1.563045347e-02f }, + { -5.869762062e-02f, +7.999490904e-01f, +2.770789004e-01f, -1.565482993e-02f }, + { -5.868692187e-02f, +7.996590346e-01f, +2.773859980e-01f, -1.567922549e-02f }, + { -5.867616710e-02f, +7.993688295e-01f, +2.776932054e-01f, -1.570364014e-02f }, + { -5.866535639e-02f, +7.990784754e-01f, +2.780005227e-01f, -1.572807386e-02f }, + { -5.865448983e-02f, +7.987879725e-01f, +2.783079496e-01f, -1.575252665e-02f }, + { -5.864356750e-02f, +7.984973209e-01f, +2.786154861e-01f, -1.577699850e-02f }, + { -5.863258948e-02f, +7.982065207e-01f, +2.789231321e-01f, -1.580148939e-02f }, + { -5.862155585e-02f, +7.979155722e-01f, +2.792308874e-01f, -1.582599931e-02f }, + { -5.861046669e-02f, +7.976244755e-01f, +2.795387520e-01f, -1.585052826e-02f }, + { -5.859932207e-02f, +7.973332308e-01f, +2.798467258e-01f, -1.587507622e-02f }, + { -5.858812209e-02f, +7.970418383e-01f, +2.801548085e-01f, -1.589964318e-02f }, + { -5.857686682e-02f, +7.967502981e-01f, +2.804630002e-01f, -1.592422914e-02f }, + { -5.856555634e-02f, +7.964586105e-01f, +2.807713007e-01f, -1.594883407e-02f }, + { -5.855419074e-02f, +7.961667755e-01f, +2.810797098e-01f, -1.597345798e-02f }, + { -5.854277008e-02f, +7.958747933e-01f, +2.813882276e-01f, -1.599810084e-02f }, + { -5.853129446e-02f, +7.955826642e-01f, +2.816968539e-01f, -1.602276266e-02f }, + { -5.851976395e-02f, +7.952903884e-01f, +2.820055885e-01f, -1.604744341e-02f }, + { -5.850817864e-02f, +7.949979658e-01f, +2.823144314e-01f, -1.607214309e-02f }, + { -5.849653859e-02f, +7.947053969e-01f, +2.826233824e-01f, -1.609686168e-02f }, + { -5.848484391e-02f, +7.944126816e-01f, +2.829324415e-01f, -1.612159918e-02f }, + { -5.847309465e-02f, +7.941198202e-01f, +2.832416085e-01f, -1.614635558e-02f }, + { -5.846129092e-02f, +7.938268129e-01f, +2.835508833e-01f, -1.617113085e-02f }, + { -5.844943277e-02f, +7.935336599e-01f, +2.838602658e-01f, -1.619592500e-02f }, + { -5.843752031e-02f, +7.932403612e-01f, +2.841697559e-01f, -1.622073801e-02f }, + { -5.842555359e-02f, +7.929469172e-01f, +2.844793535e-01f, -1.624556986e-02f }, + { -5.841353272e-02f, +7.926533279e-01f, +2.847890584e-01f, -1.627042056e-02f }, + { -5.840145776e-02f, +7.923595935e-01f, +2.850988707e-01f, -1.629529008e-02f }, + { -5.838932879e-02f, +7.920657142e-01f, +2.854087900e-01f, -1.632017842e-02f }, + { -5.837714590e-02f, +7.917716902e-01f, +2.857188164e-01f, -1.634508556e-02f }, + { -5.836490917e-02f, +7.914775217e-01f, +2.860289498e-01f, -1.637001149e-02f }, + { -5.835261867e-02f, +7.911832088e-01f, +2.863391899e-01f, -1.639495620e-02f }, + { -5.834027449e-02f, +7.908887516e-01f, +2.866495368e-01f, -1.641991969e-02f }, + { -5.832787671e-02f, +7.905941505e-01f, +2.869599902e-01f, -1.644490193e-02f }, + { -5.831542540e-02f, +7.902994055e-01f, +2.872705501e-01f, -1.646990291e-02f }, + { -5.830292065e-02f, +7.900045168e-01f, +2.875812164e-01f, -1.649492264e-02f }, + { -5.829036253e-02f, +7.897094846e-01f, +2.878919890e-01f, -1.651996108e-02f }, + { -5.827775113e-02f, +7.894143091e-01f, +2.882028676e-01f, -1.654501824e-02f }, + { -5.826508653e-02f, +7.891189904e-01f, +2.885138523e-01f, -1.657009409e-02f }, + { -5.825236880e-02f, +7.888235287e-01f, +2.888249429e-01f, -1.659518863e-02f }, + { -5.823959802e-02f, +7.885279242e-01f, +2.891361394e-01f, -1.662030185e-02f }, + { -5.822677428e-02f, +7.882321771e-01f, +2.894474415e-01f, -1.664543373e-02f }, + { -5.821389766e-02f, +7.879362875e-01f, +2.897588491e-01f, -1.667058426e-02f }, + { -5.820096823e-02f, +7.876402556e-01f, +2.900703623e-01f, -1.669575344e-02f }, + { -5.818798608e-02f, +7.873440816e-01f, +2.903819808e-01f, -1.672094124e-02f }, + { -5.817495128e-02f, +7.870477656e-01f, +2.906937045e-01f, -1.674614765e-02f }, + { -5.816186392e-02f, +7.867513079e-01f, +2.910055333e-01f, -1.677137267e-02f }, + { -5.814872407e-02f, +7.864547086e-01f, +2.913174672e-01f, -1.679661628e-02f }, + { -5.813553181e-02f, +7.861579679e-01f, +2.916295059e-01f, -1.682187847e-02f }, + { -5.812228722e-02f, +7.858610859e-01f, +2.919416495e-01f, -1.684715923e-02f }, + { -5.810899039e-02f, +7.855640629e-01f, +2.922538976e-01f, -1.687245854e-02f }, + { -5.809564139e-02f, +7.852668990e-01f, +2.925662504e-01f, -1.689777639e-02f }, + { -5.808224030e-02f, +7.849695943e-01f, +2.928787076e-01f, -1.692311278e-02f }, + { -5.806878721e-02f, +7.846721491e-01f, +2.931912691e-01f, -1.694846768e-02f }, + { -5.805528218e-02f, +7.843745636e-01f, +2.935039348e-01f, -1.697384108e-02f }, + { -5.804172530e-02f, +7.840768378e-01f, +2.938167045e-01f, -1.699923298e-02f }, + { -5.802811666e-02f, +7.837789720e-01f, +2.941295783e-01f, -1.702464336e-02f }, + { -5.801445632e-02f, +7.834809664e-01f, +2.944425560e-01f, -1.705007220e-02f }, + { -5.800074437e-02f, +7.831828211e-01f, +2.947556373e-01f, -1.707551950e-02f }, + { -5.798698089e-02f, +7.828845363e-01f, +2.950688223e-01f, -1.710098524e-02f }, + { -5.797316596e-02f, +7.825861121e-01f, +2.953821109e-01f, -1.712646941e-02f }, + { -5.795929965e-02f, +7.822875489e-01f, +2.956955028e-01f, -1.715197200e-02f }, + { -5.794538205e-02f, +7.819888466e-01f, +2.960089980e-01f, -1.717749299e-02f }, + { -5.793141324e-02f, +7.816900056e-01f, +2.963225964e-01f, -1.720303237e-02f }, + { -5.791739329e-02f, +7.813910260e-01f, +2.966362979e-01f, -1.722859012e-02f }, + { -5.790332228e-02f, +7.810919079e-01f, +2.969501022e-01f, -1.725416625e-02f }, + { -5.788920029e-02f, +7.807926515e-01f, +2.972640094e-01f, -1.727976072e-02f }, + { -5.787502741e-02f, +7.804932570e-01f, +2.975780194e-01f, -1.730537353e-02f }, + { -5.786080371e-02f, +7.801937247e-01f, +2.978921319e-01f, -1.733100467e-02f }, + { -5.784652927e-02f, +7.798940546e-01f, +2.982063468e-01f, -1.735665412e-02f }, + { -5.783220417e-02f, +7.795942469e-01f, +2.985206642e-01f, -1.738232187e-02f }, + { -5.781782849e-02f, +7.792943018e-01f, +2.988350837e-01f, -1.740800791e-02f }, + { -5.780340230e-02f, +7.789942195e-01f, +2.991496054e-01f, -1.743371222e-02f }, + { -5.778892569e-02f, +7.786940002e-01f, +2.994642291e-01f, -1.745943479e-02f }, + { -5.777439874e-02f, +7.783936440e-01f, +2.997789547e-01f, -1.748517560e-02f }, + { -5.775982152e-02f, +7.780931511e-01f, +3.000937821e-01f, -1.751093465e-02f }, + { -5.774519411e-02f, +7.777925218e-01f, +3.004087111e-01f, -1.753671192e-02f }, + { -5.773051660e-02f, +7.774917560e-01f, +3.007237417e-01f, -1.756250739e-02f }, + { -5.771578906e-02f, +7.771908542e-01f, +3.010388736e-01f, -1.758832105e-02f }, + { -5.770101157e-02f, +7.768898163e-01f, +3.013541069e-01f, -1.761415290e-02f }, + { -5.768618420e-02f, +7.765886426e-01f, +3.016694414e-01f, -1.764000291e-02f }, + { -5.767130705e-02f, +7.762873333e-01f, +3.019848769e-01f, -1.766587107e-02f }, + { -5.765638018e-02f, +7.759858886e-01f, +3.023004134e-01f, -1.769175736e-02f }, + { -5.764140368e-02f, +7.756843086e-01f, +3.026160507e-01f, -1.771766179e-02f }, + { -5.762637762e-02f, +7.753825935e-01f, +3.029317887e-01f, -1.774358432e-02f }, + { -5.761130208e-02f, +7.750807434e-01f, +3.032476274e-01f, -1.776952495e-02f }, + { -5.759617715e-02f, +7.747787586e-01f, +3.035635665e-01f, -1.779548366e-02f }, + { -5.758100289e-02f, +7.744766393e-01f, +3.038796059e-01f, -1.782146044e-02f }, + { -5.756577939e-02f, +7.741743855e-01f, +3.041957456e-01f, -1.784745527e-02f }, + { -5.755050673e-02f, +7.738719975e-01f, +3.045119855e-01f, -1.787346814e-02f }, + { -5.753518499e-02f, +7.735694755e-01f, +3.048283253e-01f, -1.789949905e-02f }, + { -5.751981424e-02f, +7.732668197e-01f, +3.051447650e-01f, -1.792554796e-02f }, + { -5.750439457e-02f, +7.729640301e-01f, +3.054613045e-01f, -1.795161487e-02f }, + { -5.748892604e-02f, +7.726611070e-01f, +3.057779436e-01f, -1.797769977e-02f }, + { -5.747340875e-02f, +7.723580506e-01f, +3.060946822e-01f, -1.800380263e-02f }, + { -5.745784276e-02f, +7.720548611e-01f, +3.064115203e-01f, -1.802992345e-02f }, + { -5.744222816e-02f, +7.717515386e-01f, +3.067284576e-01f, -1.805606221e-02f }, + { -5.742656503e-02f, +7.714480832e-01f, +3.070454941e-01f, -1.808221890e-02f }, + { -5.741085343e-02f, +7.711444953e-01f, +3.073626297e-01f, -1.810839350e-02f }, + { -5.739509346e-02f, +7.708407749e-01f, +3.076798642e-01f, -1.813458600e-02f }, + { -5.737928519e-02f, +7.705369222e-01f, +3.079971975e-01f, -1.816079639e-02f }, + { -5.736342870e-02f, +7.702329374e-01f, +3.083146294e-01f, -1.818702464e-02f }, + { -5.734752407e-02f, +7.699288208e-01f, +3.086321600e-01f, -1.821327074e-02f }, + { -5.733157137e-02f, +7.696245724e-01f, +3.089497890e-01f, -1.823953469e-02f }, + { -5.731557068e-02f, +7.693201924e-01f, +3.092675163e-01f, -1.826581646e-02f }, + { -5.729952209e-02f, +7.690156811e-01f, +3.095853418e-01f, -1.829211604e-02f }, + { -5.728342566e-02f, +7.687110385e-01f, +3.099032654e-01f, -1.831843341e-02f }, + { -5.726728148e-02f, +7.684062649e-01f, +3.102212870e-01f, -1.834476857e-02f }, + { -5.725108962e-02f, +7.681013605e-01f, +3.105394064e-01f, -1.837112149e-02f }, + { -5.723485017e-02f, +7.677963254e-01f, +3.108576236e-01f, -1.839749217e-02f }, + { -5.721856321e-02f, +7.674911598e-01f, +3.111759383e-01f, -1.842388058e-02f }, + { -5.720222880e-02f, +7.671858639e-01f, +3.114943506e-01f, -1.845028671e-02f }, + { -5.718584702e-02f, +7.668804379e-01f, +3.118128601e-01f, -1.847671054e-02f }, + { -5.716941797e-02f, +7.665748819e-01f, +3.121314670e-01f, -1.850315207e-02f }, + { -5.715294170e-02f, +7.662691962e-01f, +3.124501709e-01f, -1.852961127e-02f }, + { -5.713641831e-02f, +7.659633808e-01f, +3.127689718e-01f, -1.855608813e-02f }, + { -5.711984787e-02f, +7.656574360e-01f, +3.130878696e-01f, -1.858258264e-02f }, + { -5.710323045e-02f, +7.653513620e-01f, +3.134068642e-01f, -1.860909478e-02f }, + { -5.708656614e-02f, +7.650451589e-01f, +3.137259554e-01f, -1.863562453e-02f }, + { -5.706985501e-02f, +7.647388269e-01f, +3.140451431e-01f, -1.866217188e-02f }, + { -5.705309714e-02f, +7.644323662e-01f, +3.143644272e-01f, -1.868873682e-02f }, + { -5.703629260e-02f, +7.641257769e-01f, +3.146838075e-01f, -1.871531932e-02f }, + { -5.701944149e-02f, +7.638190593e-01f, +3.150032840e-01f, -1.874191938e-02f }, + { -5.700254386e-02f, +7.635122136e-01f, +3.153228565e-01f, -1.876853697e-02f }, + { -5.698559981e-02f, +7.632052398e-01f, +3.156425249e-01f, -1.879517209e-02f }, + { -5.696860941e-02f, +7.628981382e-01f, +3.159622890e-01f, -1.882182471e-02f }, + { -5.695157273e-02f, +7.625909090e-01f, +3.162821488e-01f, -1.884849482e-02f }, + { -5.693448985e-02f, +7.622835524e-01f, +3.166021042e-01f, -1.887518241e-02f }, + { -5.691736086e-02f, +7.619760684e-01f, +3.169221549e-01f, -1.890188745e-02f }, + { -5.690018582e-02f, +7.616684574e-01f, +3.172423009e-01f, -1.892860994e-02f }, + { -5.688296482e-02f, +7.613607194e-01f, +3.175625421e-01f, -1.895534986e-02f }, + { -5.686569793e-02f, +7.610528546e-01f, +3.178828783e-01f, -1.898210719e-02f }, + { -5.684838523e-02f, +7.607448634e-01f, +3.182033094e-01f, -1.900888191e-02f }, + { -5.683102681e-02f, +7.604367457e-01f, +3.185238353e-01f, -1.903567401e-02f }, + { -5.681362272e-02f, +7.601285018e-01f, +3.188444558e-01f, -1.906248348e-02f }, + { -5.679617306e-02f, +7.598201319e-01f, +3.191651709e-01f, -1.908931029e-02f }, + { -5.677867790e-02f, +7.595116361e-01f, +3.194859804e-01f, -1.911615443e-02f }, + { -5.676113731e-02f, +7.592030147e-01f, +3.198068842e-01f, -1.914301589e-02f }, + { -5.674355138e-02f, +7.588942678e-01f, +3.201278822e-01f, -1.916989465e-02f }, + { -5.672592019e-02f, +7.585853955e-01f, +3.204489742e-01f, -1.919679069e-02f }, + { -5.670824380e-02f, +7.582763982e-01f, +3.207701601e-01f, -1.922370400e-02f }, + { -5.669052229e-02f, +7.579672759e-01f, +3.210914398e-01f, -1.925063455e-02f }, + { -5.667275575e-02f, +7.576580288e-01f, +3.214128132e-01f, -1.927758234e-02f }, + { -5.665494425e-02f, +7.573486571e-01f, +3.217342801e-01f, -1.930454735e-02f }, + { -5.663708786e-02f, +7.570391610e-01f, +3.220558404e-01f, -1.933152956e-02f }, + { -5.661918667e-02f, +7.567295407e-01f, +3.223774940e-01f, -1.935852895e-02f }, + { -5.660124075e-02f, +7.564197963e-01f, +3.226992408e-01f, -1.938554550e-02f }, + { -5.658325018e-02f, +7.561099280e-01f, +3.230210806e-01f, -1.941257921e-02f }, + { -5.656521503e-02f, +7.557999361e-01f, +3.233430133e-01f, -1.943963005e-02f }, + { -5.654713538e-02f, +7.554898206e-01f, +3.236650389e-01f, -1.946669801e-02f }, + { -5.652901131e-02f, +7.551795818e-01f, +3.239871571e-01f, -1.949378307e-02f }, + { -5.651084290e-02f, +7.548692198e-01f, +3.243093678e-01f, -1.952088522e-02f }, + { -5.649263022e-02f, +7.545587349e-01f, +3.246316709e-01f, -1.954800443e-02f }, + { -5.647437335e-02f, +7.542481271e-01f, +3.249540663e-01f, -1.957514069e-02f }, + { -5.645607236e-02f, +7.539373968e-01f, +3.252765539e-01f, -1.960229398e-02f }, + { -5.643772734e-02f, +7.536265440e-01f, +3.255991335e-01f, -1.962946429e-02f }, + { -5.641933835e-02f, +7.533155690e-01f, +3.259218051e-01f, -1.965665160e-02f }, + { -5.640090548e-02f, +7.530044718e-01f, +3.262445684e-01f, -1.968385589e-02f }, + { -5.638242880e-02f, +7.526932528e-01f, +3.265674233e-01f, -1.971107714e-02f }, + { -5.636390839e-02f, +7.523819121e-01f, +3.268903698e-01f, -1.973831534e-02f }, + { -5.634534432e-02f, +7.520704498e-01f, +3.272134077e-01f, -1.976557047e-02f }, + { -5.632673668e-02f, +7.517588662e-01f, +3.275365369e-01f, -1.979284251e-02f }, + { -5.630808553e-02f, +7.514471614e-01f, +3.278597572e-01f, -1.982013145e-02f }, + { -5.628939096e-02f, +7.511353356e-01f, +3.281830685e-01f, -1.984743727e-02f }, + { -5.627065304e-02f, +7.508233890e-01f, +3.285064707e-01f, -1.987475995e-02f }, + { -5.625187185e-02f, +7.505113218e-01f, +3.288299637e-01f, -1.990209947e-02f }, + { -5.623304746e-02f, +7.501991341e-01f, +3.291535473e-01f, -1.992945582e-02f }, + { -5.621417995e-02f, +7.498868261e-01f, +3.294772215e-01f, -1.995682897e-02f }, + { -5.619526939e-02f, +7.495743981e-01f, +3.298009860e-01f, -1.998421892e-02f }, + { -5.617631587e-02f, +7.492618501e-01f, +3.301248407e-01f, -2.001162564e-02f }, + { -5.615731946e-02f, +7.489491824e-01f, +3.304487856e-01f, -2.003904911e-02f }, + { -5.613828023e-02f, +7.486363951e-01f, +3.307728205e-01f, -2.006648932e-02f }, + { -5.611919827e-02f, +7.483234885e-01f, +3.310969453e-01f, -2.009394625e-02f }, + { -5.610007364e-02f, +7.480104627e-01f, +3.314211598e-01f, -2.012141988e-02f }, + { -5.608090642e-02f, +7.476973179e-01f, +3.317454639e-01f, -2.014891020e-02f }, + { -5.606169669e-02f, +7.473840543e-01f, +3.320698576e-01f, -2.017641718e-02f }, + { -5.604244453e-02f, +7.470706720e-01f, +3.323943405e-01f, -2.020394081e-02f }, + { -5.602315001e-02f, +7.467571712e-01f, +3.327189127e-01f, -2.023148107e-02f }, + { -5.600381321e-02f, +7.464435522e-01f, +3.330435740e-01f, -2.025903794e-02f }, + { -5.598443420e-02f, +7.461298151e-01f, +3.333683243e-01f, -2.028661141e-02f }, + { -5.596501306e-02f, +7.458159600e-01f, +3.336931634e-01f, -2.031420145e-02f }, + { -5.594554986e-02f, +7.455019872e-01f, +3.340180912e-01f, -2.034180804e-02f }, + { -5.592604469e-02f, +7.451878969e-01f, +3.343431076e-01f, -2.036943118e-02f }, + { -5.590649761e-02f, +7.448736891e-01f, +3.346682125e-01f, -2.039707084e-02f }, + { -5.588690871e-02f, +7.445593642e-01f, +3.349934057e-01f, -2.042472700e-02f }, + { -5.586727805e-02f, +7.442449222e-01f, +3.353186871e-01f, -2.045239964e-02f }, + { -5.584760571e-02f, +7.439303635e-01f, +3.356440565e-01f, -2.048008875e-02f }, + { -5.582789178e-02f, +7.436156880e-01f, +3.359695139e-01f, -2.050779431e-02f }, + { -5.580813632e-02f, +7.433008961e-01f, +3.362950591e-01f, -2.053551629e-02f }, + { -5.578833941e-02f, +7.429859879e-01f, +3.366206920e-01f, -2.056325469e-02f }, + { -5.576850113e-02f, +7.426709636e-01f, +3.369464124e-01f, -2.059100947e-02f }, + { -5.574862155e-02f, +7.423558234e-01f, +3.372722202e-01f, -2.061878063e-02f }, + { -5.572870075e-02f, +7.420405674e-01f, +3.375981153e-01f, -2.064656814e-02f }, + { -5.570873880e-02f, +7.417251959e-01f, +3.379240976e-01f, -2.067437199e-02f }, + { -5.568873578e-02f, +7.414097090e-01f, +3.382501669e-01f, -2.070219216e-02f }, + { -5.566869176e-02f, +7.410941069e-01f, +3.385763231e-01f, -2.073002862e-02f }, + { -5.564860682e-02f, +7.407783897e-01f, +3.389025660e-01f, -2.075788136e-02f }, + { -5.562848104e-02f, +7.404625577e-01f, +3.392288956e-01f, -2.078575035e-02f }, + { -5.560831448e-02f, +7.401466111e-01f, +3.395553117e-01f, -2.081363559e-02f }, + { -5.558810723e-02f, +7.398305500e-01f, +3.398818142e-01f, -2.084153705e-02f }, + { -5.556785936e-02f, +7.395143746e-01f, +3.402084029e-01f, -2.086945472e-02f }, + { -5.554757095e-02f, +7.391980851e-01f, +3.405350777e-01f, -2.089738856e-02f }, + { -5.552724207e-02f, +7.388816817e-01f, +3.408618385e-01f, -2.092533857e-02f }, + { -5.550687279e-02f, +7.385651645e-01f, +3.411886851e-01f, -2.095330472e-02f }, + { -5.548646320e-02f, +7.382485338e-01f, +3.415156174e-01f, -2.098128700e-02f }, + { -5.546601336e-02f, +7.379317896e-01f, +3.418426354e-01f, -2.100928539e-02f }, + { -5.544552335e-02f, +7.376149323e-01f, +3.421697387e-01f, -2.103729986e-02f }, + { -5.542499324e-02f, +7.372979620e-01f, +3.424969274e-01f, -2.106533040e-02f }, + { -5.540442312e-02f, +7.369808788e-01f, +3.428242013e-01f, -2.109337699e-02f }, + { -5.538381306e-02f, +7.366636830e-01f, +3.431515602e-01f, -2.112143960e-02f }, + { -5.536316312e-02f, +7.363463747e-01f, +3.434790041e-01f, -2.114951822e-02f }, + { -5.534247339e-02f, +7.360289541e-01f, +3.438065327e-01f, -2.117761283e-02f }, + { -5.532174395e-02f, +7.357114214e-01f, +3.441341461e-01f, -2.120572342e-02f }, + { -5.530097485e-02f, +7.353937768e-01f, +3.444618439e-01f, -2.123384995e-02f }, + { -5.528016619e-02f, +7.350760204e-01f, +3.447896261e-01f, -2.126199241e-02f }, + { -5.525931803e-02f, +7.347581525e-01f, +3.451174926e-01f, -2.129015078e-02f }, + { -5.523843046e-02f, +7.344401732e-01f, +3.454454432e-01f, -2.131832504e-02f }, + { -5.521750353e-02f, +7.341220827e-01f, +3.457734778e-01f, -2.134651517e-02f }, + { -5.519653734e-02f, +7.338038812e-01f, +3.461015962e-01f, -2.137472115e-02f }, + { -5.517553195e-02f, +7.334855689e-01f, +3.464297984e-01f, -2.140294296e-02f }, + { -5.515448744e-02f, +7.331671459e-01f, +3.467580842e-01f, -2.143118058e-02f }, + { -5.513340388e-02f, +7.328486125e-01f, +3.470864534e-01f, -2.145943399e-02f }, + { -5.511228134e-02f, +7.325299688e-01f, +3.474149060e-01f, -2.148770317e-02f }, + { -5.509111991e-02f, +7.322112150e-01f, +3.477434418e-01f, -2.151598810e-02f }, + { -5.506991966e-02f, +7.318923513e-01f, +3.480720606e-01f, -2.154428875e-02f }, + { -5.504868065e-02f, +7.315733778e-01f, +3.484007623e-01f, -2.157260512e-02f }, + { -5.502740298e-02f, +7.312542948e-01f, +3.487295469e-01f, -2.160093718e-02f }, + { -5.500608670e-02f, +7.309351024e-01f, +3.490584141e-01f, -2.162928490e-02f }, + { -5.498473189e-02f, +7.306158008e-01f, +3.493873638e-01f, -2.165764827e-02f }, + { -5.496333863e-02f, +7.302963903e-01f, +3.497163959e-01f, -2.168602727e-02f }, + { -5.494190699e-02f, +7.299768709e-01f, +3.500455102e-01f, -2.171442188e-02f }, + { -5.492043705e-02f, +7.296572429e-01f, +3.503747067e-01f, -2.174283207e-02f }, + { -5.489892888e-02f, +7.293375064e-01f, +3.507039852e-01f, -2.177125783e-02f }, + { -5.487738256e-02f, +7.290176616e-01f, +3.510333455e-01f, -2.179969913e-02f }, + { -5.485579815e-02f, +7.286977088e-01f, +3.513627875e-01f, -2.182815596e-02f }, + { -5.483417574e-02f, +7.283776481e-01f, +3.516923111e-01f, -2.185662829e-02f }, + { -5.481251539e-02f, +7.280574796e-01f, +3.520219162e-01f, -2.188511610e-02f }, + { -5.479081718e-02f, +7.277372036e-01f, +3.523516026e-01f, -2.191361938e-02f }, + { -5.476908119e-02f, +7.274168203e-01f, +3.526813701e-01f, -2.194213809e-02f }, + { -5.474730748e-02f, +7.270963298e-01f, +3.530112187e-01f, -2.197067223e-02f }, + { -5.472549614e-02f, +7.267757323e-01f, +3.533411482e-01f, -2.199922176e-02f }, + { -5.470364724e-02f, +7.264550280e-01f, +3.536711584e-01f, -2.202778667e-02f }, + { -5.468176084e-02f, +7.261342170e-01f, +3.540012493e-01f, -2.205636694e-02f }, + { -5.465983703e-02f, +7.258132997e-01f, +3.543314207e-01f, -2.208496254e-02f }, + { -5.463787587e-02f, +7.254922761e-01f, +3.546616725e-01f, -2.211357346e-02f }, + { -5.461587745e-02f, +7.251711464e-01f, +3.549920045e-01f, -2.214219967e-02f }, + { -5.459384183e-02f, +7.248499108e-01f, +3.553224165e-01f, -2.217084115e-02f }, + { -5.457176909e-02f, +7.245285695e-01f, +3.556529085e-01f, -2.219949788e-02f }, + { -5.454965931e-02f, +7.242071227e-01f, +3.559834804e-01f, -2.222816984e-02f }, + { -5.452751254e-02f, +7.238855706e-01f, +3.563141319e-01f, -2.225685701e-02f }, + { -5.450532888e-02f, +7.235639133e-01f, +3.566448630e-01f, -2.228555936e-02f }, + { -5.448310839e-02f, +7.232421510e-01f, +3.569756734e-01f, -2.231427688e-02f }, + { -5.446085115e-02f, +7.229202840e-01f, +3.573065632e-01f, -2.234300954e-02f }, + { -5.443855722e-02f, +7.225983123e-01f, +3.576375321e-01f, -2.237175733e-02f }, + { -5.441622669e-02f, +7.222762363e-01f, +3.579685799e-01f, -2.240052021e-02f }, + { -5.439385962e-02f, +7.219540560e-01f, +3.582997067e-01f, -2.242929816e-02f }, + { -5.437145610e-02f, +7.216317716e-01f, +3.586309121e-01f, -2.245809118e-02f }, + { -5.434901618e-02f, +7.213093834e-01f, +3.589621962e-01f, -2.248689923e-02f }, + { -5.432653996e-02f, +7.209868915e-01f, +3.592935587e-01f, -2.251572229e-02f }, + { -5.430402749e-02f, +7.206642961e-01f, +3.596249995e-01f, -2.254456034e-02f }, + { -5.428147885e-02f, +7.203415974e-01f, +3.599565185e-01f, -2.257341336e-02f }, + { -5.425889412e-02f, +7.200187955e-01f, +3.602881155e-01f, -2.260228132e-02f }, + { -5.423627337e-02f, +7.196958907e-01f, +3.606197904e-01f, -2.263116421e-02f }, + { -5.421361667e-02f, +7.193728831e-01f, +3.609515431e-01f, -2.266006200e-02f }, + { -5.419092410e-02f, +7.190497730e-01f, +3.612833734e-01f, -2.268897467e-02f }, + { -5.416819572e-02f, +7.187265605e-01f, +3.616152812e-01f, -2.271790220e-02f }, + { -5.414543161e-02f, +7.184032457e-01f, +3.619472663e-01f, -2.274684456e-02f }, + { -5.412263185e-02f, +7.180798289e-01f, +3.622793287e-01f, -2.277580174e-02f }, + { -5.409979650e-02f, +7.177563103e-01f, +3.626114681e-01f, -2.280477371e-02f }, + { -5.407692564e-02f, +7.174326900e-01f, +3.629436844e-01f, -2.283376044e-02f }, + { -5.405401935e-02f, +7.171089682e-01f, +3.632759775e-01f, -2.286276192e-02f }, + { -5.403107768e-02f, +7.167851452e-01f, +3.636083473e-01f, -2.289177812e-02f }, + { -5.400810073e-02f, +7.164612210e-01f, +3.639407936e-01f, -2.292080903e-02f }, + { -5.398508856e-02f, +7.161371959e-01f, +3.642733163e-01f, -2.294985461e-02f }, + { -5.396204124e-02f, +7.158130701e-01f, +3.646059152e-01f, -2.297891485e-02f }, + { -5.393895884e-02f, +7.154888437e-01f, +3.649385903e-01f, -2.300798972e-02f }, + { -5.391584144e-02f, +7.151645170e-01f, +3.652713412e-01f, -2.303707919e-02f }, + { -5.389268911e-02f, +7.148400900e-01f, +3.656041680e-01f, -2.306618326e-02f }, + { -5.386950193e-02f, +7.145155631e-01f, +3.659370705e-01f, -2.309530189e-02f }, + { -5.384627996e-02f, +7.141909364e-01f, +3.662700485e-01f, -2.312443506e-02f }, + { -5.382302328e-02f, +7.138662100e-01f, +3.666031020e-01f, -2.315358275e-02f }, + { -5.379973196e-02f, +7.135413841e-01f, +3.669362306e-01f, -2.318274493e-02f }, + { -5.377640607e-02f, +7.132164590e-01f, +3.672694344e-01f, -2.321192159e-02f }, + { -5.375304569e-02f, +7.128914348e-01f, +3.676027132e-01f, -2.324111270e-02f }, + { -5.372965088e-02f, +7.125663118e-01f, +3.679360669e-01f, -2.327031823e-02f }, + { -5.370622173e-02f, +7.122410900e-01f, +3.682694952e-01f, -2.329953816e-02f }, + { -5.368275829e-02f, +7.119157697e-01f, +3.686029981e-01f, -2.332877247e-02f }, + { -5.365926065e-02f, +7.115903510e-01f, +3.689365754e-01f, -2.335802114e-02f }, + { -5.363572888e-02f, +7.112648342e-01f, +3.692702270e-01f, -2.338728414e-02f }, + { -5.361216304e-02f, +7.109392194e-01f, +3.696039527e-01f, -2.341656145e-02f }, + { -5.358856321e-02f, +7.106135068e-01f, +3.699377525e-01f, -2.344585305e-02f }, + { -5.356492947e-02f, +7.102876966e-01f, +3.702716261e-01f, -2.347515891e-02f }, + { -5.354126188e-02f, +7.099617891e-01f, +3.706055734e-01f, -2.350447901e-02f }, + { -5.351756051e-02f, +7.096357842e-01f, +3.709395943e-01f, -2.353381332e-02f }, + { -5.349382545e-02f, +7.093096823e-01f, +3.712736886e-01f, -2.356316182e-02f }, + { -5.347005675e-02f, +7.089834836e-01f, +3.716078562e-01f, -2.359252450e-02f }, + { -5.344625449e-02f, +7.086571882e-01f, +3.719420970e-01f, -2.362190131e-02f }, + { -5.342241875e-02f, +7.083307963e-01f, +3.722764108e-01f, -2.365129225e-02f }, + { -5.339854959e-02f, +7.080043080e-01f, +3.726107975e-01f, -2.368069728e-02f }, + { -5.337464709e-02f, +7.076777237e-01f, +3.729452569e-01f, -2.371011639e-02f }, + { -5.335071132e-02f, +7.073510434e-01f, +3.732797888e-01f, -2.373954954e-02f }, + { -5.332674235e-02f, +7.070242673e-01f, +3.736143933e-01f, -2.376899672e-02f }, + { -5.330274025e-02f, +7.066973957e-01f, +3.739490700e-01f, -2.379845790e-02f }, + { -5.327870509e-02f, +7.063704287e-01f, +3.742838189e-01f, -2.382793305e-02f }, + { -5.325463695e-02f, +7.060433665e-01f, +3.746186398e-01f, -2.385742216e-02f }, + { -5.323053590e-02f, +7.057162093e-01f, +3.749535326e-01f, -2.388692520e-02f }, + { -5.320640200e-02f, +7.053889572e-01f, +3.752884971e-01f, -2.391644214e-02f }, + { -5.318223533e-02f, +7.050616105e-01f, +3.756235333e-01f, -2.394597296e-02f }, + { -5.315803596e-02f, +7.047341694e-01f, +3.759586408e-01f, -2.397551763e-02f }, + { -5.313380397e-02f, +7.044066339e-01f, +3.762938197e-01f, -2.400507614e-02f }, + { -5.310953941e-02f, +7.040790044e-01f, +3.766290698e-01f, -2.403464845e-02f }, + { -5.308524237e-02f, +7.037512810e-01f, +3.769643909e-01f, -2.406423454e-02f }, + { -5.306091292e-02f, +7.034234638e-01f, +3.772997828e-01f, -2.409383439e-02f }, + { -5.303655112e-02f, +7.030955531e-01f, +3.776352455e-01f, -2.412344797e-02f }, + { -5.301215705e-02f, +7.027675491e-01f, +3.779707788e-01f, -2.415307527e-02f }, + { -5.298773078e-02f, +7.024394519e-01f, +3.783063825e-01f, -2.418271624e-02f }, + { -5.296327238e-02f, +7.021112617e-01f, +3.786420566e-01f, -2.421237087e-02f }, + { -5.293878193e-02f, +7.017829788e-01f, +3.789778008e-01f, -2.424203914e-02f }, + { -5.291425948e-02f, +7.014546032e-01f, +3.793136151e-01f, -2.427172102e-02f }, + { -5.288970511e-02f, +7.011261352e-01f, +3.796494992e-01f, -2.430141648e-02f }, + { -5.286511890e-02f, +7.007975749e-01f, +3.799854530e-01f, -2.433112550e-02f }, + { -5.284050092e-02f, +7.004689226e-01f, +3.803214765e-01f, -2.436084805e-02f }, + { -5.281585123e-02f, +7.001401785e-01f, +3.806575694e-01f, -2.439058412e-02f }, + { -5.279116991e-02f, +6.998113426e-01f, +3.809937316e-01f, -2.442033366e-02f }, + { -5.276645702e-02f, +6.994824153e-01f, +3.813299629e-01f, -2.445009667e-02f }, + { -5.274171264e-02f, +6.991533966e-01f, +3.816662633e-01f, -2.447987311e-02f }, + { -5.271693684e-02f, +6.988242869e-01f, +3.820026325e-01f, -2.450966296e-02f }, + { -5.269212969e-02f, +6.984950861e-01f, +3.823390705e-01f, -2.453946619e-02f }, + { -5.266729126e-02f, +6.981657947e-01f, +3.826755771e-01f, -2.456928278e-02f }, + { -5.264242161e-02f, +6.978364126e-01f, +3.830121520e-01f, -2.459911271e-02f }, + { -5.261752083e-02f, +6.975069402e-01f, +3.833487953e-01f, -2.462895594e-02f }, + { -5.259258898e-02f, +6.971773775e-01f, +3.836855068e-01f, -2.465881245e-02f }, + { -5.256762613e-02f, +6.968477249e-01f, +3.840222862e-01f, -2.468868221e-02f }, + { -5.254263236e-02f, +6.965179824e-01f, +3.843591335e-01f, -2.471856521e-02f }, + { -5.251760772e-02f, +6.961881503e-01f, +3.846960485e-01f, -2.474846141e-02f }, + { -5.249255230e-02f, +6.958582288e-01f, +3.850330311e-01f, -2.477837080e-02f }, + { -5.246746616e-02f, +6.955282179e-01f, +3.853700811e-01f, -2.480829333e-02f }, + { -5.244234938e-02f, +6.951981180e-01f, +3.857071983e-01f, -2.483822900e-02f }, + { -5.241720201e-02f, +6.948679292e-01f, +3.860443828e-01f, -2.486817776e-02f }, + { -5.239202415e-02f, +6.945376516e-01f, +3.863816342e-01f, -2.489813960e-02f }, + { -5.236681584e-02f, +6.942072855e-01f, +3.867189524e-01f, -2.492811449e-02f }, + { -5.234157717e-02f, +6.938768311e-01f, +3.870563373e-01f, -2.495810241e-02f }, + { -5.231630820e-02f, +6.935462886e-01f, +3.873937888e-01f, -2.498810332e-02f }, + { -5.229100900e-02f, +6.932156580e-01f, +3.877313067e-01f, -2.501811720e-02f }, + { -5.226567965e-02f, +6.928849397e-01f, +3.880688909e-01f, -2.504814403e-02f }, + { -5.224032022e-02f, +6.925541338e-01f, +3.884065411e-01f, -2.507818379e-02f }, + { -5.221493076e-02f, +6.922232404e-01f, +3.887442574e-01f, -2.510823643e-02f }, + { -5.218951136e-02f, +6.918922599e-01f, +3.890820394e-01f, -2.513830194e-02f }, + { -5.216406208e-02f, +6.915611922e-01f, +3.894198871e-01f, -2.516838029e-02f }, + { -5.213858300e-02f, +6.912300378e-01f, +3.897578004e-01f, -2.519847146e-02f }, + { -5.211307417e-02f, +6.908987966e-01f, +3.900957790e-01f, -2.522857541e-02f }, + { -5.208753568e-02f, +6.905674690e-01f, +3.904338229e-01f, -2.525869212e-02f }, + { -5.206196759e-02f, +6.902360551e-01f, +3.907719318e-01f, -2.528882157e-02f }, + { -5.203636997e-02f, +6.899045550e-01f, +3.911101057e-01f, -2.531896373e-02f }, + { -5.201074290e-02f, +6.895729691e-01f, +3.914483444e-01f, -2.534911857e-02f }, + { -5.198508643e-02f, +6.892412974e-01f, +3.917866477e-01f, -2.537928607e-02f }, + { -5.195940064e-02f, +6.889095401e-01f, +3.921250156e-01f, -2.540946619e-02f }, + { -5.193368560e-02f, +6.885776975e-01f, +3.924634478e-01f, -2.543965891e-02f }, + { -5.190794138e-02f, +6.882457697e-01f, +3.928019442e-01f, -2.546986421e-02f }, + { -5.188216805e-02f, +6.879137568e-01f, +3.931405046e-01f, -2.550008206e-02f }, + { -5.185636568e-02f, +6.875816592e-01f, +3.934791290e-01f, -2.553031243e-02f }, + { -5.183053433e-02f, +6.872494769e-01f, +3.938178171e-01f, -2.556055529e-02f }, + { -5.180467408e-02f, +6.869172102e-01f, +3.941565688e-01f, -2.559081062e-02f }, + { -5.177878499e-02f, +6.865848593e-01f, +3.944953840e-01f, -2.562107838e-02f }, + { -5.175286714e-02f, +6.862524243e-01f, +3.948342626e-01f, -2.565135856e-02f }, + { -5.172692059e-02f, +6.859199054e-01f, +3.951732042e-01f, -2.568165113e-02f }, + { -5.170094541e-02f, +6.855873028e-01f, +3.955122090e-01f, -2.571195605e-02f }, + { -5.167494167e-02f, +6.852546167e-01f, +3.958512766e-01f, -2.574227331e-02f }, + { -5.164890945e-02f, +6.849218472e-01f, +3.961904069e-01f, -2.577260287e-02f }, + { -5.162284880e-02f, +6.845889947e-01f, +3.965295998e-01f, -2.580294470e-02f }, + { -5.159675980e-02f, +6.842560591e-01f, +3.968688551e-01f, -2.583329878e-02f }, + { -5.157064252e-02f, +6.839230409e-01f, +3.972081727e-01f, -2.586366508e-02f }, + { -5.154449702e-02f, +6.835899400e-01f, +3.975475525e-01f, -2.589404358e-02f }, + { -5.151832338e-02f, +6.832567567e-01f, +3.978869942e-01f, -2.592443425e-02f }, + { -5.149212166e-02f, +6.829234913e-01f, +3.982264977e-01f, -2.595483705e-02f }, + { -5.146589193e-02f, +6.825901438e-01f, +3.985660630e-01f, -2.598525196e-02f }, + { -5.143963427e-02f, +6.822567144e-01f, +3.989056898e-01f, -2.601567895e-02f }, + { -5.141334873e-02f, +6.819232035e-01f, +3.992453779e-01f, -2.604611800e-02f }, + { -5.138703539e-02f, +6.815896110e-01f, +3.995851274e-01f, -2.607656908e-02f }, + { -5.136069431e-02f, +6.812559373e-01f, +3.999249379e-01f, -2.610703216e-02f }, + { -5.133432558e-02f, +6.809221825e-01f, +4.002648093e-01f, -2.613750720e-02f }, + { -5.130792924e-02f, +6.805883468e-01f, +4.006047415e-01f, -2.616799420e-02f }, + { -5.128150537e-02f, +6.802544304e-01f, +4.009447344e-01f, -2.619849310e-02f }, + { -5.125505405e-02f, +6.799204334e-01f, +4.012847878e-01f, -2.622900390e-02f }, + { -5.122857533e-02f, +6.795863561e-01f, +4.016249015e-01f, -2.625952655e-02f }, + { -5.120206929e-02f, +6.792521986e-01f, +4.019650754e-01f, -2.629006103e-02f }, + { -5.117553600e-02f, +6.789179612e-01f, +4.023053093e-01f, -2.632060732e-02f }, + { -5.114897551e-02f, +6.785836440e-01f, +4.026456031e-01f, -2.635116538e-02f }, + { -5.112238791e-02f, +6.782492471e-01f, +4.029859567e-01f, -2.638173519e-02f }, + { -5.109577326e-02f, +6.779147709e-01f, +4.033263699e-01f, -2.641231671e-02f }, + { -5.106913162e-02f, +6.775802154e-01f, +4.036668425e-01f, -2.644290992e-02f }, + { -5.104246307e-02f, +6.772455809e-01f, +4.040073744e-01f, -2.647351480e-02f }, + { -5.101576767e-02f, +6.769108675e-01f, +4.043479654e-01f, -2.650413130e-02f }, + { -5.098904550e-02f, +6.765760755e-01f, +4.046886155e-01f, -2.653475941e-02f }, + { -5.096229661e-02f, +6.762412050e-01f, +4.050293243e-01f, -2.656539910e-02f }, + { -5.093552108e-02f, +6.759062562e-01f, +4.053700919e-01f, -2.659605033e-02f }, + { -5.090871897e-02f, +6.755712292e-01f, +4.057109180e-01f, -2.662671308e-02f }, + { -5.088189036e-02f, +6.752361244e-01f, +4.060518025e-01f, -2.665738731e-02f }, + { -5.085503531e-02f, +6.749009418e-01f, +4.063927452e-01f, -2.668807301e-02f }, + { -5.082815388e-02f, +6.745656817e-01f, +4.067337460e-01f, -2.671877013e-02f }, + { -5.080124615e-02f, +6.742303442e-01f, +4.070748047e-01f, -2.674947866e-02f }, + { -5.077431218e-02f, +6.738949295e-01f, +4.074159212e-01f, -2.678019856e-02f }, + { -5.074735205e-02f, +6.735594378e-01f, +4.077570954e-01f, -2.681092981e-02f }, + { -5.072036581e-02f, +6.732238693e-01f, +4.080983270e-01f, -2.684167237e-02f }, + { -5.069335353e-02f, +6.728882242e-01f, +4.084396159e-01f, -2.687242621e-02f }, + { -5.066631529e-02f, +6.725525027e-01f, +4.087809621e-01f, -2.690319131e-02f }, + { -5.063925115e-02f, +6.722167049e-01f, +4.091223652e-01f, -2.693396764e-02f }, + { -5.061216118e-02f, +6.718808311e-01f, +4.094638252e-01f, -2.696475516e-02f }, + { -5.058504544e-02f, +6.715448814e-01f, +4.098053420e-01f, -2.699555385e-02f }, + { -5.055790401e-02f, +6.712088560e-01f, +4.101469153e-01f, -2.702636369e-02f }, + { -5.053073694e-02f, +6.708727551e-01f, +4.104885450e-01f, -2.705718463e-02f }, + { -5.050354431e-02f, +6.705365788e-01f, +4.108302310e-01f, -2.708801665e-02f }, + { -5.047632619e-02f, +6.702003275e-01f, +4.111719731e-01f, -2.711885972e-02f }, + { -5.044908263e-02f, +6.698640012e-01f, +4.115137711e-01f, -2.714971381e-02f }, + { -5.042181372e-02f, +6.695276002e-01f, +4.118556250e-01f, -2.718057889e-02f }, + { -5.039451951e-02f, +6.691911246e-01f, +4.121975345e-01f, -2.721145493e-02f }, + { -5.036720007e-02f, +6.688545746e-01f, +4.125394995e-01f, -2.724234191e-02f }, + { -5.033985546e-02f, +6.685179504e-01f, +4.128815199e-01f, -2.727323979e-02f }, + { -5.031248577e-02f, +6.681812522e-01f, +4.132235955e-01f, -2.730414853e-02f }, + { -5.028509105e-02f, +6.678444802e-01f, +4.135657261e-01f, -2.733506812e-02f }, + { -5.025767136e-02f, +6.675076346e-01f, +4.139079116e-01f, -2.736599852e-02f }, + { -5.023022678e-02f, +6.671707155e-01f, +4.142501518e-01f, -2.739693971e-02f }, + { -5.020275738e-02f, +6.668337231e-01f, +4.145924466e-01f, -2.742789164e-02f }, + { -5.017526321e-02f, +6.664966577e-01f, +4.149347959e-01f, -2.745885430e-02f }, + { -5.014774435e-02f, +6.661595193e-01f, +4.152771994e-01f, -2.748982764e-02f }, + { -5.012020087e-02f, +6.658223083e-01f, +4.156196570e-01f, -2.752081165e-02f }, + { -5.009263282e-02f, +6.654850247e-01f, +4.159621686e-01f, -2.755180629e-02f }, + { -5.006504027e-02f, +6.651476689e-01f, +4.163047340e-01f, -2.758281153e-02f }, + { -5.003742330e-02f, +6.648102408e-01f, +4.166473531e-01f, -2.761382734e-02f }, + { -5.000978197e-02f, +6.644727409e-01f, +4.169900257e-01f, -2.764485368e-02f }, + { -4.998211634e-02f, +6.641351691e-01f, +4.173327517e-01f, -2.767589054e-02f }, + { -4.995442649e-02f, +6.637975258e-01f, +4.176755308e-01f, -2.770693788e-02f }, + { -4.992671247e-02f, +6.634598110e-01f, +4.180183630e-01f, -2.773799566e-02f }, + { -4.989897435e-02f, +6.631220251e-01f, +4.183612481e-01f, -2.776906386e-02f }, + { -4.987121220e-02f, +6.627841681e-01f, +4.187041859e-01f, -2.780014245e-02f }, + { -4.984342609e-02f, +6.624462403e-01f, +4.190471763e-01f, -2.783123139e-02f }, + { -4.981561608e-02f, +6.621082419e-01f, +4.193902192e-01f, -2.786233066e-02f }, + { -4.978778224e-02f, +6.617701729e-01f, +4.197333143e-01f, -2.789344022e-02f }, + { -4.975992463e-02f, +6.614320337e-01f, +4.200764615e-01f, -2.792456005e-02f }, + { -4.973204333e-02f, +6.610938245e-01f, +4.204196607e-01f, -2.795569010e-02f }, + { -4.970413838e-02f, +6.607555453e-01f, +4.207629117e-01f, -2.798683036e-02f }, + { -4.967620987e-02f, +6.604171963e-01f, +4.211062143e-01f, -2.801798079e-02f }, + { -4.964825786e-02f, +6.600787779e-01f, +4.214495685e-01f, -2.804914136e-02f }, + { -4.962028241e-02f, +6.597402901e-01f, +4.217929740e-01f, -2.808031203e-02f }, + { -4.959228359e-02f, +6.594017331e-01f, +4.221364307e-01f, -2.811149279e-02f }, + { -4.956426147e-02f, +6.590631072e-01f, +4.224799384e-01f, -2.814268358e-02f }, + { -4.953621610e-02f, +6.587244125e-01f, +4.228234970e-01f, -2.817388439e-02f }, + { -4.950814756e-02f, +6.583856492e-01f, +4.231671063e-01f, -2.820509519e-02f }, + { -4.948005591e-02f, +6.580468175e-01f, +4.235107662e-01f, -2.823631593e-02f }, + { -4.945194122e-02f, +6.577079175e-01f, +4.238544765e-01f, -2.826754660e-02f }, + { -4.942380356e-02f, +6.573689495e-01f, +4.241982371e-01f, -2.829878715e-02f }, + { -4.939564297e-02f, +6.570299137e-01f, +4.245420477e-01f, -2.833003756e-02f }, + { -4.936745955e-02f, +6.566908102e-01f, +4.248859083e-01f, -2.836129779e-02f }, + { -4.933925334e-02f, +6.563516392e-01f, +4.252298187e-01f, -2.839256782e-02f }, + { -4.931102441e-02f, +6.560124009e-01f, +4.255737788e-01f, -2.842384761e-02f }, + { -4.928277284e-02f, +6.556730955e-01f, +4.259177883e-01f, -2.845513713e-02f }, + { -4.925449868e-02f, +6.553337232e-01f, +4.262618471e-01f, -2.848643635e-02f }, + { -4.922620200e-02f, +6.549942842e-01f, +4.266059551e-01f, -2.851774523e-02f }, + { -4.919788286e-02f, +6.546547786e-01f, +4.269501121e-01f, -2.854906375e-02f }, + { -4.916954133e-02f, +6.543152066e-01f, +4.272943179e-01f, -2.858039187e-02f }, + { -4.914117748e-02f, +6.539755685e-01f, +4.276385725e-01f, -2.861172956e-02f }, + { -4.911279137e-02f, +6.536358644e-01f, +4.279828756e-01f, -2.864307678e-02f }, + { -4.908438306e-02f, +6.532960945e-01f, +4.283272270e-01f, -2.867443352e-02f }, + { -4.905595262e-02f, +6.529562589e-01f, +4.286716267e-01f, -2.870579972e-02f }, + { -4.902750012e-02f, +6.526163580e-01f, +4.290160745e-01f, -2.873717537e-02f }, + { -4.899902562e-02f, +6.522763918e-01f, +4.293605701e-01f, -2.876856043e-02f }, + { -4.897052918e-02f, +6.519363605e-01f, +4.297051136e-01f, -2.879995486e-02f }, + { -4.894201087e-02f, +6.515962644e-01f, +4.300497046e-01f, -2.883135864e-02f }, + { -4.891347075e-02f, +6.512561036e-01f, +4.303943430e-01f, -2.886277173e-02f }, + { -4.888490889e-02f, +6.509158783e-01f, +4.307390288e-01f, -2.889419410e-02f }, + { -4.885632535e-02f, +6.505755887e-01f, +4.310837617e-01f, -2.892562571e-02f }, + { -4.882772020e-02f, +6.502352350e-01f, +4.314285415e-01f, -2.895706654e-02f }, + { -4.879909350e-02f, +6.498948173e-01f, +4.317733681e-01f, -2.898851656e-02f }, + { -4.877044532e-02f, +6.495543359e-01f, +4.321182414e-01f, -2.901997572e-02f }, + { -4.874177572e-02f, +6.492137910e-01f, +4.324631612e-01f, -2.905144399e-02f }, + { -4.871308476e-02f, +6.488731826e-01f, +4.328081273e-01f, -2.908292135e-02f }, + { -4.868437251e-02f, +6.485325111e-01f, +4.331531396e-01f, -2.911440776e-02f }, + { -4.865563904e-02f, +6.481917765e-01f, +4.334981980e-01f, -2.914590319e-02f }, + { -4.862688440e-02f, +6.478509792e-01f, +4.338433021e-01f, -2.917740760e-02f }, + { -4.859810867e-02f, +6.475101192e-01f, +4.341884520e-01f, -2.920892096e-02f }, + { -4.856931190e-02f, +6.471691968e-01f, +4.345336475e-01f, -2.924044325e-02f }, + { -4.854049416e-02f, +6.468282121e-01f, +4.348788883e-01f, -2.927197441e-02f }, + { -4.851165552e-02f, +6.464871653e-01f, +4.352241743e-01f, -2.930351443e-02f }, + { -4.848279603e-02f, +6.461460567e-01f, +4.355695055e-01f, -2.933506327e-02f }, + { -4.845391577e-02f, +6.458048863e-01f, +4.359148815e-01f, -2.936662089e-02f }, + { -4.842501479e-02f, +6.454636545e-01f, +4.362603023e-01f, -2.939818727e-02f }, + { -4.839609316e-02f, +6.451223613e-01f, +4.366057677e-01f, -2.942976236e-02f }, + { -4.836715094e-02f, +6.447810070e-01f, +4.369512775e-01f, -2.946134614e-02f }, + { -4.833818821e-02f, +6.444395917e-01f, +4.372968316e-01f, -2.949293857e-02f }, + { -4.830920501e-02f, +6.440981157e-01f, +4.376424298e-01f, -2.952453962e-02f }, + { -4.828020142e-02f, +6.437565791e-01f, +4.379880720e-01f, -2.955614925e-02f }, + { -4.825117750e-02f, +6.434149821e-01f, +4.383337580e-01f, -2.958776743e-02f }, + { -4.822213331e-02f, +6.430733249e-01f, +4.386794876e-01f, -2.961939414e-02f }, + { -4.819306891e-02f, +6.427316077e-01f, +4.390252607e-01f, -2.965102932e-02f }, + { -4.816398438e-02f, +6.423898306e-01f, +4.393710771e-01f, -2.968267296e-02f }, + { -4.813487976e-02f, +6.420479939e-01f, +4.397169367e-01f, -2.971432501e-02f }, + { -4.810575513e-02f, +6.417060978e-01f, +4.400628392e-01f, -2.974598544e-02f }, + { -4.807661056e-02f, +6.413641423e-01f, +4.404087847e-01f, -2.977765422e-02f }, + { -4.804744609e-02f, +6.410221278e-01f, +4.407547728e-01f, -2.980933131e-02f }, + { -4.801826180e-02f, +6.406800544e-01f, +4.411008034e-01f, -2.984101669e-02f }, + { -4.798905775e-02f, +6.403379223e-01f, +4.414468764e-01f, -2.987271031e-02f }, + { -4.795983400e-02f, +6.399957316e-01f, +4.417929916e-01f, -2.990441214e-02f }, + { -4.793059062e-02f, +6.396534826e-01f, +4.421391489e-01f, -2.993612215e-02f }, + { -4.790132766e-02f, +6.393111754e-01f, +4.424853480e-01f, -2.996784030e-02f }, + { -4.787204520e-02f, +6.389688103e-01f, +4.428315888e-01f, -2.999956656e-02f }, + { -4.784274329e-02f, +6.386263874e-01f, +4.431778713e-01f, -3.003130090e-02f }, + { -4.781342200e-02f, +6.382839069e-01f, +4.435241951e-01f, -3.006304328e-02f }, + { -4.778408139e-02f, +6.379413690e-01f, +4.438705601e-01f, -3.009479366e-02f }, + { -4.775472152e-02f, +6.375987738e-01f, +4.442169663e-01f, -3.012655201e-02f }, + { -4.772534246e-02f, +6.372561217e-01f, +4.445634133e-01f, -3.015831830e-02f }, + { -4.769594427e-02f, +6.369134126e-01f, +4.449099012e-01f, -3.019009249e-02f }, + { -4.766652701e-02f, +6.365706469e-01f, +4.452564296e-01f, -3.022187454e-02f }, + { -4.763709074e-02f, +6.362278248e-01f, +4.456029984e-01f, -3.025366443e-02f }, + { -4.760763553e-02f, +6.358849463e-01f, +4.459496076e-01f, -3.028546212e-02f }, + { -4.757816144e-02f, +6.355420117e-01f, +4.462962568e-01f, -3.031726757e-02f }, + { -4.754866853e-02f, +6.351990212e-01f, +4.466429460e-01f, -3.034908075e-02f }, + { -4.751915687e-02f, +6.348559750e-01f, +4.469896750e-01f, -3.038090162e-02f }, + { -4.748962651e-02f, +6.345128733e-01f, +4.473364437e-01f, -3.041273015e-02f }, + { -4.746007752e-02f, +6.341697161e-01f, +4.476832518e-01f, -3.044456630e-02f }, + { -4.743050997e-02f, +6.338265038e-01f, +4.480300992e-01f, -3.047641003e-02f }, + { -4.740092391e-02f, +6.334832365e-01f, +4.483769858e-01f, -3.050826133e-02f }, + { -4.737131940e-02f, +6.331399144e-01f, +4.487239113e-01f, -3.054012013e-02f }, + { -4.734169651e-02f, +6.327965377e-01f, +4.490708757e-01f, -3.057198642e-02f }, + { -4.731205530e-02f, +6.324531066e-01f, +4.494178788e-01f, -3.060386016e-02f }, + { -4.728239584e-02f, +6.321096212e-01f, +4.497649203e-01f, -3.063574131e-02f }, + { -4.725271818e-02f, +6.317660818e-01f, +4.501120002e-01f, -3.066762983e-02f }, + { -4.722302238e-02f, +6.314224885e-01f, +4.504591183e-01f, -3.069952570e-02f }, + { -4.719330852e-02f, +6.310788415e-01f, +4.508062744e-01f, -3.073142887e-02f }, + { -4.716357665e-02f, +6.307351410e-01f, +4.511534683e-01f, -3.076333930e-02f }, + { -4.713382682e-02f, +6.303913872e-01f, +4.515006999e-01f, -3.079525698e-02f }, + { -4.710405912e-02f, +6.300475802e-01f, +4.518479691e-01f, -3.082718185e-02f }, + { -4.707427359e-02f, +6.297037204e-01f, +4.521952756e-01f, -3.085911388e-02f }, + { -4.704447029e-02f, +6.293598077e-01f, +4.525426193e-01f, -3.089105304e-02f }, + { -4.701464930e-02f, +6.290158425e-01f, +4.528900001e-01f, -3.092299929e-02f }, + { -4.698481067e-02f, +6.286718249e-01f, +4.532374178e-01f, -3.095495259e-02f }, + { -4.695495446e-02f, +6.283277552e-01f, +4.535848721e-01f, -3.098691291e-02f }, + { -4.692508073e-02f, +6.279836334e-01f, +4.539323631e-01f, -3.101888022e-02f }, + { -4.689518955e-02f, +6.276394598e-01f, +4.542798904e-01f, -3.105085447e-02f }, + { -4.686528098e-02f, +6.272952345e-01f, +4.546274539e-01f, -3.108283564e-02f }, + { -4.683535507e-02f, +6.269509578e-01f, +4.549750535e-01f, -3.111482367e-02f }, + { -4.680541190e-02f, +6.266066299e-01f, +4.553226890e-01f, -3.114681855e-02f }, + { -4.677545152e-02f, +6.262622508e-01f, +4.556703603e-01f, -3.117882023e-02f }, + { -4.674547399e-02f, +6.259178209e-01f, +4.560180671e-01f, -3.121082867e-02f }, + { -4.671547937e-02f, +6.255733402e-01f, +4.563658094e-01f, -3.124284384e-02f }, + { -4.668546773e-02f, +6.252288091e-01f, +4.567135869e-01f, -3.127486571e-02f }, + { -4.665543913e-02f, +6.248842275e-01f, +4.570613994e-01f, -3.130689423e-02f }, + { -4.662539362e-02f, +6.245395959e-01f, +4.574092469e-01f, -3.133892937e-02f }, + { -4.659533127e-02f, +6.241949143e-01f, +4.577571292e-01f, -3.137097110e-02f }, + { -4.656525215e-02f, +6.238501829e-01f, +4.581050460e-01f, -3.140301937e-02f }, + { -4.653515630e-02f, +6.235054019e-01f, +4.584529973e-01f, -3.143507415e-02f }, + { -4.650504379e-02f, +6.231605715e-01f, +4.588009829e-01f, -3.146713541e-02f }, + { -4.647491468e-02f, +6.228156918e-01f, +4.591490025e-01f, -3.149920310e-02f }, + { -4.644476904e-02f, +6.224707632e-01f, +4.594970561e-01f, -3.153127720e-02f }, + { -4.641460692e-02f, +6.221257857e-01f, +4.598451435e-01f, -3.156335765e-02f }, + { -4.638442839e-02f, +6.217807595e-01f, +4.601932645e-01f, -3.159544443e-02f }, + { -4.635423350e-02f, +6.214356849e-01f, +4.605414189e-01f, -3.162753750e-02f }, + { -4.632402231e-02f, +6.210905619e-01f, +4.608896066e-01f, -3.165963682e-02f }, + { -4.629379489e-02f, +6.207453909e-01f, +4.612378274e-01f, -3.169174236e-02f }, + { -4.626355130e-02f, +6.204001719e-01f, +4.615860812e-01f, -3.172385407e-02f }, + { -4.623329159e-02f, +6.200549052e-01f, +4.619343678e-01f, -3.175597193e-02f }, + { -4.620301584e-02f, +6.197095909e-01f, +4.622826870e-01f, -3.178809589e-02f }, + { -4.617272409e-02f, +6.193642293e-01f, +4.626310387e-01f, -3.182022591e-02f }, + { -4.614241641e-02f, +6.190188205e-01f, +4.629794226e-01f, -3.185236196e-02f }, + { -4.611209285e-02f, +6.186733647e-01f, +4.633278387e-01f, -3.188450401e-02f }, + { -4.608175349e-02f, +6.183278621e-01f, +4.636762867e-01f, -3.191665200e-02f }, + { -4.605139837e-02f, +6.179823129e-01f, +4.640247666e-01f, -3.194880592e-02f }, + { -4.602102757e-02f, +6.176367173e-01f, +4.643732781e-01f, -3.198096571e-02f }, + { -4.599064113e-02f, +6.172910754e-01f, +4.647218210e-01f, -3.201313134e-02f }, + { -4.596023912e-02f, +6.169453874e-01f, +4.650703953e-01f, -3.204530278e-02f }, + { -4.592982160e-02f, +6.165996536e-01f, +4.654190007e-01f, -3.207747998e-02f }, + { -4.589938863e-02f, +6.162538740e-01f, +4.657676371e-01f, -3.210966291e-02f }, + { -4.586894027e-02f, +6.159080490e-01f, +4.661163043e-01f, -3.214185153e-02f }, + { -4.583847658e-02f, +6.155621786e-01f, +4.664650021e-01f, -3.217404580e-02f }, + { -4.580799762e-02f, +6.152162631e-01f, +4.668137304e-01f, -3.220624568e-02f }, + { -4.577750344e-02f, +6.148703026e-01f, +4.671624891e-01f, -3.223845114e-02f }, + { -4.574699411e-02f, +6.145242974e-01f, +4.675112778e-01f, -3.227066214e-02f }, + { -4.571646969e-02f, +6.141782476e-01f, +4.678600966e-01f, -3.230287864e-02f }, + { -4.568593024e-02f, +6.138321534e-01f, +4.682089452e-01f, -3.233510060e-02f }, + { -4.565537582e-02f, +6.134860150e-01f, +4.685578234e-01f, -3.236732799e-02f }, + { -4.562480648e-02f, +6.131398326e-01f, +4.689067311e-01f, -3.239956076e-02f }, + { -4.559422228e-02f, +6.127936063e-01f, +4.692556681e-01f, -3.243179888e-02f }, + { -4.556362330e-02f, +6.124473364e-01f, +4.696046343e-01f, -3.246404230e-02f }, + { -4.553300957e-02f, +6.121010230e-01f, +4.699536294e-01f, -3.249629100e-02f }, + { -4.550238117e-02f, +6.117546663e-01f, +4.703026534e-01f, -3.252854493e-02f }, + { -4.547173816e-02f, +6.114082665e-01f, +4.706517061e-01f, -3.256080405e-02f }, + { -4.544108058e-02f, +6.110618238e-01f, +4.710007872e-01f, -3.259306833e-02f }, + { -4.541040851e-02f, +6.107153384e-01f, +4.713498966e-01f, -3.262533772e-02f }, + { -4.537972200e-02f, +6.103688104e-01f, +4.716990342e-01f, -3.265761219e-02f }, + { -4.534902111e-02f, +6.100222401e-01f, +4.720481998e-01f, -3.268989170e-02f }, + { -4.531830590e-02f, +6.096756276e-01f, +4.723973932e-01f, -3.272217621e-02f }, + { -4.528757642e-02f, +6.093289732e-01f, +4.727466142e-01f, -3.275446568e-02f }, + { -4.525683274e-02f, +6.089822769e-01f, +4.730958628e-01f, -3.278676008e-02f }, + { -4.522607492e-02f, +6.086355390e-01f, +4.734451386e-01f, -3.281905935e-02f }, + { -4.519530301e-02f, +6.082887597e-01f, +4.737944416e-01f, -3.285136347e-02f }, + { -4.516451708e-02f, +6.079419391e-01f, +4.741437716e-01f, -3.288367240e-02f }, + { -4.513371718e-02f, +6.075950775e-01f, +4.744931285e-01f, -3.291598609e-02f }, + { -4.510290336e-02f, +6.072481750e-01f, +4.748425119e-01f, -3.294830451e-02f }, + { -4.507207570e-02f, +6.069012318e-01f, +4.751919219e-01f, -3.298062762e-02f }, + { -4.504123425e-02f, +6.065542481e-01f, +4.755413581e-01f, -3.301295538e-02f }, + { -4.501037906e-02f, +6.062072240e-01f, +4.758908206e-01f, -3.304528775e-02f }, + { -4.497951020e-02f, +6.058601599e-01f, +4.762403090e-01f, -3.307762468e-02f }, + { -4.494862772e-02f, +6.055130558e-01f, +4.765898232e-01f, -3.310996615e-02f }, + { -4.491773168e-02f, +6.051659119e-01f, +4.769393630e-01f, -3.314231211e-02f }, + { -4.488682214e-02f, +6.048187284e-01f, +4.772889284e-01f, -3.317466252e-02f }, + { -4.485589916e-02f, +6.044715056e-01f, +4.776385190e-01f, -3.320701734e-02f }, + { -4.482496280e-02f, +6.041242435e-01f, +4.779881348e-01f, -3.323937653e-02f }, + { -4.479401311e-02f, +6.037769424e-01f, +4.783377756e-01f, -3.327174006e-02f }, + { -4.476305016e-02f, +6.034296025e-01f, +4.786874411e-01f, -3.330410788e-02f }, + { -4.473207400e-02f, +6.030822239e-01f, +4.790371313e-01f, -3.333647996e-02f }, + { -4.470108468e-02f, +6.027348068e-01f, +4.793868460e-01f, -3.336885624e-02f }, + { -4.467008228e-02f, +6.023873514e-01f, +4.797365850e-01f, -3.340123671e-02f }, + { -4.463906683e-02f, +6.020398580e-01f, +4.800863481e-01f, -3.343362130e-02f }, + { -4.460803842e-02f, +6.016923266e-01f, +4.804361352e-01f, -3.346600999e-02f }, + { -4.457699708e-02f, +6.013447575e-01f, +4.807859461e-01f, -3.349840273e-02f }, + { -4.454594288e-02f, +6.009971508e-01f, +4.811357806e-01f, -3.353079949e-02f }, + { -4.451487588e-02f, +6.006495068e-01f, +4.814856386e-01f, -3.356320022e-02f }, + { -4.448379613e-02f, +6.003018256e-01f, +4.818355198e-01f, -3.359560488e-02f }, + { -4.445270370e-02f, +5.999541074e-01f, +4.821854242e-01f, -3.362801344e-02f }, + { -4.442159863e-02f, +5.996063524e-01f, +4.825353516e-01f, -3.366042585e-02f }, + { -4.439048099e-02f, +5.992585607e-01f, +4.828853017e-01f, -3.369284207e-02f }, + { -4.435935084e-02f, +5.989107327e-01f, +4.832352745e-01f, -3.372526206e-02f }, + { -4.432820823e-02f, +5.985628683e-01f, +4.835852697e-01f, -3.375768579e-02f }, + { -4.429705321e-02f, +5.982149679e-01f, +4.839352871e-01f, -3.379011321e-02f }, + { -4.426588586e-02f, +5.978670316e-01f, +4.842853267e-01f, -3.382254427e-02f }, + { -4.423470622e-02f, +5.975190596e-01f, +4.846353882e-01f, -3.385497895e-02f }, + { -4.420351435e-02f, +5.971710521e-01f, +4.849854715e-01f, -3.388741720e-02f }, + { -4.417231031e-02f, +5.968230092e-01f, +4.853355764e-01f, -3.391985897e-02f }, + { -4.414109415e-02f, +5.964749312e-01f, +4.856857028e-01f, -3.395230423e-02f }, + { -4.410986594e-02f, +5.961268182e-01f, +4.860358504e-01f, -3.398475294e-02f }, + { -4.407862573e-02f, +5.957786704e-01f, +4.863860191e-01f, -3.401720506e-02f }, + { -4.404737358e-02f, +5.954304881e-01f, +4.867362087e-01f, -3.404966054e-02f }, + { -4.401610954e-02f, +5.950822713e-01f, +4.870864191e-01f, -3.408211934e-02f }, + { -4.398483367e-02f, +5.947340203e-01f, +4.874366500e-01f, -3.411458143e-02f }, + { -4.395354603e-02f, +5.943857352e-01f, +4.877869014e-01f, -3.414704676e-02f }, + { -4.392224667e-02f, +5.940374163e-01f, +4.881371730e-01f, -3.417951529e-02f }, + { -4.389093566e-02f, +5.936890637e-01f, +4.884874647e-01f, -3.421198698e-02f }, + { -4.385961304e-02f, +5.933406776e-01f, +4.888377763e-01f, -3.424446179e-02f }, + { -4.382827888e-02f, +5.929922582e-01f, +4.891881076e-01f, -3.427693968e-02f }, + { -4.379693323e-02f, +5.926438057e-01f, +4.895384585e-01f, -3.430942060e-02f }, + { -4.376557615e-02f, +5.922953202e-01f, +4.898888288e-01f, -3.434190452e-02f }, + { -4.373420769e-02f, +5.919468020e-01f, +4.902392184e-01f, -3.437439139e-02f }, + { -4.370282792e-02f, +5.915982512e-01f, +4.905896269e-01f, -3.440688117e-02f }, + { -4.367143688e-02f, +5.912496680e-01f, +4.909400544e-01f, -3.443937382e-02f }, + { -4.364003464e-02f, +5.909010526e-01f, +4.912905006e-01f, -3.447186930e-02f }, + { -4.360862124e-02f, +5.905524052e-01f, +4.916409653e-01f, -3.450436756e-02f }, + { -4.357719676e-02f, +5.902037260e-01f, +4.919914484e-01f, -3.453686857e-02f }, + { -4.354576123e-02f, +5.898550151e-01f, +4.923419497e-01f, -3.456937229e-02f }, + { -4.351431473e-02f, +5.895062727e-01f, +4.926924690e-01f, -3.460187866e-02f }, + { -4.348285730e-02f, +5.891574990e-01f, +4.930430062e-01f, -3.463438766e-02f }, + { -4.345138900e-02f, +5.888086942e-01f, +4.933935611e-01f, -3.466689923e-02f }, + { -4.341990989e-02f, +5.884598586e-01f, +4.937441335e-01f, -3.469941334e-02f }, + { -4.338842003e-02f, +5.881109921e-01f, +4.940947233e-01f, -3.473192994e-02f }, + { -4.335691946e-02f, +5.877620952e-01f, +4.944453302e-01f, -3.476444900e-02f }, + { -4.332540825e-02f, +5.874131678e-01f, +4.947959542e-01f, -3.479697046e-02f }, + { -4.329388645e-02f, +5.870642103e-01f, +4.951465949e-01f, -3.482949429e-02f }, + { -4.326235411e-02f, +5.867152227e-01f, +4.954972524e-01f, -3.486202044e-02f }, + { -4.323081130e-02f, +5.863662054e-01f, +4.958479263e-01f, -3.489454888e-02f }, + { -4.319925807e-02f, +5.860171584e-01f, +4.961986166e-01f, -3.492707956e-02f }, + { -4.316769447e-02f, +5.856680820e-01f, +4.965493230e-01f, -3.495961243e-02f }, + { -4.313612056e-02f, +5.853189763e-01f, +4.969000454e-01f, -3.499214746e-02f }, + { -4.310453640e-02f, +5.849698415e-01f, +4.972507836e-01f, -3.502468461e-02f }, + { -4.307294203e-02f, +5.846206778e-01f, +4.976015374e-01f, -3.505722382e-02f }, + { -4.304133752e-02f, +5.842714854e-01f, +4.979523067e-01f, -3.508976506e-02f }, + { -4.300972293e-02f, +5.839222644e-01f, +4.983030913e-01f, -3.512230829e-02f }, + { -4.297809830e-02f, +5.835730151e-01f, +4.986538910e-01f, -3.515485346e-02f }, + { -4.294646369e-02f, +5.832237377e-01f, +4.990047056e-01f, -3.518740053e-02f }, + { -4.291481916e-02f, +5.828744322e-01f, +4.993555351e-01f, -3.521994946e-02f }, + { -4.288316476e-02f, +5.825250990e-01f, +4.997063791e-01f, -3.525250020e-02f }, + { -4.285150055e-02f, +5.821757381e-01f, +5.000572376e-01f, -3.528505271e-02f }, + { -4.281982659e-02f, +5.818263498e-01f, +5.004081103e-01f, -3.531760695e-02f }, + { -4.278814292e-02f, +5.814769342e-01f, +5.007589972e-01f, -3.535016287e-02f }, + { -4.275644960e-02f, +5.811274916e-01f, +5.011098979e-01f, -3.538272044e-02f }, + { -4.272474669e-02f, +5.807780221e-01f, +5.014608124e-01f, -3.541527960e-02f }, + { -4.269303424e-02f, +5.804285259e-01f, +5.018117405e-01f, -3.544784032e-02f }, + { -4.266131231e-02f, +5.800790031e-01f, +5.021626819e-01f, -3.548040255e-02f }, + { -4.262958096e-02f, +5.797294541e-01f, +5.025136366e-01f, -3.551296626e-02f }, + { -4.259784023e-02f, +5.793798788e-01f, +5.028646044e-01f, -3.554553138e-02f }, + { -4.256609018e-02f, +5.790302776e-01f, +5.032155850e-01f, -3.557809789e-02f }, + { -4.253433087e-02f, +5.786806507e-01f, +5.035665783e-01f, -3.561066574e-02f }, + { -4.250256235e-02f, +5.783309981e-01f, +5.039175842e-01f, -3.564323489e-02f }, + { -4.247078467e-02f, +5.779813201e-01f, +5.042686025e-01f, -3.567580528e-02f }, + { -4.243899790e-02f, +5.776316168e-01f, +5.046196329e-01f, -3.570837689e-02f }, + { -4.240720208e-02f, +5.772818885e-01f, +5.049706753e-01f, -3.574094966e-02f }, + { -4.237539726e-02f, +5.769321353e-01f, +5.053217296e-01f, -3.577352355e-02f }, + { -4.234358351e-02f, +5.765823574e-01f, +5.056727956e-01f, -3.580609851e-02f }, + { -4.231176088e-02f, +5.762325550e-01f, +5.060238731e-01f, -3.583867451e-02f }, + { -4.227992942e-02f, +5.758827283e-01f, +5.063749619e-01f, -3.587125150e-02f }, + { -4.224808919e-02f, +5.755328774e-01f, +5.067260619e-01f, -3.590382944e-02f }, + { -4.221624023e-02f, +5.751830026e-01f, +5.070771728e-01f, -3.593640828e-02f }, + { -4.218438261e-02f, +5.748331040e-01f, +5.074282945e-01f, -3.596898797e-02f }, + { -4.215251638e-02f, +5.744831818e-01f, +5.077794269e-01f, -3.600156848e-02f }, + { -4.212064159e-02f, +5.741332362e-01f, +5.081305697e-01f, -3.603414976e-02f }, + { -4.208875830e-02f, +5.737832673e-01f, +5.084817229e-01f, -3.606673176e-02f }, + { -4.205686655e-02f, +5.734332754e-01f, +5.088328861e-01f, -3.609931444e-02f }, + { -4.202496641e-02f, +5.730832607e-01f, +5.091840593e-01f, -3.613189776e-02f }, + { -4.199305793e-02f, +5.727332232e-01f, +5.095352422e-01f, -3.616448168e-02f }, + { -4.196114116e-02f, +5.723831633e-01f, +5.098864348e-01f, -3.619706614e-02f }, + { -4.192921615e-02f, +5.720330810e-01f, +5.102376367e-01f, -3.622965110e-02f }, + { -4.189728297e-02f, +5.716829766e-01f, +5.105888479e-01f, -3.626223652e-02f }, + { -4.186534165e-02f, +5.713328502e-01f, +5.109400682e-01f, -3.629482236e-02f }, + { -4.183339226e-02f, +5.709827020e-01f, +5.112912974e-01f, -3.632740857e-02f }, + { -4.180143485e-02f, +5.706325323e-01f, +5.116425353e-01f, -3.635999510e-02f }, + { -4.176946947e-02f, +5.702823411e-01f, +5.119937817e-01f, -3.639258191e-02f }, + { -4.173749618e-02f, +5.699321287e-01f, +5.123450366e-01f, -3.642516896e-02f }, + { -4.170551503e-02f, +5.695818953e-01f, +5.126962996e-01f, -3.645775620e-02f }, + { -4.167352607e-02f, +5.692316410e-01f, +5.130475706e-01f, -3.649034358e-02f }, + { -4.164152936e-02f, +5.688813660e-01f, +5.133988495e-01f, -3.652293107e-02f }, + { -4.160952494e-02f, +5.685310706e-01f, +5.137501361e-01f, -3.655551861e-02f }, + { -4.157751288e-02f, +5.681807548e-01f, +5.141014302e-01f, -3.658810617e-02f }, + { -4.154549322e-02f, +5.678304188e-01f, +5.144527316e-01f, -3.662069369e-02f }, + { -4.151346602e-02f, +5.674800629e-01f, +5.148040402e-01f, -3.665328113e-02f }, + { -4.148143133e-02f, +5.671296873e-01f, +5.151553558e-01f, -3.668586844e-02f }, + { -4.144938921e-02f, +5.667792920e-01f, +5.155066781e-01f, -3.671845559e-02f }, + { -4.141733970e-02f, +5.664288773e-01f, +5.158580071e-01f, -3.675104252e-02f }, + { -4.138528287e-02f, +5.660784434e-01f, +5.162093426e-01f, -3.678362919e-02f }, + { -4.135321875e-02f, +5.657279905e-01f, +5.165606843e-01f, -3.681621556e-02f }, + { -4.132114741e-02f, +5.653775186e-01f, +5.169120321e-01f, -3.684880158e-02f }, + { -4.128906890e-02f, +5.650270281e-01f, +5.172633859e-01f, -3.688138720e-02f }, + { -4.125698327e-02f, +5.646765191e-01f, +5.176147454e-01f, -3.691397237e-02f }, + { -4.122489058e-02f, +5.643259918e-01f, +5.179661105e-01f, -3.694655706e-02f }, + { -4.119279087e-02f, +5.639754463e-01f, +5.183174810e-01f, -3.697914122e-02f }, + { -4.116068419e-02f, +5.636248829e-01f, +5.186688568e-01f, -3.701172480e-02f }, + { -4.112857061e-02f, +5.632743017e-01f, +5.190202376e-01f, -3.704430775e-02f }, + { -4.109645017e-02f, +5.629237029e-01f, +5.193716233e-01f, -3.707689003e-02f }, + { -4.106432293e-02f, +5.625730867e-01f, +5.197230137e-01f, -3.710947160e-02f }, + { -4.103218893e-02f, +5.622224532e-01f, +5.200744086e-01f, -3.714205241e-02f }, + { -4.100004824e-02f, +5.618718027e-01f, +5.204258079e-01f, -3.717463240e-02f }, + { -4.096790089e-02f, +5.615211353e-01f, +5.207772113e-01f, -3.720721154e-02f }, + { -4.093574695e-02f, +5.611704512e-01f, +5.211286188e-01f, -3.723978979e-02f }, + { -4.090358647e-02f, +5.608197506e-01f, +5.214800301e-01f, -3.727236708e-02f }, + { -4.087141949e-02f, +5.604690337e-01f, +5.218314450e-01f, -3.730494338e-02f }, + { -4.083924608e-02f, +5.601183006e-01f, +5.221828634e-01f, -3.733751865e-02f }, + { -4.080706628e-02f, +5.597675516e-01f, +5.225342852e-01f, -3.737009283e-02f }, + { -4.077488014e-02f, +5.594167868e-01f, +5.228857100e-01f, -3.740266587e-02f }, + { -4.074268771e-02f, +5.590660064e-01f, +5.232371378e-01f, -3.743523774e-02f }, + { -4.071048906e-02f, +5.587152105e-01f, +5.235885684e-01f, -3.746780839e-02f }, + { -4.067828422e-02f, +5.583643994e-01f, +5.239400015e-01f, -3.750037777e-02f }, + { -4.064607325e-02f, +5.580135732e-01f, +5.242914371e-01f, -3.753294582e-02f }, + { -4.061385621e-02f, +5.576627322e-01f, +5.246428750e-01f, -3.756551252e-02f }, + { -4.058163314e-02f, +5.573118764e-01f, +5.249943149e-01f, -3.759807780e-02f }, + { -4.054940409e-02f, +5.569610062e-01f, +5.253457567e-01f, -3.763064163e-02f }, + { -4.051716913e-02f, +5.566101215e-01f, +5.256972002e-01f, -3.766320395e-02f }, + { -4.048492829e-02f, +5.562592228e-01f, +5.260486453e-01f, -3.769576473e-02f }, + { -4.045268163e-02f, +5.559083100e-01f, +5.264000917e-01f, -3.772832390e-02f }, + { -4.042042920e-02f, +5.555573834e-01f, +5.267515394e-01f, -3.776088143e-02f }, + { -4.038817105e-02f, +5.552064433e-01f, +5.271029880e-01f, -3.779343727e-02f }, + { -4.035590724e-02f, +5.548554896e-01f, +5.274544375e-01f, -3.782599137e-02f }, + { -4.032363781e-02f, +5.545045228e-01f, +5.278058876e-01f, -3.785854369e-02f }, + { -4.029136282e-02f, +5.541535428e-01f, +5.281573382e-01f, -3.789109417e-02f }, + { -4.025908231e-02f, +5.538025499e-01f, +5.285087891e-01f, -3.792364277e-02f }, + { -4.022679634e-02f, +5.534515443e-01f, +5.288602402e-01f, -3.795618945e-02f }, + { -4.019450496e-02f, +5.531005262e-01f, +5.292116912e-01f, -3.798873415e-02f }, + { -4.016220822e-02f, +5.527494957e-01f, +5.295631419e-01f, -3.802127683e-02f }, + { -4.012990617e-02f, +5.523984531e-01f, +5.299145923e-01f, -3.805381745e-02f }, + { -4.009759887e-02f, +5.520473984e-01f, +5.302660421e-01f, -3.808635594e-02f }, + { -4.006528635e-02f, +5.516963319e-01f, +5.306174912e-01f, -3.811889228e-02f }, + { -4.003296867e-02f, +5.513452538e-01f, +5.309689393e-01f, -3.815142640e-02f }, + { -4.000064589e-02f, +5.509941643e-01f, +5.313203863e-01f, -3.818395826e-02f }, + { -3.996831805e-02f, +5.506430634e-01f, +5.316718320e-01f, -3.821648782e-02f }, + { -3.993598521e-02f, +5.502919514e-01f, +5.320232763e-01f, -3.824901502e-02f }, + { -3.990364741e-02f, +5.499408286e-01f, +5.323747189e-01f, -3.828153982e-02f }, + { -3.987130471e-02f, +5.495896949e-01f, +5.327261597e-01f, -3.831406217e-02f }, + { -3.983895715e-02f, +5.492385508e-01f, +5.330775985e-01f, -3.834658202e-02f }, + { -3.980660479e-02f, +5.488873962e-01f, +5.334290351e-01f, -3.837909933e-02f }, + { -3.977424767e-02f, +5.485362314e-01f, +5.337804694e-01f, -3.841161404e-02f }, + { -3.974188585e-02f, +5.481850566e-01f, +5.341319012e-01f, -3.844412612e-02f }, + { -3.970951938e-02f, +5.478338720e-01f, +5.344833302e-01f, -3.847663550e-02f }, + { -3.967714830e-02f, +5.474826777e-01f, +5.348347564e-01f, -3.850914215e-02f }, + { -3.964477267e-02f, +5.471314739e-01f, +5.351861795e-01f, -3.854164601e-02f }, + { -3.961239253e-02f, +5.467802608e-01f, +5.355375994e-01f, -3.857414703e-02f }, + { -3.958000795e-02f, +5.464290386e-01f, +5.358890159e-01f, -3.860664518e-02f }, + { -3.954761896e-02f, +5.460778075e-01f, +5.362404287e-01f, -3.863914039e-02f }, + { -3.951522561e-02f, +5.457265676e-01f, +5.365918378e-01f, -3.867163263e-02f }, + { -3.948282796e-02f, +5.453753190e-01f, +5.369432430e-01f, -3.870412184e-02f }, + { -3.945042606e-02f, +5.450240621e-01f, +5.372946440e-01f, -3.873660797e-02f }, + { -3.941801995e-02f, +5.446727970e-01f, +5.376460407e-01f, -3.876909098e-02f }, + { -3.938560969e-02f, +5.443215238e-01f, +5.379974330e-01f, -3.880157082e-02f }, + { -3.935319533e-02f, +5.439702427e-01f, +5.383488206e-01f, -3.883404743e-02f }, + { -3.932077690e-02f, +5.436189539e-01f, +5.387002033e-01f, -3.886652078e-02f }, + { -3.928835448e-02f, +5.432676576e-01f, +5.390515810e-01f, -3.889899081e-02f }, + { -3.925592809e-02f, +5.429163540e-01f, +5.394029536e-01f, -3.893145747e-02f }, + { -3.922349780e-02f, +5.425650432e-01f, +5.397543207e-01f, -3.896392071e-02f }, + { -3.919106365e-02f, +5.422137254e-01f, +5.401056823e-01f, -3.899638049e-02f }, + { -3.915862569e-02f, +5.418624009e-01f, +5.404570382e-01f, -3.902883675e-02f }, + { -3.912618397e-02f, +5.415110697e-01f, +5.408083882e-01f, -3.906128945e-02f }, + { -3.909373854e-02f, +5.411597321e-01f, +5.411597321e-01f, -3.909373854e-02f }, + { -3.906128945e-02f, +5.408083882e-01f, +5.415110697e-01f, -3.912618397e-02f }, + { -3.902883675e-02f, +5.404570382e-01f, +5.418624009e-01f, -3.915862569e-02f }, + { -3.899638049e-02f, +5.401056823e-01f, +5.422137254e-01f, -3.919106365e-02f }, + { -3.896392071e-02f, +5.397543207e-01f, +5.425650432e-01f, -3.922349780e-02f }, + { -3.893145747e-02f, +5.394029536e-01f, +5.429163540e-01f, -3.925592809e-02f }, + { -3.889899081e-02f, +5.390515810e-01f, +5.432676576e-01f, -3.928835448e-02f }, + { -3.886652078e-02f, +5.387002033e-01f, +5.436189539e-01f, -3.932077690e-02f }, + { -3.883404743e-02f, +5.383488206e-01f, +5.439702427e-01f, -3.935319533e-02f }, + { -3.880157082e-02f, +5.379974330e-01f, +5.443215238e-01f, -3.938560969e-02f }, + { -3.876909098e-02f, +5.376460407e-01f, +5.446727970e-01f, -3.941801995e-02f }, + { -3.873660797e-02f, +5.372946440e-01f, +5.450240621e-01f, -3.945042606e-02f }, + { -3.870412184e-02f, +5.369432430e-01f, +5.453753190e-01f, -3.948282796e-02f }, + { -3.867163263e-02f, +5.365918378e-01f, +5.457265676e-01f, -3.951522561e-02f }, + { -3.863914039e-02f, +5.362404287e-01f, +5.460778075e-01f, -3.954761896e-02f }, + { -3.860664518e-02f, +5.358890159e-01f, +5.464290386e-01f, -3.958000795e-02f }, + { -3.857414703e-02f, +5.355375994e-01f, +5.467802608e-01f, -3.961239253e-02f }, + { -3.854164601e-02f, +5.351861795e-01f, +5.471314739e-01f, -3.964477267e-02f }, + { -3.850914215e-02f, +5.348347564e-01f, +5.474826777e-01f, -3.967714830e-02f }, + { -3.847663550e-02f, +5.344833302e-01f, +5.478338720e-01f, -3.970951938e-02f }, + { -3.844412612e-02f, +5.341319012e-01f, +5.481850566e-01f, -3.974188585e-02f }, + { -3.841161404e-02f, +5.337804694e-01f, +5.485362314e-01f, -3.977424767e-02f }, + { -3.837909933e-02f, +5.334290351e-01f, +5.488873962e-01f, -3.980660479e-02f }, + { -3.834658202e-02f, +5.330775985e-01f, +5.492385508e-01f, -3.983895715e-02f }, + { -3.831406217e-02f, +5.327261597e-01f, +5.495896949e-01f, -3.987130471e-02f }, + { -3.828153982e-02f, +5.323747189e-01f, +5.499408286e-01f, -3.990364741e-02f }, + { -3.824901502e-02f, +5.320232763e-01f, +5.502919514e-01f, -3.993598521e-02f }, + { -3.821648782e-02f, +5.316718320e-01f, +5.506430634e-01f, -3.996831805e-02f }, + { -3.818395826e-02f, +5.313203863e-01f, +5.509941643e-01f, -4.000064589e-02f }, + { -3.815142640e-02f, +5.309689393e-01f, +5.513452538e-01f, -4.003296867e-02f }, + { -3.811889228e-02f, +5.306174912e-01f, +5.516963319e-01f, -4.006528635e-02f }, + { -3.808635594e-02f, +5.302660421e-01f, +5.520473984e-01f, -4.009759887e-02f }, + { -3.805381745e-02f, +5.299145923e-01f, +5.523984531e-01f, -4.012990617e-02f }, + { -3.802127683e-02f, +5.295631419e-01f, +5.527494957e-01f, -4.016220822e-02f }, + { -3.798873415e-02f, +5.292116912e-01f, +5.531005262e-01f, -4.019450496e-02f }, + { -3.795618945e-02f, +5.288602402e-01f, +5.534515443e-01f, -4.022679634e-02f }, + { -3.792364277e-02f, +5.285087891e-01f, +5.538025499e-01f, -4.025908231e-02f }, + { -3.789109417e-02f, +5.281573382e-01f, +5.541535428e-01f, -4.029136282e-02f }, + { -3.785854369e-02f, +5.278058876e-01f, +5.545045228e-01f, -4.032363781e-02f }, + { -3.782599137e-02f, +5.274544375e-01f, +5.548554896e-01f, -4.035590724e-02f }, + { -3.779343727e-02f, +5.271029880e-01f, +5.552064433e-01f, -4.038817105e-02f }, + { -3.776088143e-02f, +5.267515394e-01f, +5.555573834e-01f, -4.042042920e-02f }, + { -3.772832390e-02f, +5.264000917e-01f, +5.559083100e-01f, -4.045268163e-02f }, + { -3.769576473e-02f, +5.260486453e-01f, +5.562592228e-01f, -4.048492829e-02f }, + { -3.766320395e-02f, +5.256972002e-01f, +5.566101215e-01f, -4.051716913e-02f }, + { -3.763064163e-02f, +5.253457567e-01f, +5.569610062e-01f, -4.054940409e-02f }, + { -3.759807780e-02f, +5.249943149e-01f, +5.573118764e-01f, -4.058163314e-02f }, + { -3.756551252e-02f, +5.246428750e-01f, +5.576627322e-01f, -4.061385621e-02f }, + { -3.753294582e-02f, +5.242914371e-01f, +5.580135732e-01f, -4.064607325e-02f }, + { -3.750037777e-02f, +5.239400015e-01f, +5.583643994e-01f, -4.067828422e-02f }, + { -3.746780839e-02f, +5.235885684e-01f, +5.587152105e-01f, -4.071048906e-02f }, + { -3.743523774e-02f, +5.232371378e-01f, +5.590660064e-01f, -4.074268771e-02f }, + { -3.740266587e-02f, +5.228857100e-01f, +5.594167868e-01f, -4.077488014e-02f }, + { -3.737009283e-02f, +5.225342852e-01f, +5.597675516e-01f, -4.080706628e-02f }, + { -3.733751865e-02f, +5.221828634e-01f, +5.601183006e-01f, -4.083924608e-02f }, + { -3.730494338e-02f, +5.218314450e-01f, +5.604690337e-01f, -4.087141949e-02f }, + { -3.727236708e-02f, +5.214800301e-01f, +5.608197506e-01f, -4.090358647e-02f }, + { -3.723978979e-02f, +5.211286188e-01f, +5.611704512e-01f, -4.093574695e-02f }, + { -3.720721154e-02f, +5.207772113e-01f, +5.615211353e-01f, -4.096790089e-02f }, + { -3.717463240e-02f, +5.204258079e-01f, +5.618718027e-01f, -4.100004824e-02f }, + { -3.714205241e-02f, +5.200744086e-01f, +5.622224532e-01f, -4.103218893e-02f }, + { -3.710947160e-02f, +5.197230137e-01f, +5.625730867e-01f, -4.106432293e-02f }, + { -3.707689003e-02f, +5.193716233e-01f, +5.629237029e-01f, -4.109645017e-02f }, + { -3.704430775e-02f, +5.190202376e-01f, +5.632743017e-01f, -4.112857061e-02f }, + { -3.701172480e-02f, +5.186688568e-01f, +5.636248829e-01f, -4.116068419e-02f }, + { -3.697914122e-02f, +5.183174810e-01f, +5.639754463e-01f, -4.119279087e-02f }, + { -3.694655706e-02f, +5.179661105e-01f, +5.643259918e-01f, -4.122489058e-02f }, + { -3.691397237e-02f, +5.176147454e-01f, +5.646765191e-01f, -4.125698327e-02f }, + { -3.688138720e-02f, +5.172633859e-01f, +5.650270281e-01f, -4.128906890e-02f }, + { -3.684880158e-02f, +5.169120321e-01f, +5.653775186e-01f, -4.132114741e-02f }, + { -3.681621556e-02f, +5.165606843e-01f, +5.657279905e-01f, -4.135321875e-02f }, + { -3.678362919e-02f, +5.162093426e-01f, +5.660784434e-01f, -4.138528287e-02f }, + { -3.675104252e-02f, +5.158580071e-01f, +5.664288773e-01f, -4.141733970e-02f }, + { -3.671845559e-02f, +5.155066781e-01f, +5.667792920e-01f, -4.144938921e-02f }, + { -3.668586844e-02f, +5.151553558e-01f, +5.671296873e-01f, -4.148143133e-02f }, + { -3.665328113e-02f, +5.148040402e-01f, +5.674800629e-01f, -4.151346602e-02f }, + { -3.662069369e-02f, +5.144527316e-01f, +5.678304188e-01f, -4.154549322e-02f }, + { -3.658810617e-02f, +5.141014302e-01f, +5.681807548e-01f, -4.157751288e-02f }, + { -3.655551861e-02f, +5.137501361e-01f, +5.685310706e-01f, -4.160952494e-02f }, + { -3.652293107e-02f, +5.133988495e-01f, +5.688813660e-01f, -4.164152936e-02f }, + { -3.649034358e-02f, +5.130475706e-01f, +5.692316410e-01f, -4.167352607e-02f }, + { -3.645775620e-02f, +5.126962996e-01f, +5.695818953e-01f, -4.170551503e-02f }, + { -3.642516896e-02f, +5.123450366e-01f, +5.699321287e-01f, -4.173749618e-02f }, + { -3.639258191e-02f, +5.119937817e-01f, +5.702823411e-01f, -4.176946947e-02f }, + { -3.635999510e-02f, +5.116425353e-01f, +5.706325323e-01f, -4.180143485e-02f }, + { -3.632740857e-02f, +5.112912974e-01f, +5.709827020e-01f, -4.183339226e-02f }, + { -3.629482236e-02f, +5.109400682e-01f, +5.713328502e-01f, -4.186534165e-02f }, + { -3.626223652e-02f, +5.105888479e-01f, +5.716829766e-01f, -4.189728297e-02f }, + { -3.622965110e-02f, +5.102376367e-01f, +5.720330810e-01f, -4.192921615e-02f }, + { -3.619706614e-02f, +5.098864348e-01f, +5.723831633e-01f, -4.196114116e-02f }, + { -3.616448168e-02f, +5.095352422e-01f, +5.727332232e-01f, -4.199305793e-02f }, + { -3.613189776e-02f, +5.091840593e-01f, +5.730832607e-01f, -4.202496641e-02f }, + { -3.609931444e-02f, +5.088328861e-01f, +5.734332754e-01f, -4.205686655e-02f }, + { -3.606673176e-02f, +5.084817229e-01f, +5.737832673e-01f, -4.208875830e-02f }, + { -3.603414976e-02f, +5.081305697e-01f, +5.741332362e-01f, -4.212064159e-02f }, + { -3.600156848e-02f, +5.077794269e-01f, +5.744831818e-01f, -4.215251638e-02f }, + { -3.596898797e-02f, +5.074282945e-01f, +5.748331040e-01f, -4.218438261e-02f }, + { -3.593640828e-02f, +5.070771728e-01f, +5.751830026e-01f, -4.221624023e-02f }, + { -3.590382944e-02f, +5.067260619e-01f, +5.755328774e-01f, -4.224808919e-02f }, + { -3.587125150e-02f, +5.063749619e-01f, +5.758827283e-01f, -4.227992942e-02f }, + { -3.583867451e-02f, +5.060238731e-01f, +5.762325550e-01f, -4.231176088e-02f }, + { -3.580609851e-02f, +5.056727956e-01f, +5.765823574e-01f, -4.234358351e-02f }, + { -3.577352355e-02f, +5.053217296e-01f, +5.769321353e-01f, -4.237539726e-02f }, + { -3.574094966e-02f, +5.049706753e-01f, +5.772818885e-01f, -4.240720208e-02f }, + { -3.570837689e-02f, +5.046196329e-01f, +5.776316168e-01f, -4.243899790e-02f }, + { -3.567580528e-02f, +5.042686025e-01f, +5.779813201e-01f, -4.247078467e-02f }, + { -3.564323489e-02f, +5.039175842e-01f, +5.783309981e-01f, -4.250256235e-02f }, + { -3.561066574e-02f, +5.035665783e-01f, +5.786806507e-01f, -4.253433087e-02f }, + { -3.557809789e-02f, +5.032155850e-01f, +5.790302776e-01f, -4.256609018e-02f }, + { -3.554553138e-02f, +5.028646044e-01f, +5.793798788e-01f, -4.259784023e-02f }, + { -3.551296626e-02f, +5.025136366e-01f, +5.797294541e-01f, -4.262958096e-02f }, + { -3.548040255e-02f, +5.021626819e-01f, +5.800790031e-01f, -4.266131231e-02f }, + { -3.544784032e-02f, +5.018117405e-01f, +5.804285259e-01f, -4.269303424e-02f }, + { -3.541527960e-02f, +5.014608124e-01f, +5.807780221e-01f, -4.272474669e-02f }, + { -3.538272044e-02f, +5.011098979e-01f, +5.811274916e-01f, -4.275644960e-02f }, + { -3.535016287e-02f, +5.007589972e-01f, +5.814769342e-01f, -4.278814292e-02f }, + { -3.531760695e-02f, +5.004081103e-01f, +5.818263498e-01f, -4.281982659e-02f }, + { -3.528505271e-02f, +5.000572376e-01f, +5.821757381e-01f, -4.285150055e-02f }, + { -3.525250020e-02f, +4.997063791e-01f, +5.825250990e-01f, -4.288316476e-02f }, + { -3.521994946e-02f, +4.993555351e-01f, +5.828744322e-01f, -4.291481916e-02f }, + { -3.518740053e-02f, +4.990047056e-01f, +5.832237377e-01f, -4.294646369e-02f }, + { -3.515485346e-02f, +4.986538910e-01f, +5.835730151e-01f, -4.297809830e-02f }, + { -3.512230829e-02f, +4.983030913e-01f, +5.839222644e-01f, -4.300972293e-02f }, + { -3.508976506e-02f, +4.979523067e-01f, +5.842714854e-01f, -4.304133752e-02f }, + { -3.505722382e-02f, +4.976015374e-01f, +5.846206778e-01f, -4.307294203e-02f }, + { -3.502468461e-02f, +4.972507836e-01f, +5.849698415e-01f, -4.310453640e-02f }, + { -3.499214746e-02f, +4.969000454e-01f, +5.853189763e-01f, -4.313612056e-02f }, + { -3.495961243e-02f, +4.965493230e-01f, +5.856680820e-01f, -4.316769447e-02f }, + { -3.492707956e-02f, +4.961986166e-01f, +5.860171584e-01f, -4.319925807e-02f }, + { -3.489454888e-02f, +4.958479263e-01f, +5.863662054e-01f, -4.323081130e-02f }, + { -3.486202044e-02f, +4.954972524e-01f, +5.867152227e-01f, -4.326235411e-02f }, + { -3.482949429e-02f, +4.951465949e-01f, +5.870642103e-01f, -4.329388645e-02f }, + { -3.479697046e-02f, +4.947959542e-01f, +5.874131678e-01f, -4.332540825e-02f }, + { -3.476444900e-02f, +4.944453302e-01f, +5.877620952e-01f, -4.335691946e-02f }, + { -3.473192994e-02f, +4.940947233e-01f, +5.881109921e-01f, -4.338842003e-02f }, + { -3.469941334e-02f, +4.937441335e-01f, +5.884598586e-01f, -4.341990989e-02f }, + { -3.466689923e-02f, +4.933935611e-01f, +5.888086942e-01f, -4.345138900e-02f }, + { -3.463438766e-02f, +4.930430062e-01f, +5.891574990e-01f, -4.348285730e-02f }, + { -3.460187866e-02f, +4.926924690e-01f, +5.895062727e-01f, -4.351431473e-02f }, + { -3.456937229e-02f, +4.923419497e-01f, +5.898550151e-01f, -4.354576123e-02f }, + { -3.453686857e-02f, +4.919914484e-01f, +5.902037260e-01f, -4.357719676e-02f }, + { -3.450436756e-02f, +4.916409653e-01f, +5.905524052e-01f, -4.360862124e-02f }, + { -3.447186930e-02f, +4.912905006e-01f, +5.909010526e-01f, -4.364003464e-02f }, + { -3.443937382e-02f, +4.909400544e-01f, +5.912496680e-01f, -4.367143688e-02f }, + { -3.440688117e-02f, +4.905896269e-01f, +5.915982512e-01f, -4.370282792e-02f }, + { -3.437439139e-02f, +4.902392184e-01f, +5.919468020e-01f, -4.373420769e-02f }, + { -3.434190452e-02f, +4.898888288e-01f, +5.922953202e-01f, -4.376557615e-02f }, + { -3.430942060e-02f, +4.895384585e-01f, +5.926438057e-01f, -4.379693323e-02f }, + { -3.427693968e-02f, +4.891881076e-01f, +5.929922582e-01f, -4.382827888e-02f }, + { -3.424446179e-02f, +4.888377763e-01f, +5.933406776e-01f, -4.385961304e-02f }, + { -3.421198698e-02f, +4.884874647e-01f, +5.936890637e-01f, -4.389093566e-02f }, + { -3.417951529e-02f, +4.881371730e-01f, +5.940374163e-01f, -4.392224667e-02f }, + { -3.414704676e-02f, +4.877869014e-01f, +5.943857352e-01f, -4.395354603e-02f }, + { -3.411458143e-02f, +4.874366500e-01f, +5.947340203e-01f, -4.398483367e-02f }, + { -3.408211934e-02f, +4.870864191e-01f, +5.950822713e-01f, -4.401610954e-02f }, + { -3.404966054e-02f, +4.867362087e-01f, +5.954304881e-01f, -4.404737358e-02f }, + { -3.401720506e-02f, +4.863860191e-01f, +5.957786704e-01f, -4.407862573e-02f }, + { -3.398475294e-02f, +4.860358504e-01f, +5.961268182e-01f, -4.410986594e-02f }, + { -3.395230423e-02f, +4.856857028e-01f, +5.964749312e-01f, -4.414109415e-02f }, + { -3.391985897e-02f, +4.853355764e-01f, +5.968230092e-01f, -4.417231031e-02f }, + { -3.388741720e-02f, +4.849854715e-01f, +5.971710521e-01f, -4.420351435e-02f }, + { -3.385497895e-02f, +4.846353882e-01f, +5.975190596e-01f, -4.423470622e-02f }, + { -3.382254427e-02f, +4.842853267e-01f, +5.978670316e-01f, -4.426588586e-02f }, + { -3.379011321e-02f, +4.839352871e-01f, +5.982149679e-01f, -4.429705321e-02f }, + { -3.375768579e-02f, +4.835852697e-01f, +5.985628683e-01f, -4.432820823e-02f }, + { -3.372526206e-02f, +4.832352745e-01f, +5.989107327e-01f, -4.435935084e-02f }, + { -3.369284207e-02f, +4.828853017e-01f, +5.992585607e-01f, -4.439048099e-02f }, + { -3.366042585e-02f, +4.825353516e-01f, +5.996063524e-01f, -4.442159863e-02f }, + { -3.362801344e-02f, +4.821854242e-01f, +5.999541074e-01f, -4.445270370e-02f }, + { -3.359560488e-02f, +4.818355198e-01f, +6.003018256e-01f, -4.448379613e-02f }, + { -3.356320022e-02f, +4.814856386e-01f, +6.006495068e-01f, -4.451487588e-02f }, + { -3.353079949e-02f, +4.811357806e-01f, +6.009971508e-01f, -4.454594288e-02f }, + { -3.349840273e-02f, +4.807859461e-01f, +6.013447575e-01f, -4.457699708e-02f }, + { -3.346600999e-02f, +4.804361352e-01f, +6.016923266e-01f, -4.460803842e-02f }, + { -3.343362130e-02f, +4.800863481e-01f, +6.020398580e-01f, -4.463906683e-02f }, + { -3.340123671e-02f, +4.797365850e-01f, +6.023873514e-01f, -4.467008228e-02f }, + { -3.336885624e-02f, +4.793868460e-01f, +6.027348068e-01f, -4.470108468e-02f }, + { -3.333647996e-02f, +4.790371313e-01f, +6.030822239e-01f, -4.473207400e-02f }, + { -3.330410788e-02f, +4.786874411e-01f, +6.034296025e-01f, -4.476305016e-02f }, + { -3.327174006e-02f, +4.783377756e-01f, +6.037769424e-01f, -4.479401311e-02f }, + { -3.323937653e-02f, +4.779881348e-01f, +6.041242435e-01f, -4.482496280e-02f }, + { -3.320701734e-02f, +4.776385190e-01f, +6.044715056e-01f, -4.485589916e-02f }, + { -3.317466252e-02f, +4.772889284e-01f, +6.048187284e-01f, -4.488682214e-02f }, + { -3.314231211e-02f, +4.769393630e-01f, +6.051659119e-01f, -4.491773168e-02f }, + { -3.310996615e-02f, +4.765898232e-01f, +6.055130558e-01f, -4.494862772e-02f }, + { -3.307762468e-02f, +4.762403090e-01f, +6.058601599e-01f, -4.497951020e-02f }, + { -3.304528775e-02f, +4.758908206e-01f, +6.062072240e-01f, -4.501037906e-02f }, + { -3.301295538e-02f, +4.755413581e-01f, +6.065542481e-01f, -4.504123425e-02f }, + { -3.298062762e-02f, +4.751919219e-01f, +6.069012318e-01f, -4.507207570e-02f }, + { -3.294830451e-02f, +4.748425119e-01f, +6.072481750e-01f, -4.510290336e-02f }, + { -3.291598609e-02f, +4.744931285e-01f, +6.075950775e-01f, -4.513371718e-02f }, + { -3.288367240e-02f, +4.741437716e-01f, +6.079419391e-01f, -4.516451708e-02f }, + { -3.285136347e-02f, +4.737944416e-01f, +6.082887597e-01f, -4.519530301e-02f }, + { -3.281905935e-02f, +4.734451386e-01f, +6.086355390e-01f, -4.522607492e-02f }, + { -3.278676008e-02f, +4.730958628e-01f, +6.089822769e-01f, -4.525683274e-02f }, + { -3.275446568e-02f, +4.727466142e-01f, +6.093289732e-01f, -4.528757642e-02f }, + { -3.272217621e-02f, +4.723973932e-01f, +6.096756276e-01f, -4.531830590e-02f }, + { -3.268989170e-02f, +4.720481998e-01f, +6.100222401e-01f, -4.534902111e-02f }, + { -3.265761219e-02f, +4.716990342e-01f, +6.103688104e-01f, -4.537972200e-02f }, + { -3.262533772e-02f, +4.713498966e-01f, +6.107153384e-01f, -4.541040851e-02f }, + { -3.259306833e-02f, +4.710007872e-01f, +6.110618238e-01f, -4.544108058e-02f }, + { -3.256080405e-02f, +4.706517061e-01f, +6.114082665e-01f, -4.547173816e-02f }, + { -3.252854493e-02f, +4.703026534e-01f, +6.117546663e-01f, -4.550238117e-02f }, + { -3.249629100e-02f, +4.699536294e-01f, +6.121010230e-01f, -4.553300957e-02f }, + { -3.246404230e-02f, +4.696046343e-01f, +6.124473364e-01f, -4.556362330e-02f }, + { -3.243179888e-02f, +4.692556681e-01f, +6.127936063e-01f, -4.559422228e-02f }, + { -3.239956076e-02f, +4.689067311e-01f, +6.131398326e-01f, -4.562480648e-02f }, + { -3.236732799e-02f, +4.685578234e-01f, +6.134860150e-01f, -4.565537582e-02f }, + { -3.233510060e-02f, +4.682089452e-01f, +6.138321534e-01f, -4.568593024e-02f }, + { -3.230287864e-02f, +4.678600966e-01f, +6.141782476e-01f, -4.571646969e-02f }, + { -3.227066214e-02f, +4.675112778e-01f, +6.145242974e-01f, -4.574699411e-02f }, + { -3.223845114e-02f, +4.671624891e-01f, +6.148703026e-01f, -4.577750344e-02f }, + { -3.220624568e-02f, +4.668137304e-01f, +6.152162631e-01f, -4.580799762e-02f }, + { -3.217404580e-02f, +4.664650021e-01f, +6.155621786e-01f, -4.583847658e-02f }, + { -3.214185153e-02f, +4.661163043e-01f, +6.159080490e-01f, -4.586894027e-02f }, + { -3.210966291e-02f, +4.657676371e-01f, +6.162538740e-01f, -4.589938863e-02f }, + { -3.207747998e-02f, +4.654190007e-01f, +6.165996536e-01f, -4.592982160e-02f }, + { -3.204530278e-02f, +4.650703953e-01f, +6.169453874e-01f, -4.596023912e-02f }, + { -3.201313134e-02f, +4.647218210e-01f, +6.172910754e-01f, -4.599064113e-02f }, + { -3.198096571e-02f, +4.643732781e-01f, +6.176367173e-01f, -4.602102757e-02f }, + { -3.194880592e-02f, +4.640247666e-01f, +6.179823129e-01f, -4.605139837e-02f }, + { -3.191665200e-02f, +4.636762867e-01f, +6.183278621e-01f, -4.608175349e-02f }, + { -3.188450401e-02f, +4.633278387e-01f, +6.186733647e-01f, -4.611209285e-02f }, + { -3.185236196e-02f, +4.629794226e-01f, +6.190188205e-01f, -4.614241641e-02f }, + { -3.182022591e-02f, +4.626310387e-01f, +6.193642293e-01f, -4.617272409e-02f }, + { -3.178809589e-02f, +4.622826870e-01f, +6.197095909e-01f, -4.620301584e-02f }, + { -3.175597193e-02f, +4.619343678e-01f, +6.200549052e-01f, -4.623329159e-02f }, + { -3.172385407e-02f, +4.615860812e-01f, +6.204001719e-01f, -4.626355130e-02f }, + { -3.169174236e-02f, +4.612378274e-01f, +6.207453909e-01f, -4.629379489e-02f }, + { -3.165963682e-02f, +4.608896066e-01f, +6.210905619e-01f, -4.632402231e-02f }, + { -3.162753750e-02f, +4.605414189e-01f, +6.214356849e-01f, -4.635423350e-02f }, + { -3.159544443e-02f, +4.601932645e-01f, +6.217807595e-01f, -4.638442839e-02f }, + { -3.156335765e-02f, +4.598451435e-01f, +6.221257857e-01f, -4.641460692e-02f }, + { -3.153127720e-02f, +4.594970561e-01f, +6.224707632e-01f, -4.644476904e-02f }, + { -3.149920310e-02f, +4.591490025e-01f, +6.228156918e-01f, -4.647491468e-02f }, + { -3.146713541e-02f, +4.588009829e-01f, +6.231605715e-01f, -4.650504379e-02f }, + { -3.143507415e-02f, +4.584529973e-01f, +6.235054019e-01f, -4.653515630e-02f }, + { -3.140301937e-02f, +4.581050460e-01f, +6.238501829e-01f, -4.656525215e-02f }, + { -3.137097110e-02f, +4.577571292e-01f, +6.241949143e-01f, -4.659533127e-02f }, + { -3.133892937e-02f, +4.574092469e-01f, +6.245395959e-01f, -4.662539362e-02f }, + { -3.130689423e-02f, +4.570613994e-01f, +6.248842275e-01f, -4.665543913e-02f }, + { -3.127486571e-02f, +4.567135869e-01f, +6.252288091e-01f, -4.668546773e-02f }, + { -3.124284384e-02f, +4.563658094e-01f, +6.255733402e-01f, -4.671547937e-02f }, + { -3.121082867e-02f, +4.560180671e-01f, +6.259178209e-01f, -4.674547399e-02f }, + { -3.117882023e-02f, +4.556703603e-01f, +6.262622508e-01f, -4.677545152e-02f }, + { -3.114681855e-02f, +4.553226890e-01f, +6.266066299e-01f, -4.680541190e-02f }, + { -3.111482367e-02f, +4.549750535e-01f, +6.269509578e-01f, -4.683535507e-02f }, + { -3.108283564e-02f, +4.546274539e-01f, +6.272952345e-01f, -4.686528098e-02f }, + { -3.105085447e-02f, +4.542798904e-01f, +6.276394598e-01f, -4.689518955e-02f }, + { -3.101888022e-02f, +4.539323631e-01f, +6.279836334e-01f, -4.692508073e-02f }, + { -3.098691291e-02f, +4.535848721e-01f, +6.283277552e-01f, -4.695495446e-02f }, + { -3.095495259e-02f, +4.532374178e-01f, +6.286718249e-01f, -4.698481067e-02f }, + { -3.092299929e-02f, +4.528900001e-01f, +6.290158425e-01f, -4.701464930e-02f }, + { -3.089105304e-02f, +4.525426193e-01f, +6.293598077e-01f, -4.704447029e-02f }, + { -3.085911388e-02f, +4.521952756e-01f, +6.297037204e-01f, -4.707427359e-02f }, + { -3.082718185e-02f, +4.518479691e-01f, +6.300475802e-01f, -4.710405912e-02f }, + { -3.079525698e-02f, +4.515006999e-01f, +6.303913872e-01f, -4.713382682e-02f }, + { -3.076333930e-02f, +4.511534683e-01f, +6.307351410e-01f, -4.716357665e-02f }, + { -3.073142887e-02f, +4.508062744e-01f, +6.310788415e-01f, -4.719330852e-02f }, + { -3.069952570e-02f, +4.504591183e-01f, +6.314224885e-01f, -4.722302238e-02f }, + { -3.066762983e-02f, +4.501120002e-01f, +6.317660818e-01f, -4.725271818e-02f }, + { -3.063574131e-02f, +4.497649203e-01f, +6.321096212e-01f, -4.728239584e-02f }, + { -3.060386016e-02f, +4.494178788e-01f, +6.324531066e-01f, -4.731205530e-02f }, + { -3.057198642e-02f, +4.490708757e-01f, +6.327965377e-01f, -4.734169651e-02f }, + { -3.054012013e-02f, +4.487239113e-01f, +6.331399144e-01f, -4.737131940e-02f }, + { -3.050826133e-02f, +4.483769858e-01f, +6.334832365e-01f, -4.740092391e-02f }, + { -3.047641003e-02f, +4.480300992e-01f, +6.338265038e-01f, -4.743050997e-02f }, + { -3.044456630e-02f, +4.476832518e-01f, +6.341697161e-01f, -4.746007752e-02f }, + { -3.041273015e-02f, +4.473364437e-01f, +6.345128733e-01f, -4.748962651e-02f }, + { -3.038090162e-02f, +4.469896750e-01f, +6.348559750e-01f, -4.751915687e-02f }, + { -3.034908075e-02f, +4.466429460e-01f, +6.351990212e-01f, -4.754866853e-02f }, + { -3.031726757e-02f, +4.462962568e-01f, +6.355420117e-01f, -4.757816144e-02f }, + { -3.028546212e-02f, +4.459496076e-01f, +6.358849463e-01f, -4.760763553e-02f }, + { -3.025366443e-02f, +4.456029984e-01f, +6.362278248e-01f, -4.763709074e-02f }, + { -3.022187454e-02f, +4.452564296e-01f, +6.365706469e-01f, -4.766652701e-02f }, + { -3.019009249e-02f, +4.449099012e-01f, +6.369134126e-01f, -4.769594427e-02f }, + { -3.015831830e-02f, +4.445634133e-01f, +6.372561217e-01f, -4.772534246e-02f }, + { -3.012655201e-02f, +4.442169663e-01f, +6.375987738e-01f, -4.775472152e-02f }, + { -3.009479366e-02f, +4.438705601e-01f, +6.379413690e-01f, -4.778408139e-02f }, + { -3.006304328e-02f, +4.435241951e-01f, +6.382839069e-01f, -4.781342200e-02f }, + { -3.003130090e-02f, +4.431778713e-01f, +6.386263874e-01f, -4.784274329e-02f }, + { -2.999956656e-02f, +4.428315888e-01f, +6.389688103e-01f, -4.787204520e-02f }, + { -2.996784030e-02f, +4.424853480e-01f, +6.393111754e-01f, -4.790132766e-02f }, + { -2.993612215e-02f, +4.421391489e-01f, +6.396534826e-01f, -4.793059062e-02f }, + { -2.990441214e-02f, +4.417929916e-01f, +6.399957316e-01f, -4.795983400e-02f }, + { -2.987271031e-02f, +4.414468764e-01f, +6.403379223e-01f, -4.798905775e-02f }, + { -2.984101669e-02f, +4.411008034e-01f, +6.406800544e-01f, -4.801826180e-02f }, + { -2.980933131e-02f, +4.407547728e-01f, +6.410221278e-01f, -4.804744609e-02f }, + { -2.977765422e-02f, +4.404087847e-01f, +6.413641423e-01f, -4.807661056e-02f }, + { -2.974598544e-02f, +4.400628392e-01f, +6.417060978e-01f, -4.810575513e-02f }, + { -2.971432501e-02f, +4.397169367e-01f, +6.420479939e-01f, -4.813487976e-02f }, + { -2.968267296e-02f, +4.393710771e-01f, +6.423898306e-01f, -4.816398438e-02f }, + { -2.965102932e-02f, +4.390252607e-01f, +6.427316077e-01f, -4.819306891e-02f }, + { -2.961939414e-02f, +4.386794876e-01f, +6.430733249e-01f, -4.822213331e-02f }, + { -2.958776743e-02f, +4.383337580e-01f, +6.434149821e-01f, -4.825117750e-02f }, + { -2.955614925e-02f, +4.379880720e-01f, +6.437565791e-01f, -4.828020142e-02f }, + { -2.952453962e-02f, +4.376424298e-01f, +6.440981157e-01f, -4.830920501e-02f }, + { -2.949293857e-02f, +4.372968316e-01f, +6.444395917e-01f, -4.833818821e-02f }, + { -2.946134614e-02f, +4.369512775e-01f, +6.447810070e-01f, -4.836715094e-02f }, + { -2.942976236e-02f, +4.366057677e-01f, +6.451223613e-01f, -4.839609316e-02f }, + { -2.939818727e-02f, +4.362603023e-01f, +6.454636545e-01f, -4.842501479e-02f }, + { -2.936662089e-02f, +4.359148815e-01f, +6.458048863e-01f, -4.845391577e-02f }, + { -2.933506327e-02f, +4.355695055e-01f, +6.461460567e-01f, -4.848279603e-02f }, + { -2.930351443e-02f, +4.352241743e-01f, +6.464871653e-01f, -4.851165552e-02f }, + { -2.927197441e-02f, +4.348788883e-01f, +6.468282121e-01f, -4.854049416e-02f }, + { -2.924044325e-02f, +4.345336475e-01f, +6.471691968e-01f, -4.856931190e-02f }, + { -2.920892096e-02f, +4.341884520e-01f, +6.475101192e-01f, -4.859810867e-02f }, + { -2.917740760e-02f, +4.338433021e-01f, +6.478509792e-01f, -4.862688440e-02f }, + { -2.914590319e-02f, +4.334981980e-01f, +6.481917765e-01f, -4.865563904e-02f }, + { -2.911440776e-02f, +4.331531396e-01f, +6.485325111e-01f, -4.868437251e-02f }, + { -2.908292135e-02f, +4.328081273e-01f, +6.488731826e-01f, -4.871308476e-02f }, + { -2.905144399e-02f, +4.324631612e-01f, +6.492137910e-01f, -4.874177572e-02f }, + { -2.901997572e-02f, +4.321182414e-01f, +6.495543359e-01f, -4.877044532e-02f }, + { -2.898851656e-02f, +4.317733681e-01f, +6.498948173e-01f, -4.879909350e-02f }, + { -2.895706654e-02f, +4.314285415e-01f, +6.502352350e-01f, -4.882772020e-02f }, + { -2.892562571e-02f, +4.310837617e-01f, +6.505755887e-01f, -4.885632535e-02f }, + { -2.889419410e-02f, +4.307390288e-01f, +6.509158783e-01f, -4.888490889e-02f }, + { -2.886277173e-02f, +4.303943430e-01f, +6.512561036e-01f, -4.891347075e-02f }, + { -2.883135864e-02f, +4.300497046e-01f, +6.515962644e-01f, -4.894201087e-02f }, + { -2.879995486e-02f, +4.297051136e-01f, +6.519363605e-01f, -4.897052918e-02f }, + { -2.876856043e-02f, +4.293605701e-01f, +6.522763918e-01f, -4.899902562e-02f }, + { -2.873717537e-02f, +4.290160745e-01f, +6.526163580e-01f, -4.902750012e-02f }, + { -2.870579972e-02f, +4.286716267e-01f, +6.529562589e-01f, -4.905595262e-02f }, + { -2.867443352e-02f, +4.283272270e-01f, +6.532960945e-01f, -4.908438306e-02f }, + { -2.864307678e-02f, +4.279828756e-01f, +6.536358644e-01f, -4.911279137e-02f }, + { -2.861172956e-02f, +4.276385725e-01f, +6.539755685e-01f, -4.914117748e-02f }, + { -2.858039187e-02f, +4.272943179e-01f, +6.543152066e-01f, -4.916954133e-02f }, + { -2.854906375e-02f, +4.269501121e-01f, +6.546547786e-01f, -4.919788286e-02f }, + { -2.851774523e-02f, +4.266059551e-01f, +6.549942842e-01f, -4.922620200e-02f }, + { -2.848643635e-02f, +4.262618471e-01f, +6.553337232e-01f, -4.925449868e-02f }, + { -2.845513713e-02f, +4.259177883e-01f, +6.556730955e-01f, -4.928277284e-02f }, + { -2.842384761e-02f, +4.255737788e-01f, +6.560124009e-01f, -4.931102441e-02f }, + { -2.839256782e-02f, +4.252298187e-01f, +6.563516392e-01f, -4.933925334e-02f }, + { -2.836129779e-02f, +4.248859083e-01f, +6.566908102e-01f, -4.936745955e-02f }, + { -2.833003756e-02f, +4.245420477e-01f, +6.570299137e-01f, -4.939564297e-02f }, + { -2.829878715e-02f, +4.241982371e-01f, +6.573689495e-01f, -4.942380356e-02f }, + { -2.826754660e-02f, +4.238544765e-01f, +6.577079175e-01f, -4.945194122e-02f }, + { -2.823631593e-02f, +4.235107662e-01f, +6.580468175e-01f, -4.948005591e-02f }, + { -2.820509519e-02f, +4.231671063e-01f, +6.583856492e-01f, -4.950814756e-02f }, + { -2.817388439e-02f, +4.228234970e-01f, +6.587244125e-01f, -4.953621610e-02f }, + { -2.814268358e-02f, +4.224799384e-01f, +6.590631072e-01f, -4.956426147e-02f }, + { -2.811149279e-02f, +4.221364307e-01f, +6.594017331e-01f, -4.959228359e-02f }, + { -2.808031203e-02f, +4.217929740e-01f, +6.597402901e-01f, -4.962028241e-02f }, + { -2.804914136e-02f, +4.214495685e-01f, +6.600787779e-01f, -4.964825786e-02f }, + { -2.801798079e-02f, +4.211062143e-01f, +6.604171963e-01f, -4.967620987e-02f }, + { -2.798683036e-02f, +4.207629117e-01f, +6.607555453e-01f, -4.970413838e-02f }, + { -2.795569010e-02f, +4.204196607e-01f, +6.610938245e-01f, -4.973204333e-02f }, + { -2.792456005e-02f, +4.200764615e-01f, +6.614320337e-01f, -4.975992463e-02f }, + { -2.789344022e-02f, +4.197333143e-01f, +6.617701729e-01f, -4.978778224e-02f }, + { -2.786233066e-02f, +4.193902192e-01f, +6.621082419e-01f, -4.981561608e-02f }, + { -2.783123139e-02f, +4.190471763e-01f, +6.624462403e-01f, -4.984342609e-02f }, + { -2.780014245e-02f, +4.187041859e-01f, +6.627841681e-01f, -4.987121220e-02f }, + { -2.776906386e-02f, +4.183612481e-01f, +6.631220251e-01f, -4.989897435e-02f }, + { -2.773799566e-02f, +4.180183630e-01f, +6.634598110e-01f, -4.992671247e-02f }, + { -2.770693788e-02f, +4.176755308e-01f, +6.637975258e-01f, -4.995442649e-02f }, + { -2.767589054e-02f, +4.173327517e-01f, +6.641351691e-01f, -4.998211634e-02f }, + { -2.764485368e-02f, +4.169900257e-01f, +6.644727409e-01f, -5.000978197e-02f }, + { -2.761382734e-02f, +4.166473531e-01f, +6.648102408e-01f, -5.003742330e-02f }, + { -2.758281153e-02f, +4.163047340e-01f, +6.651476689e-01f, -5.006504027e-02f }, + { -2.755180629e-02f, +4.159621686e-01f, +6.654850247e-01f, -5.009263282e-02f }, + { -2.752081165e-02f, +4.156196570e-01f, +6.658223083e-01f, -5.012020087e-02f }, + { -2.748982764e-02f, +4.152771994e-01f, +6.661595193e-01f, -5.014774435e-02f }, + { -2.745885430e-02f, +4.149347959e-01f, +6.664966577e-01f, -5.017526321e-02f }, + { -2.742789164e-02f, +4.145924466e-01f, +6.668337231e-01f, -5.020275738e-02f }, + { -2.739693971e-02f, +4.142501518e-01f, +6.671707155e-01f, -5.023022678e-02f }, + { -2.736599852e-02f, +4.139079116e-01f, +6.675076346e-01f, -5.025767136e-02f }, + { -2.733506812e-02f, +4.135657261e-01f, +6.678444802e-01f, -5.028509105e-02f }, + { -2.730414853e-02f, +4.132235955e-01f, +6.681812522e-01f, -5.031248577e-02f }, + { -2.727323979e-02f, +4.128815199e-01f, +6.685179504e-01f, -5.033985546e-02f }, + { -2.724234191e-02f, +4.125394995e-01f, +6.688545746e-01f, -5.036720007e-02f }, + { -2.721145493e-02f, +4.121975345e-01f, +6.691911246e-01f, -5.039451951e-02f }, + { -2.718057889e-02f, +4.118556250e-01f, +6.695276002e-01f, -5.042181372e-02f }, + { -2.714971381e-02f, +4.115137711e-01f, +6.698640012e-01f, -5.044908263e-02f }, + { -2.711885972e-02f, +4.111719731e-01f, +6.702003275e-01f, -5.047632619e-02f }, + { -2.708801665e-02f, +4.108302310e-01f, +6.705365788e-01f, -5.050354431e-02f }, + { -2.705718463e-02f, +4.104885450e-01f, +6.708727551e-01f, -5.053073694e-02f }, + { -2.702636369e-02f, +4.101469153e-01f, +6.712088560e-01f, -5.055790401e-02f }, + { -2.699555385e-02f, +4.098053420e-01f, +6.715448814e-01f, -5.058504544e-02f }, + { -2.696475516e-02f, +4.094638252e-01f, +6.718808311e-01f, -5.061216118e-02f }, + { -2.693396764e-02f, +4.091223652e-01f, +6.722167049e-01f, -5.063925115e-02f }, + { -2.690319131e-02f, +4.087809621e-01f, +6.725525027e-01f, -5.066631529e-02f }, + { -2.687242621e-02f, +4.084396159e-01f, +6.728882242e-01f, -5.069335353e-02f }, + { -2.684167237e-02f, +4.080983270e-01f, +6.732238693e-01f, -5.072036581e-02f }, + { -2.681092981e-02f, +4.077570954e-01f, +6.735594378e-01f, -5.074735205e-02f }, + { -2.678019856e-02f, +4.074159212e-01f, +6.738949295e-01f, -5.077431218e-02f }, + { -2.674947866e-02f, +4.070748047e-01f, +6.742303442e-01f, -5.080124615e-02f }, + { -2.671877013e-02f, +4.067337460e-01f, +6.745656817e-01f, -5.082815388e-02f }, + { -2.668807301e-02f, +4.063927452e-01f, +6.749009418e-01f, -5.085503531e-02f }, + { -2.665738731e-02f, +4.060518025e-01f, +6.752361244e-01f, -5.088189036e-02f }, + { -2.662671308e-02f, +4.057109180e-01f, +6.755712292e-01f, -5.090871897e-02f }, + { -2.659605033e-02f, +4.053700919e-01f, +6.759062562e-01f, -5.093552108e-02f }, + { -2.656539910e-02f, +4.050293243e-01f, +6.762412050e-01f, -5.096229661e-02f }, + { -2.653475941e-02f, +4.046886155e-01f, +6.765760755e-01f, -5.098904550e-02f }, + { -2.650413130e-02f, +4.043479654e-01f, +6.769108675e-01f, -5.101576767e-02f }, + { -2.647351480e-02f, +4.040073744e-01f, +6.772455809e-01f, -5.104246307e-02f }, + { -2.644290992e-02f, +4.036668425e-01f, +6.775802154e-01f, -5.106913162e-02f }, + { -2.641231671e-02f, +4.033263699e-01f, +6.779147709e-01f, -5.109577326e-02f }, + { -2.638173519e-02f, +4.029859567e-01f, +6.782492471e-01f, -5.112238791e-02f }, + { -2.635116538e-02f, +4.026456031e-01f, +6.785836440e-01f, -5.114897551e-02f }, + { -2.632060732e-02f, +4.023053093e-01f, +6.789179612e-01f, -5.117553600e-02f }, + { -2.629006103e-02f, +4.019650754e-01f, +6.792521986e-01f, -5.120206929e-02f }, + { -2.625952655e-02f, +4.016249015e-01f, +6.795863561e-01f, -5.122857533e-02f }, + { -2.622900390e-02f, +4.012847878e-01f, +6.799204334e-01f, -5.125505405e-02f }, + { -2.619849310e-02f, +4.009447344e-01f, +6.802544304e-01f, -5.128150537e-02f }, + { -2.616799420e-02f, +4.006047415e-01f, +6.805883468e-01f, -5.130792924e-02f }, + { -2.613750720e-02f, +4.002648093e-01f, +6.809221825e-01f, -5.133432558e-02f }, + { -2.610703216e-02f, +3.999249379e-01f, +6.812559373e-01f, -5.136069431e-02f }, + { -2.607656908e-02f, +3.995851274e-01f, +6.815896110e-01f, -5.138703539e-02f }, + { -2.604611800e-02f, +3.992453779e-01f, +6.819232035e-01f, -5.141334873e-02f }, + { -2.601567895e-02f, +3.989056898e-01f, +6.822567144e-01f, -5.143963427e-02f }, + { -2.598525196e-02f, +3.985660630e-01f, +6.825901438e-01f, -5.146589193e-02f }, + { -2.595483705e-02f, +3.982264977e-01f, +6.829234913e-01f, -5.149212166e-02f }, + { -2.592443425e-02f, +3.978869942e-01f, +6.832567567e-01f, -5.151832338e-02f }, + { -2.589404358e-02f, +3.975475525e-01f, +6.835899400e-01f, -5.154449702e-02f }, + { -2.586366508e-02f, +3.972081727e-01f, +6.839230409e-01f, -5.157064252e-02f }, + { -2.583329878e-02f, +3.968688551e-01f, +6.842560591e-01f, -5.159675980e-02f }, + { -2.580294470e-02f, +3.965295998e-01f, +6.845889947e-01f, -5.162284880e-02f }, + { -2.577260287e-02f, +3.961904069e-01f, +6.849218472e-01f, -5.164890945e-02f }, + { -2.574227331e-02f, +3.958512766e-01f, +6.852546167e-01f, -5.167494167e-02f }, + { -2.571195605e-02f, +3.955122090e-01f, +6.855873028e-01f, -5.170094541e-02f }, + { -2.568165113e-02f, +3.951732042e-01f, +6.859199054e-01f, -5.172692059e-02f }, + { -2.565135856e-02f, +3.948342626e-01f, +6.862524243e-01f, -5.175286714e-02f }, + { -2.562107838e-02f, +3.944953840e-01f, +6.865848593e-01f, -5.177878499e-02f }, + { -2.559081062e-02f, +3.941565688e-01f, +6.869172102e-01f, -5.180467408e-02f }, + { -2.556055529e-02f, +3.938178171e-01f, +6.872494769e-01f, -5.183053433e-02f }, + { -2.553031243e-02f, +3.934791290e-01f, +6.875816592e-01f, -5.185636568e-02f }, + { -2.550008206e-02f, +3.931405046e-01f, +6.879137568e-01f, -5.188216805e-02f }, + { -2.546986421e-02f, +3.928019442e-01f, +6.882457697e-01f, -5.190794138e-02f }, + { -2.543965891e-02f, +3.924634478e-01f, +6.885776975e-01f, -5.193368560e-02f }, + { -2.540946619e-02f, +3.921250156e-01f, +6.889095401e-01f, -5.195940064e-02f }, + { -2.537928607e-02f, +3.917866477e-01f, +6.892412974e-01f, -5.198508643e-02f }, + { -2.534911857e-02f, +3.914483444e-01f, +6.895729691e-01f, -5.201074290e-02f }, + { -2.531896373e-02f, +3.911101057e-01f, +6.899045550e-01f, -5.203636997e-02f }, + { -2.528882157e-02f, +3.907719318e-01f, +6.902360551e-01f, -5.206196759e-02f }, + { -2.525869212e-02f, +3.904338229e-01f, +6.905674690e-01f, -5.208753568e-02f }, + { -2.522857541e-02f, +3.900957790e-01f, +6.908987966e-01f, -5.211307417e-02f }, + { -2.519847146e-02f, +3.897578004e-01f, +6.912300378e-01f, -5.213858300e-02f }, + { -2.516838029e-02f, +3.894198871e-01f, +6.915611922e-01f, -5.216406208e-02f }, + { -2.513830194e-02f, +3.890820394e-01f, +6.918922599e-01f, -5.218951136e-02f }, + { -2.510823643e-02f, +3.887442574e-01f, +6.922232404e-01f, -5.221493076e-02f }, + { -2.507818379e-02f, +3.884065411e-01f, +6.925541338e-01f, -5.224032022e-02f }, + { -2.504814403e-02f, +3.880688909e-01f, +6.928849397e-01f, -5.226567965e-02f }, + { -2.501811720e-02f, +3.877313067e-01f, +6.932156580e-01f, -5.229100900e-02f }, + { -2.498810332e-02f, +3.873937888e-01f, +6.935462886e-01f, -5.231630820e-02f }, + { -2.495810241e-02f, +3.870563373e-01f, +6.938768311e-01f, -5.234157717e-02f }, + { -2.492811449e-02f, +3.867189524e-01f, +6.942072855e-01f, -5.236681584e-02f }, + { -2.489813960e-02f, +3.863816342e-01f, +6.945376516e-01f, -5.239202415e-02f }, + { -2.486817776e-02f, +3.860443828e-01f, +6.948679292e-01f, -5.241720201e-02f }, + { -2.483822900e-02f, +3.857071983e-01f, +6.951981180e-01f, -5.244234938e-02f }, + { -2.480829333e-02f, +3.853700811e-01f, +6.955282179e-01f, -5.246746616e-02f }, + { -2.477837080e-02f, +3.850330311e-01f, +6.958582288e-01f, -5.249255230e-02f }, + { -2.474846141e-02f, +3.846960485e-01f, +6.961881503e-01f, -5.251760772e-02f }, + { -2.471856521e-02f, +3.843591335e-01f, +6.965179824e-01f, -5.254263236e-02f }, + { -2.468868221e-02f, +3.840222862e-01f, +6.968477249e-01f, -5.256762613e-02f }, + { -2.465881245e-02f, +3.836855068e-01f, +6.971773775e-01f, -5.259258898e-02f }, + { -2.462895594e-02f, +3.833487953e-01f, +6.975069402e-01f, -5.261752083e-02f }, + { -2.459911271e-02f, +3.830121520e-01f, +6.978364126e-01f, -5.264242161e-02f }, + { -2.456928278e-02f, +3.826755771e-01f, +6.981657947e-01f, -5.266729126e-02f }, + { -2.453946619e-02f, +3.823390705e-01f, +6.984950861e-01f, -5.269212969e-02f }, + { -2.450966296e-02f, +3.820026325e-01f, +6.988242869e-01f, -5.271693684e-02f }, + { -2.447987311e-02f, +3.816662633e-01f, +6.991533966e-01f, -5.274171264e-02f }, + { -2.445009667e-02f, +3.813299629e-01f, +6.994824153e-01f, -5.276645702e-02f }, + { -2.442033366e-02f, +3.809937316e-01f, +6.998113426e-01f, -5.279116991e-02f }, + { -2.439058412e-02f, +3.806575694e-01f, +7.001401785e-01f, -5.281585123e-02f }, + { -2.436084805e-02f, +3.803214765e-01f, +7.004689226e-01f, -5.284050092e-02f }, + { -2.433112550e-02f, +3.799854530e-01f, +7.007975749e-01f, -5.286511890e-02f }, + { -2.430141648e-02f, +3.796494992e-01f, +7.011261352e-01f, -5.288970511e-02f }, + { -2.427172102e-02f, +3.793136151e-01f, +7.014546032e-01f, -5.291425948e-02f }, + { -2.424203914e-02f, +3.789778008e-01f, +7.017829788e-01f, -5.293878193e-02f }, + { -2.421237087e-02f, +3.786420566e-01f, +7.021112617e-01f, -5.296327238e-02f }, + { -2.418271624e-02f, +3.783063825e-01f, +7.024394519e-01f, -5.298773078e-02f }, + { -2.415307527e-02f, +3.779707788e-01f, +7.027675491e-01f, -5.301215705e-02f }, + { -2.412344797e-02f, +3.776352455e-01f, +7.030955531e-01f, -5.303655112e-02f }, + { -2.409383439e-02f, +3.772997828e-01f, +7.034234638e-01f, -5.306091292e-02f }, + { -2.406423454e-02f, +3.769643909e-01f, +7.037512810e-01f, -5.308524237e-02f }, + { -2.403464845e-02f, +3.766290698e-01f, +7.040790044e-01f, -5.310953941e-02f }, + { -2.400507614e-02f, +3.762938197e-01f, +7.044066339e-01f, -5.313380397e-02f }, + { -2.397551763e-02f, +3.759586408e-01f, +7.047341694e-01f, -5.315803596e-02f }, + { -2.394597296e-02f, +3.756235333e-01f, +7.050616105e-01f, -5.318223533e-02f }, + { -2.391644214e-02f, +3.752884971e-01f, +7.053889572e-01f, -5.320640200e-02f }, + { -2.388692520e-02f, +3.749535326e-01f, +7.057162093e-01f, -5.323053590e-02f }, + { -2.385742216e-02f, +3.746186398e-01f, +7.060433665e-01f, -5.325463695e-02f }, + { -2.382793305e-02f, +3.742838189e-01f, +7.063704287e-01f, -5.327870509e-02f }, + { -2.379845790e-02f, +3.739490700e-01f, +7.066973957e-01f, -5.330274025e-02f }, + { -2.376899672e-02f, +3.736143933e-01f, +7.070242673e-01f, -5.332674235e-02f }, + { -2.373954954e-02f, +3.732797888e-01f, +7.073510434e-01f, -5.335071132e-02f }, + { -2.371011639e-02f, +3.729452569e-01f, +7.076777237e-01f, -5.337464709e-02f }, + { -2.368069728e-02f, +3.726107975e-01f, +7.080043080e-01f, -5.339854959e-02f }, + { -2.365129225e-02f, +3.722764108e-01f, +7.083307963e-01f, -5.342241875e-02f }, + { -2.362190131e-02f, +3.719420970e-01f, +7.086571882e-01f, -5.344625449e-02f }, + { -2.359252450e-02f, +3.716078562e-01f, +7.089834836e-01f, -5.347005675e-02f }, + { -2.356316182e-02f, +3.712736886e-01f, +7.093096823e-01f, -5.349382545e-02f }, + { -2.353381332e-02f, +3.709395943e-01f, +7.096357842e-01f, -5.351756051e-02f }, + { -2.350447901e-02f, +3.706055734e-01f, +7.099617891e-01f, -5.354126188e-02f }, + { -2.347515891e-02f, +3.702716261e-01f, +7.102876966e-01f, -5.356492947e-02f }, + { -2.344585305e-02f, +3.699377525e-01f, +7.106135068e-01f, -5.358856321e-02f }, + { -2.341656145e-02f, +3.696039527e-01f, +7.109392194e-01f, -5.361216304e-02f }, + { -2.338728414e-02f, +3.692702270e-01f, +7.112648342e-01f, -5.363572888e-02f }, + { -2.335802114e-02f, +3.689365754e-01f, +7.115903510e-01f, -5.365926065e-02f }, + { -2.332877247e-02f, +3.686029981e-01f, +7.119157697e-01f, -5.368275829e-02f }, + { -2.329953816e-02f, +3.682694952e-01f, +7.122410900e-01f, -5.370622173e-02f }, + { -2.327031823e-02f, +3.679360669e-01f, +7.125663118e-01f, -5.372965088e-02f }, + { -2.324111270e-02f, +3.676027132e-01f, +7.128914348e-01f, -5.375304569e-02f }, + { -2.321192159e-02f, +3.672694344e-01f, +7.132164590e-01f, -5.377640607e-02f }, + { -2.318274493e-02f, +3.669362306e-01f, +7.135413841e-01f, -5.379973196e-02f }, + { -2.315358275e-02f, +3.666031020e-01f, +7.138662100e-01f, -5.382302328e-02f }, + { -2.312443506e-02f, +3.662700485e-01f, +7.141909364e-01f, -5.384627996e-02f }, + { -2.309530189e-02f, +3.659370705e-01f, +7.145155631e-01f, -5.386950193e-02f }, + { -2.306618326e-02f, +3.656041680e-01f, +7.148400900e-01f, -5.389268911e-02f }, + { -2.303707919e-02f, +3.652713412e-01f, +7.151645170e-01f, -5.391584144e-02f }, + { -2.300798972e-02f, +3.649385903e-01f, +7.154888437e-01f, -5.393895884e-02f }, + { -2.297891485e-02f, +3.646059152e-01f, +7.158130701e-01f, -5.396204124e-02f }, + { -2.294985461e-02f, +3.642733163e-01f, +7.161371959e-01f, -5.398508856e-02f }, + { -2.292080903e-02f, +3.639407936e-01f, +7.164612210e-01f, -5.400810073e-02f }, + { -2.289177812e-02f, +3.636083473e-01f, +7.167851452e-01f, -5.403107768e-02f }, + { -2.286276192e-02f, +3.632759775e-01f, +7.171089682e-01f, -5.405401935e-02f }, + { -2.283376044e-02f, +3.629436844e-01f, +7.174326900e-01f, -5.407692564e-02f }, + { -2.280477371e-02f, +3.626114681e-01f, +7.177563103e-01f, -5.409979650e-02f }, + { -2.277580174e-02f, +3.622793287e-01f, +7.180798289e-01f, -5.412263185e-02f }, + { -2.274684456e-02f, +3.619472663e-01f, +7.184032457e-01f, -5.414543161e-02f }, + { -2.271790220e-02f, +3.616152812e-01f, +7.187265605e-01f, -5.416819572e-02f }, + { -2.268897467e-02f, +3.612833734e-01f, +7.190497730e-01f, -5.419092410e-02f }, + { -2.266006200e-02f, +3.609515431e-01f, +7.193728831e-01f, -5.421361667e-02f }, + { -2.263116421e-02f, +3.606197904e-01f, +7.196958907e-01f, -5.423627337e-02f }, + { -2.260228132e-02f, +3.602881155e-01f, +7.200187955e-01f, -5.425889412e-02f }, + { -2.257341336e-02f, +3.599565185e-01f, +7.203415974e-01f, -5.428147885e-02f }, + { -2.254456034e-02f, +3.596249995e-01f, +7.206642961e-01f, -5.430402749e-02f }, + { -2.251572229e-02f, +3.592935587e-01f, +7.209868915e-01f, -5.432653996e-02f }, + { -2.248689923e-02f, +3.589621962e-01f, +7.213093834e-01f, -5.434901618e-02f }, + { -2.245809118e-02f, +3.586309121e-01f, +7.216317716e-01f, -5.437145610e-02f }, + { -2.242929816e-02f, +3.582997067e-01f, +7.219540560e-01f, -5.439385962e-02f }, + { -2.240052021e-02f, +3.579685799e-01f, +7.222762363e-01f, -5.441622669e-02f }, + { -2.237175733e-02f, +3.576375321e-01f, +7.225983123e-01f, -5.443855722e-02f }, + { -2.234300954e-02f, +3.573065632e-01f, +7.229202840e-01f, -5.446085115e-02f }, + { -2.231427688e-02f, +3.569756734e-01f, +7.232421510e-01f, -5.448310839e-02f }, + { -2.228555936e-02f, +3.566448630e-01f, +7.235639133e-01f, -5.450532888e-02f }, + { -2.225685701e-02f, +3.563141319e-01f, +7.238855706e-01f, -5.452751254e-02f }, + { -2.222816984e-02f, +3.559834804e-01f, +7.242071227e-01f, -5.454965931e-02f }, + { -2.219949788e-02f, +3.556529085e-01f, +7.245285695e-01f, -5.457176909e-02f }, + { -2.217084115e-02f, +3.553224165e-01f, +7.248499108e-01f, -5.459384183e-02f }, + { -2.214219967e-02f, +3.549920045e-01f, +7.251711464e-01f, -5.461587745e-02f }, + { -2.211357346e-02f, +3.546616725e-01f, +7.254922761e-01f, -5.463787587e-02f }, + { -2.208496254e-02f, +3.543314207e-01f, +7.258132997e-01f, -5.465983703e-02f }, + { -2.205636694e-02f, +3.540012493e-01f, +7.261342170e-01f, -5.468176084e-02f }, + { -2.202778667e-02f, +3.536711584e-01f, +7.264550280e-01f, -5.470364724e-02f }, + { -2.199922176e-02f, +3.533411482e-01f, +7.267757323e-01f, -5.472549614e-02f }, + { -2.197067223e-02f, +3.530112187e-01f, +7.270963298e-01f, -5.474730748e-02f }, + { -2.194213809e-02f, +3.526813701e-01f, +7.274168203e-01f, -5.476908119e-02f }, + { -2.191361938e-02f, +3.523516026e-01f, +7.277372036e-01f, -5.479081718e-02f }, + { -2.188511610e-02f, +3.520219162e-01f, +7.280574796e-01f, -5.481251539e-02f }, + { -2.185662829e-02f, +3.516923111e-01f, +7.283776481e-01f, -5.483417574e-02f }, + { -2.182815596e-02f, +3.513627875e-01f, +7.286977088e-01f, -5.485579815e-02f }, + { -2.179969913e-02f, +3.510333455e-01f, +7.290176616e-01f, -5.487738256e-02f }, + { -2.177125783e-02f, +3.507039852e-01f, +7.293375064e-01f, -5.489892888e-02f }, + { -2.174283207e-02f, +3.503747067e-01f, +7.296572429e-01f, -5.492043705e-02f }, + { -2.171442188e-02f, +3.500455102e-01f, +7.299768709e-01f, -5.494190699e-02f }, + { -2.168602727e-02f, +3.497163959e-01f, +7.302963903e-01f, -5.496333863e-02f }, + { -2.165764827e-02f, +3.493873638e-01f, +7.306158008e-01f, -5.498473189e-02f }, + { -2.162928490e-02f, +3.490584141e-01f, +7.309351024e-01f, -5.500608670e-02f }, + { -2.160093718e-02f, +3.487295469e-01f, +7.312542948e-01f, -5.502740298e-02f }, + { -2.157260512e-02f, +3.484007623e-01f, +7.315733778e-01f, -5.504868065e-02f }, + { -2.154428875e-02f, +3.480720606e-01f, +7.318923513e-01f, -5.506991966e-02f }, + { -2.151598810e-02f, +3.477434418e-01f, +7.322112150e-01f, -5.509111991e-02f }, + { -2.148770317e-02f, +3.474149060e-01f, +7.325299688e-01f, -5.511228134e-02f }, + { -2.145943399e-02f, +3.470864534e-01f, +7.328486125e-01f, -5.513340388e-02f }, + { -2.143118058e-02f, +3.467580842e-01f, +7.331671459e-01f, -5.515448744e-02f }, + { -2.140294296e-02f, +3.464297984e-01f, +7.334855689e-01f, -5.517553195e-02f }, + { -2.137472115e-02f, +3.461015962e-01f, +7.338038812e-01f, -5.519653734e-02f }, + { -2.134651517e-02f, +3.457734778e-01f, +7.341220827e-01f, -5.521750353e-02f }, + { -2.131832504e-02f, +3.454454432e-01f, +7.344401732e-01f, -5.523843046e-02f }, + { -2.129015078e-02f, +3.451174926e-01f, +7.347581525e-01f, -5.525931803e-02f }, + { -2.126199241e-02f, +3.447896261e-01f, +7.350760204e-01f, -5.528016619e-02f }, + { -2.123384995e-02f, +3.444618439e-01f, +7.353937768e-01f, -5.530097485e-02f }, + { -2.120572342e-02f, +3.441341461e-01f, +7.357114214e-01f, -5.532174395e-02f }, + { -2.117761283e-02f, +3.438065327e-01f, +7.360289541e-01f, -5.534247339e-02f }, + { -2.114951822e-02f, +3.434790041e-01f, +7.363463747e-01f, -5.536316312e-02f }, + { -2.112143960e-02f, +3.431515602e-01f, +7.366636830e-01f, -5.538381306e-02f }, + { -2.109337699e-02f, +3.428242013e-01f, +7.369808788e-01f, -5.540442312e-02f }, + { -2.106533040e-02f, +3.424969274e-01f, +7.372979620e-01f, -5.542499324e-02f }, + { -2.103729986e-02f, +3.421697387e-01f, +7.376149323e-01f, -5.544552335e-02f }, + { -2.100928539e-02f, +3.418426354e-01f, +7.379317896e-01f, -5.546601336e-02f }, + { -2.098128700e-02f, +3.415156174e-01f, +7.382485338e-01f, -5.548646320e-02f }, + { -2.095330472e-02f, +3.411886851e-01f, +7.385651645e-01f, -5.550687279e-02f }, + { -2.092533857e-02f, +3.408618385e-01f, +7.388816817e-01f, -5.552724207e-02f }, + { -2.089738856e-02f, +3.405350777e-01f, +7.391980851e-01f, -5.554757095e-02f }, + { -2.086945472e-02f, +3.402084029e-01f, +7.395143746e-01f, -5.556785936e-02f }, + { -2.084153705e-02f, +3.398818142e-01f, +7.398305500e-01f, -5.558810723e-02f }, + { -2.081363559e-02f, +3.395553117e-01f, +7.401466111e-01f, -5.560831448e-02f }, + { -2.078575035e-02f, +3.392288956e-01f, +7.404625577e-01f, -5.562848104e-02f }, + { -2.075788136e-02f, +3.389025660e-01f, +7.407783897e-01f, -5.564860682e-02f }, + { -2.073002862e-02f, +3.385763231e-01f, +7.410941069e-01f, -5.566869176e-02f }, + { -2.070219216e-02f, +3.382501669e-01f, +7.414097090e-01f, -5.568873578e-02f }, + { -2.067437199e-02f, +3.379240976e-01f, +7.417251959e-01f, -5.570873880e-02f }, + { -2.064656814e-02f, +3.375981153e-01f, +7.420405674e-01f, -5.572870075e-02f }, + { -2.061878063e-02f, +3.372722202e-01f, +7.423558234e-01f, -5.574862155e-02f }, + { -2.059100947e-02f, +3.369464124e-01f, +7.426709636e-01f, -5.576850113e-02f }, + { -2.056325469e-02f, +3.366206920e-01f, +7.429859879e-01f, -5.578833941e-02f }, + { -2.053551629e-02f, +3.362950591e-01f, +7.433008961e-01f, -5.580813632e-02f }, + { -2.050779431e-02f, +3.359695139e-01f, +7.436156880e-01f, -5.582789178e-02f }, + { -2.048008875e-02f, +3.356440565e-01f, +7.439303635e-01f, -5.584760571e-02f }, + { -2.045239964e-02f, +3.353186871e-01f, +7.442449222e-01f, -5.586727805e-02f }, + { -2.042472700e-02f, +3.349934057e-01f, +7.445593642e-01f, -5.588690871e-02f }, + { -2.039707084e-02f, +3.346682125e-01f, +7.448736891e-01f, -5.590649761e-02f }, + { -2.036943118e-02f, +3.343431076e-01f, +7.451878969e-01f, -5.592604469e-02f }, + { -2.034180804e-02f, +3.340180912e-01f, +7.455019872e-01f, -5.594554986e-02f }, + { -2.031420145e-02f, +3.336931634e-01f, +7.458159600e-01f, -5.596501306e-02f }, + { -2.028661141e-02f, +3.333683243e-01f, +7.461298151e-01f, -5.598443420e-02f }, + { -2.025903794e-02f, +3.330435740e-01f, +7.464435522e-01f, -5.600381321e-02f }, + { -2.023148107e-02f, +3.327189127e-01f, +7.467571712e-01f, -5.602315001e-02f }, + { -2.020394081e-02f, +3.323943405e-01f, +7.470706720e-01f, -5.604244453e-02f }, + { -2.017641718e-02f, +3.320698576e-01f, +7.473840543e-01f, -5.606169669e-02f }, + { -2.014891020e-02f, +3.317454639e-01f, +7.476973179e-01f, -5.608090642e-02f }, + { -2.012141988e-02f, +3.314211598e-01f, +7.480104627e-01f, -5.610007364e-02f }, + { -2.009394625e-02f, +3.310969453e-01f, +7.483234885e-01f, -5.611919827e-02f }, + { -2.006648932e-02f, +3.307728205e-01f, +7.486363951e-01f, -5.613828023e-02f }, + { -2.003904911e-02f, +3.304487856e-01f, +7.489491824e-01f, -5.615731946e-02f }, + { -2.001162564e-02f, +3.301248407e-01f, +7.492618501e-01f, -5.617631587e-02f }, + { -1.998421892e-02f, +3.298009860e-01f, +7.495743981e-01f, -5.619526939e-02f }, + { -1.995682897e-02f, +3.294772215e-01f, +7.498868261e-01f, -5.621417995e-02f }, + { -1.992945582e-02f, +3.291535473e-01f, +7.501991341e-01f, -5.623304746e-02f }, + { -1.990209947e-02f, +3.288299637e-01f, +7.505113218e-01f, -5.625187185e-02f }, + { -1.987475995e-02f, +3.285064707e-01f, +7.508233890e-01f, -5.627065304e-02f }, + { -1.984743727e-02f, +3.281830685e-01f, +7.511353356e-01f, -5.628939096e-02f }, + { -1.982013145e-02f, +3.278597572e-01f, +7.514471614e-01f, -5.630808553e-02f }, + { -1.979284251e-02f, +3.275365369e-01f, +7.517588662e-01f, -5.632673668e-02f }, + { -1.976557047e-02f, +3.272134077e-01f, +7.520704498e-01f, -5.634534432e-02f }, + { -1.973831534e-02f, +3.268903698e-01f, +7.523819121e-01f, -5.636390839e-02f }, + { -1.971107714e-02f, +3.265674233e-01f, +7.526932528e-01f, -5.638242880e-02f }, + { -1.968385589e-02f, +3.262445684e-01f, +7.530044718e-01f, -5.640090548e-02f }, + { -1.965665160e-02f, +3.259218051e-01f, +7.533155690e-01f, -5.641933835e-02f }, + { -1.962946429e-02f, +3.255991335e-01f, +7.536265440e-01f, -5.643772734e-02f }, + { -1.960229398e-02f, +3.252765539e-01f, +7.539373968e-01f, -5.645607236e-02f }, + { -1.957514069e-02f, +3.249540663e-01f, +7.542481271e-01f, -5.647437335e-02f }, + { -1.954800443e-02f, +3.246316709e-01f, +7.545587349e-01f, -5.649263022e-02f }, + { -1.952088522e-02f, +3.243093678e-01f, +7.548692198e-01f, -5.651084290e-02f }, + { -1.949378307e-02f, +3.239871571e-01f, +7.551795818e-01f, -5.652901131e-02f }, + { -1.946669801e-02f, +3.236650389e-01f, +7.554898206e-01f, -5.654713538e-02f }, + { -1.943963005e-02f, +3.233430133e-01f, +7.557999361e-01f, -5.656521503e-02f }, + { -1.941257921e-02f, +3.230210806e-01f, +7.561099280e-01f, -5.658325018e-02f }, + { -1.938554550e-02f, +3.226992408e-01f, +7.564197963e-01f, -5.660124075e-02f }, + { -1.935852895e-02f, +3.223774940e-01f, +7.567295407e-01f, -5.661918667e-02f }, + { -1.933152956e-02f, +3.220558404e-01f, +7.570391610e-01f, -5.663708786e-02f }, + { -1.930454735e-02f, +3.217342801e-01f, +7.573486571e-01f, -5.665494425e-02f }, + { -1.927758234e-02f, +3.214128132e-01f, +7.576580288e-01f, -5.667275575e-02f }, + { -1.925063455e-02f, +3.210914398e-01f, +7.579672759e-01f, -5.669052229e-02f }, + { -1.922370400e-02f, +3.207701601e-01f, +7.582763982e-01f, -5.670824380e-02f }, + { -1.919679069e-02f, +3.204489742e-01f, +7.585853955e-01f, -5.672592019e-02f }, + { -1.916989465e-02f, +3.201278822e-01f, +7.588942678e-01f, -5.674355138e-02f }, + { -1.914301589e-02f, +3.198068842e-01f, +7.592030147e-01f, -5.676113731e-02f }, + { -1.911615443e-02f, +3.194859804e-01f, +7.595116361e-01f, -5.677867790e-02f }, + { -1.908931029e-02f, +3.191651709e-01f, +7.598201319e-01f, -5.679617306e-02f }, + { -1.906248348e-02f, +3.188444558e-01f, +7.601285018e-01f, -5.681362272e-02f }, + { -1.903567401e-02f, +3.185238353e-01f, +7.604367457e-01f, -5.683102681e-02f }, + { -1.900888191e-02f, +3.182033094e-01f, +7.607448634e-01f, -5.684838523e-02f }, + { -1.898210719e-02f, +3.178828783e-01f, +7.610528546e-01f, -5.686569793e-02f }, + { -1.895534986e-02f, +3.175625421e-01f, +7.613607194e-01f, -5.688296482e-02f }, + { -1.892860994e-02f, +3.172423009e-01f, +7.616684574e-01f, -5.690018582e-02f }, + { -1.890188745e-02f, +3.169221549e-01f, +7.619760684e-01f, -5.691736086e-02f }, + { -1.887518241e-02f, +3.166021042e-01f, +7.622835524e-01f, -5.693448985e-02f }, + { -1.884849482e-02f, +3.162821488e-01f, +7.625909090e-01f, -5.695157273e-02f }, + { -1.882182471e-02f, +3.159622890e-01f, +7.628981382e-01f, -5.696860941e-02f }, + { -1.879517209e-02f, +3.156425249e-01f, +7.632052398e-01f, -5.698559981e-02f }, + { -1.876853697e-02f, +3.153228565e-01f, +7.635122136e-01f, -5.700254386e-02f }, + { -1.874191938e-02f, +3.150032840e-01f, +7.638190593e-01f, -5.701944149e-02f }, + { -1.871531932e-02f, +3.146838075e-01f, +7.641257769e-01f, -5.703629260e-02f }, + { -1.868873682e-02f, +3.143644272e-01f, +7.644323662e-01f, -5.705309714e-02f }, + { -1.866217188e-02f, +3.140451431e-01f, +7.647388269e-01f, -5.706985501e-02f }, + { -1.863562453e-02f, +3.137259554e-01f, +7.650451589e-01f, -5.708656614e-02f }, + { -1.860909478e-02f, +3.134068642e-01f, +7.653513620e-01f, -5.710323045e-02f }, + { -1.858258264e-02f, +3.130878696e-01f, +7.656574360e-01f, -5.711984787e-02f }, + { -1.855608813e-02f, +3.127689718e-01f, +7.659633808e-01f, -5.713641831e-02f }, + { -1.852961127e-02f, +3.124501709e-01f, +7.662691962e-01f, -5.715294170e-02f }, + { -1.850315207e-02f, +3.121314670e-01f, +7.665748819e-01f, -5.716941797e-02f }, + { -1.847671054e-02f, +3.118128601e-01f, +7.668804379e-01f, -5.718584702e-02f }, + { -1.845028671e-02f, +3.114943506e-01f, +7.671858639e-01f, -5.720222880e-02f }, + { -1.842388058e-02f, +3.111759383e-01f, +7.674911598e-01f, -5.721856321e-02f }, + { -1.839749217e-02f, +3.108576236e-01f, +7.677963254e-01f, -5.723485017e-02f }, + { -1.837112149e-02f, +3.105394064e-01f, +7.681013605e-01f, -5.725108962e-02f }, + { -1.834476857e-02f, +3.102212870e-01f, +7.684062649e-01f, -5.726728148e-02f }, + { -1.831843341e-02f, +3.099032654e-01f, +7.687110385e-01f, -5.728342566e-02f }, + { -1.829211604e-02f, +3.095853418e-01f, +7.690156811e-01f, -5.729952209e-02f }, + { -1.826581646e-02f, +3.092675163e-01f, +7.693201924e-01f, -5.731557068e-02f }, + { -1.823953469e-02f, +3.089497890e-01f, +7.696245724e-01f, -5.733157137e-02f }, + { -1.821327074e-02f, +3.086321600e-01f, +7.699288208e-01f, -5.734752407e-02f }, + { -1.818702464e-02f, +3.083146294e-01f, +7.702329374e-01f, -5.736342870e-02f }, + { -1.816079639e-02f, +3.079971975e-01f, +7.705369222e-01f, -5.737928519e-02f }, + { -1.813458600e-02f, +3.076798642e-01f, +7.708407749e-01f, -5.739509346e-02f }, + { -1.810839350e-02f, +3.073626297e-01f, +7.711444953e-01f, -5.741085343e-02f }, + { -1.808221890e-02f, +3.070454941e-01f, +7.714480832e-01f, -5.742656503e-02f }, + { -1.805606221e-02f, +3.067284576e-01f, +7.717515386e-01f, -5.744222816e-02f }, + { -1.802992345e-02f, +3.064115203e-01f, +7.720548611e-01f, -5.745784276e-02f }, + { -1.800380263e-02f, +3.060946822e-01f, +7.723580506e-01f, -5.747340875e-02f }, + { -1.797769977e-02f, +3.057779436e-01f, +7.726611070e-01f, -5.748892604e-02f }, + { -1.795161487e-02f, +3.054613045e-01f, +7.729640301e-01f, -5.750439457e-02f }, + { -1.792554796e-02f, +3.051447650e-01f, +7.732668197e-01f, -5.751981424e-02f }, + { -1.789949905e-02f, +3.048283253e-01f, +7.735694755e-01f, -5.753518499e-02f }, + { -1.787346814e-02f, +3.045119855e-01f, +7.738719975e-01f, -5.755050673e-02f }, + { -1.784745527e-02f, +3.041957456e-01f, +7.741743855e-01f, -5.756577939e-02f }, + { -1.782146044e-02f, +3.038796059e-01f, +7.744766393e-01f, -5.758100289e-02f }, + { -1.779548366e-02f, +3.035635665e-01f, +7.747787586e-01f, -5.759617715e-02f }, + { -1.776952495e-02f, +3.032476274e-01f, +7.750807434e-01f, -5.761130208e-02f }, + { -1.774358432e-02f, +3.029317887e-01f, +7.753825935e-01f, -5.762637762e-02f }, + { -1.771766179e-02f, +3.026160507e-01f, +7.756843086e-01f, -5.764140368e-02f }, + { -1.769175736e-02f, +3.023004134e-01f, +7.759858886e-01f, -5.765638018e-02f }, + { -1.766587107e-02f, +3.019848769e-01f, +7.762873333e-01f, -5.767130705e-02f }, + { -1.764000291e-02f, +3.016694414e-01f, +7.765886426e-01f, -5.768618420e-02f }, + { -1.761415290e-02f, +3.013541069e-01f, +7.768898163e-01f, -5.770101157e-02f }, + { -1.758832105e-02f, +3.010388736e-01f, +7.771908542e-01f, -5.771578906e-02f }, + { -1.756250739e-02f, +3.007237417e-01f, +7.774917560e-01f, -5.773051660e-02f }, + { -1.753671192e-02f, +3.004087111e-01f, +7.777925218e-01f, -5.774519411e-02f }, + { -1.751093465e-02f, +3.000937821e-01f, +7.780931511e-01f, -5.775982152e-02f }, + { -1.748517560e-02f, +2.997789547e-01f, +7.783936440e-01f, -5.777439874e-02f }, + { -1.745943479e-02f, +2.994642291e-01f, +7.786940002e-01f, -5.778892569e-02f }, + { -1.743371222e-02f, +2.991496054e-01f, +7.789942195e-01f, -5.780340230e-02f }, + { -1.740800791e-02f, +2.988350837e-01f, +7.792943018e-01f, -5.781782849e-02f }, + { -1.738232187e-02f, +2.985206642e-01f, +7.795942469e-01f, -5.783220417e-02f }, + { -1.735665412e-02f, +2.982063468e-01f, +7.798940546e-01f, -5.784652927e-02f }, + { -1.733100467e-02f, +2.978921319e-01f, +7.801937247e-01f, -5.786080371e-02f }, + { -1.730537353e-02f, +2.975780194e-01f, +7.804932570e-01f, -5.787502741e-02f }, + { -1.727976072e-02f, +2.972640094e-01f, +7.807926515e-01f, -5.788920029e-02f }, + { -1.725416625e-02f, +2.969501022e-01f, +7.810919079e-01f, -5.790332228e-02f }, + { -1.722859012e-02f, +2.966362979e-01f, +7.813910260e-01f, -5.791739329e-02f }, + { -1.720303237e-02f, +2.963225964e-01f, +7.816900056e-01f, -5.793141324e-02f }, + { -1.717749299e-02f, +2.960089980e-01f, +7.819888466e-01f, -5.794538205e-02f }, + { -1.715197200e-02f, +2.956955028e-01f, +7.822875489e-01f, -5.795929965e-02f }, + { -1.712646941e-02f, +2.953821109e-01f, +7.825861121e-01f, -5.797316596e-02f }, + { -1.710098524e-02f, +2.950688223e-01f, +7.828845363e-01f, -5.798698089e-02f }, + { -1.707551950e-02f, +2.947556373e-01f, +7.831828211e-01f, -5.800074437e-02f }, + { -1.705007220e-02f, +2.944425560e-01f, +7.834809664e-01f, -5.801445632e-02f }, + { -1.702464336e-02f, +2.941295783e-01f, +7.837789720e-01f, -5.802811666e-02f }, + { -1.699923298e-02f, +2.938167045e-01f, +7.840768378e-01f, -5.804172530e-02f }, + { -1.697384108e-02f, +2.935039348e-01f, +7.843745636e-01f, -5.805528218e-02f }, + { -1.694846768e-02f, +2.931912691e-01f, +7.846721491e-01f, -5.806878721e-02f }, + { -1.692311278e-02f, +2.928787076e-01f, +7.849695943e-01f, -5.808224030e-02f }, + { -1.689777639e-02f, +2.925662504e-01f, +7.852668990e-01f, -5.809564139e-02f }, + { -1.687245854e-02f, +2.922538976e-01f, +7.855640629e-01f, -5.810899039e-02f }, + { -1.684715923e-02f, +2.919416495e-01f, +7.858610859e-01f, -5.812228722e-02f }, + { -1.682187847e-02f, +2.916295059e-01f, +7.861579679e-01f, -5.813553181e-02f }, + { -1.679661628e-02f, +2.913174672e-01f, +7.864547086e-01f, -5.814872407e-02f }, + { -1.677137267e-02f, +2.910055333e-01f, +7.867513079e-01f, -5.816186392e-02f }, + { -1.674614765e-02f, +2.906937045e-01f, +7.870477656e-01f, -5.817495128e-02f }, + { -1.672094124e-02f, +2.903819808e-01f, +7.873440816e-01f, -5.818798608e-02f }, + { -1.669575344e-02f, +2.900703623e-01f, +7.876402556e-01f, -5.820096823e-02f }, + { -1.667058426e-02f, +2.897588491e-01f, +7.879362875e-01f, -5.821389766e-02f }, + { -1.664543373e-02f, +2.894474415e-01f, +7.882321771e-01f, -5.822677428e-02f }, + { -1.662030185e-02f, +2.891361394e-01f, +7.885279242e-01f, -5.823959802e-02f }, + { -1.659518863e-02f, +2.888249429e-01f, +7.888235287e-01f, -5.825236880e-02f }, + { -1.657009409e-02f, +2.885138523e-01f, +7.891189904e-01f, -5.826508653e-02f }, + { -1.654501824e-02f, +2.882028676e-01f, +7.894143091e-01f, -5.827775113e-02f }, + { -1.651996108e-02f, +2.878919890e-01f, +7.897094846e-01f, -5.829036253e-02f }, + { -1.649492264e-02f, +2.875812164e-01f, +7.900045168e-01f, -5.830292065e-02f }, + { -1.646990291e-02f, +2.872705501e-01f, +7.902994055e-01f, -5.831542540e-02f }, + { -1.644490193e-02f, +2.869599902e-01f, +7.905941505e-01f, -5.832787671e-02f }, + { -1.641991969e-02f, +2.866495368e-01f, +7.908887516e-01f, -5.834027449e-02f }, + { -1.639495620e-02f, +2.863391899e-01f, +7.911832088e-01f, -5.835261867e-02f }, + { -1.637001149e-02f, +2.860289498e-01f, +7.914775217e-01f, -5.836490917e-02f }, + { -1.634508556e-02f, +2.857188164e-01f, +7.917716902e-01f, -5.837714590e-02f }, + { -1.632017842e-02f, +2.854087900e-01f, +7.920657142e-01f, -5.838932879e-02f }, + { -1.629529008e-02f, +2.850988707e-01f, +7.923595935e-01f, -5.840145776e-02f }, + { -1.627042056e-02f, +2.847890584e-01f, +7.926533279e-01f, -5.841353272e-02f }, + { -1.624556986e-02f, +2.844793535e-01f, +7.929469172e-01f, -5.842555359e-02f }, + { -1.622073801e-02f, +2.841697559e-01f, +7.932403612e-01f, -5.843752031e-02f }, + { -1.619592500e-02f, +2.838602658e-01f, +7.935336599e-01f, -5.844943277e-02f }, + { -1.617113085e-02f, +2.835508833e-01f, +7.938268129e-01f, -5.846129092e-02f }, + { -1.614635558e-02f, +2.832416085e-01f, +7.941198202e-01f, -5.847309465e-02f }, + { -1.612159918e-02f, +2.829324415e-01f, +7.944126816e-01f, -5.848484391e-02f }, + { -1.609686168e-02f, +2.826233824e-01f, +7.947053969e-01f, -5.849653859e-02f }, + { -1.607214309e-02f, +2.823144314e-01f, +7.949979658e-01f, -5.850817864e-02f }, + { -1.604744341e-02f, +2.820055885e-01f, +7.952903884e-01f, -5.851976395e-02f }, + { -1.602276266e-02f, +2.816968539e-01f, +7.955826642e-01f, -5.853129446e-02f }, + { -1.599810084e-02f, +2.813882276e-01f, +7.958747933e-01f, -5.854277008e-02f }, + { -1.597345798e-02f, +2.810797098e-01f, +7.961667755e-01f, -5.855419074e-02f }, + { -1.594883407e-02f, +2.807713007e-01f, +7.964586105e-01f, -5.856555634e-02f }, + { -1.592422914e-02f, +2.804630002e-01f, +7.967502981e-01f, -5.857686682e-02f }, + { -1.589964318e-02f, +2.801548085e-01f, +7.970418383e-01f, -5.858812209e-02f }, + { -1.587507622e-02f, +2.798467258e-01f, +7.973332308e-01f, -5.859932207e-02f }, + { -1.585052826e-02f, +2.795387520e-01f, +7.976244755e-01f, -5.861046669e-02f }, + { -1.582599931e-02f, +2.792308874e-01f, +7.979155722e-01f, -5.862155585e-02f }, + { -1.580148939e-02f, +2.789231321e-01f, +7.982065207e-01f, -5.863258948e-02f }, + { -1.577699850e-02f, +2.786154861e-01f, +7.984973209e-01f, -5.864356750e-02f }, + { -1.575252665e-02f, +2.783079496e-01f, +7.987879725e-01f, -5.865448983e-02f }, + { -1.572807386e-02f, +2.780005227e-01f, +7.990784754e-01f, -5.866535639e-02f }, + { -1.570364014e-02f, +2.776932054e-01f, +7.993688295e-01f, -5.867616710e-02f }, + { -1.567922549e-02f, +2.773859980e-01f, +7.996590346e-01f, -5.868692187e-02f }, + { -1.565482993e-02f, +2.770789004e-01f, +7.999490904e-01f, -5.869762062e-02f }, + { -1.563045347e-02f, +2.767719129e-01f, +8.002389969e-01f, -5.870826329e-02f }, + { -1.560609611e-02f, +2.764650354e-01f, +8.005287538e-01f, -5.871884977e-02f }, + { -1.558175787e-02f, +2.761582682e-01f, +8.008183610e-01f, -5.872938000e-02f }, + { -1.555743875e-02f, +2.758516114e-01f, +8.011078183e-01f, -5.873985390e-02f }, + { -1.553313878e-02f, +2.755450649e-01f, +8.013971255e-01f, -5.875027137e-02f }, + { -1.550885795e-02f, +2.752386291e-01f, +8.016862825e-01f, -5.876063235e-02f }, + { -1.548459628e-02f, +2.749323038e-01f, +8.019752891e-01f, -5.877093675e-02f }, + { -1.546035377e-02f, +2.746260894e-01f, +8.022641451e-01f, -5.878118449e-02f }, + { -1.543613045e-02f, +2.743199858e-01f, +8.025528503e-01f, -5.879137549e-02f }, + { -1.541192631e-02f, +2.740139932e-01f, +8.028414047e-01f, -5.880150966e-02f }, + { -1.538774137e-02f, +2.737081117e-01f, +8.031298079e-01f, -5.881158693e-02f }, + { -1.536357563e-02f, +2.734023414e-01f, +8.034180599e-01f, -5.882160722e-02f }, + { -1.533942912e-02f, +2.730966824e-01f, +8.037061604e-01f, -5.883157045e-02f }, + { -1.531530183e-02f, +2.727911348e-01f, +8.039941094e-01f, -5.884147653e-02f }, + { -1.529119377e-02f, +2.724856987e-01f, +8.042819066e-01f, -5.885132538e-02f }, + { -1.526710496e-02f, +2.721803743e-01f, +8.045695518e-01f, -5.886111692e-02f }, + { -1.524303541e-02f, +2.718751616e-01f, +8.048570449e-01f, -5.887085108e-02f }, + { -1.521898512e-02f, +2.715700607e-01f, +8.051443857e-01f, -5.888052777e-02f }, + { -1.519495411e-02f, +2.712650718e-01f, +8.054315741e-01f, -5.889014690e-02f }, + { -1.517094238e-02f, +2.709601949e-01f, +8.057186098e-01f, -5.889970841e-02f }, + { -1.514694995e-02f, +2.706554301e-01f, +8.060054928e-01f, -5.890921220e-02f }, + { -1.512297682e-02f, +2.703507777e-01f, +8.062922227e-01f, -5.891865819e-02f }, + { -1.509902300e-02f, +2.700462376e-01f, +8.065787996e-01f, -5.892804632e-02f }, + { -1.507508850e-02f, +2.697418099e-01f, +8.068652231e-01f, -5.893737648e-02f }, + { -1.505117334e-02f, +2.694374949e-01f, +8.071514932e-01f, -5.894664861e-02f }, + { -1.502727751e-02f, +2.691332925e-01f, +8.074376096e-01f, -5.895586262e-02f }, + { -1.500340104e-02f, +2.688292029e-01f, +8.077235722e-01f, -5.896501843e-02f }, + { -1.497954392e-02f, +2.685252263e-01f, +8.080093808e-01f, -5.897411596e-02f }, + { -1.495570618e-02f, +2.682213626e-01f, +8.082950352e-01f, -5.898315513e-02f }, + { -1.493188780e-02f, +2.679176120e-01f, +8.085805354e-01f, -5.899213585e-02f }, + { -1.490808882e-02f, +2.676139746e-01f, +8.088658810e-01f, -5.900105805e-02f }, + { -1.488430923e-02f, +2.673104506e-01f, +8.091510719e-01f, -5.900992164e-02f }, + { -1.486054904e-02f, +2.670070400e-01f, +8.094361081e-01f, -5.901872654e-02f }, + { -1.483680827e-02f, +2.667037429e-01f, +8.097209892e-01f, -5.902747268e-02f }, + { -1.481308692e-02f, +2.664005594e-01f, +8.100057151e-01f, -5.903615996e-02f }, + { -1.478938500e-02f, +2.660974897e-01f, +8.102902857e-01f, -5.904478831e-02f }, + { -1.476570252e-02f, +2.657945338e-01f, +8.105747008e-01f, -5.905335765e-02f }, + { -1.474203949e-02f, +2.654916918e-01f, +8.108589603e-01f, -5.906186790e-02f }, + { -1.471839591e-02f, +2.651889639e-01f, +8.111430638e-01f, -5.907031897e-02f }, + { -1.469477181e-02f, +2.648863501e-01f, +8.114270114e-01f, -5.907871078e-02f }, + { -1.467116717e-02f, +2.645838506e-01f, +8.117108027e-01f, -5.908704325e-02f }, + { -1.464758202e-02f, +2.642814655e-01f, +8.119944377e-01f, -5.909531630e-02f }, + { -1.462401636e-02f, +2.639791948e-01f, +8.122779162e-01f, -5.910352985e-02f }, + { -1.460047020e-02f, +2.636770386e-01f, +8.125612380e-01f, -5.911168382e-02f }, + { -1.457694355e-02f, +2.633749972e-01f, +8.128444029e-01f, -5.911977812e-02f }, + { -1.455343641e-02f, +2.630730705e-01f, +8.131274108e-01f, -5.912781267e-02f }, + { -1.452994881e-02f, +2.627712587e-01f, +8.134102615e-01f, -5.913578740e-02f }, + { -1.450648073e-02f, +2.624695618e-01f, +8.136929549e-01f, -5.914370221e-02f }, + { -1.448303220e-02f, +2.621679801e-01f, +8.139754907e-01f, -5.915155704e-02f }, + { -1.445960321e-02f, +2.618665135e-01f, +8.142578688e-01f, -5.915935179e-02f }, + { -1.443619379e-02f, +2.615651622e-01f, +8.145400890e-01f, -5.916708638e-02f }, + { -1.441280393e-02f, +2.612639263e-01f, +8.148221512e-01f, -5.917476074e-02f }, + { -1.438943365e-02f, +2.609628058e-01f, +8.151040551e-01f, -5.918237478e-02f }, + { -1.436608295e-02f, +2.606618010e-01f, +8.153858007e-01f, -5.918992842e-02f }, + { -1.434275184e-02f, +2.603609118e-01f, +8.156673878e-01f, -5.919742158e-02f }, + { -1.431944033e-02f, +2.600601385e-01f, +8.159488162e-01f, -5.920485418e-02f }, + { -1.429614843e-02f, +2.597594810e-01f, +8.162300856e-01f, -5.921222613e-02f }, + { -1.427287614e-02f, +2.594589396e-01f, +8.165111960e-01f, -5.921953735e-02f }, + { -1.424962348e-02f, +2.591585142e-01f, +8.167921473e-01f, -5.922678777e-02f }, + { -1.422639045e-02f, +2.588582051e-01f, +8.170729391e-01f, -5.923397729e-02f }, + { -1.420317705e-02f, +2.585580122e-01f, +8.173535714e-01f, -5.924110584e-02f }, + { -1.417998331e-02f, +2.582579358e-01f, +8.176340439e-01f, -5.924817333e-02f }, + { -1.415680921e-02f, +2.579579758e-01f, +8.179143566e-01f, -5.925517969e-02f }, + { -1.413365478e-02f, +2.576581325e-01f, +8.181945092e-01f, -5.926212483e-02f }, + { -1.411052002e-02f, +2.573584058e-01f, +8.184745017e-01f, -5.926900867e-02f }, + { -1.408740493e-02f, +2.570587960e-01f, +8.187543337e-01f, -5.927583113e-02f }, + { -1.406430953e-02f, +2.567593031e-01f, +8.190340052e-01f, -5.928259213e-02f }, + { -1.404123383e-02f, +2.564599271e-01f, +8.193135159e-01f, -5.928929157e-02f }, + { -1.401817782e-02f, +2.561606683e-01f, +8.195928658e-01f, -5.929592939e-02f }, + { -1.399514152e-02f, +2.558615267e-01f, +8.198720547e-01f, -5.930250550e-02f }, + { -1.397212493e-02f, +2.555625024e-01f, +8.201510823e-01f, -5.930901982e-02f }, + { -1.394912807e-02f, +2.552635955e-01f, +8.204299485e-01f, -5.931547226e-02f }, + { -1.392615094e-02f, +2.549648062e-01f, +8.207086532e-01f, -5.932186275e-02f }, + { -1.390319354e-02f, +2.546661344e-01f, +8.209871961e-01f, -5.932819120e-02f }, + { -1.388025589e-02f, +2.543675803e-01f, +8.212655772e-01f, -5.933445753e-02f }, + { -1.385733799e-02f, +2.540691440e-01f, +8.215437962e-01f, -5.934066165e-02f }, + { -1.383443984e-02f, +2.537708257e-01f, +8.218218531e-01f, -5.934680349e-02f }, + { -1.381156147e-02f, +2.534726253e-01f, +8.220997475e-01f, -5.935288297e-02f }, + { -1.378870286e-02f, +2.531745431e-01f, +8.223774794e-01f, -5.935889999e-02f }, + { -1.376586404e-02f, +2.528765790e-01f, +8.226550485e-01f, -5.936485448e-02f }, + { -1.374304500e-02f, +2.525787333e-01f, +8.229324548e-01f, -5.937074636e-02f }, + { -1.372024576e-02f, +2.522810059e-01f, +8.232096981e-01f, -5.937657555e-02f }, + { -1.369746632e-02f, +2.519833971e-01f, +8.234867781e-01f, -5.938234196e-02f }, + { -1.367470668e-02f, +2.516859068e-01f, +8.237636948e-01f, -5.938804550e-02f }, + { -1.365196686e-02f, +2.513885353e-01f, +8.240404479e-01f, -5.939368611e-02f }, + { -1.362924687e-02f, +2.510912825e-01f, +8.243170373e-01f, -5.939926369e-02f }, + { -1.360654670e-02f, +2.507941486e-01f, +8.245934629e-01f, -5.940477816e-02f }, + { -1.358386636e-02f, +2.504971337e-01f, +8.248697244e-01f, -5.941022944e-02f }, + { -1.356120587e-02f, +2.502002379e-01f, +8.251458217e-01f, -5.941561746e-02f }, + { -1.353856523e-02f, +2.499034613e-01f, +8.254217546e-01f, -5.942094212e-02f }, + { -1.351594444e-02f, +2.496068040e-01f, +8.256975230e-01f, -5.942620334e-02f }, + { -1.349334351e-02f, +2.493102660e-01f, +8.259731267e-01f, -5.943140104e-02f }, + { -1.347076245e-02f, +2.490138475e-01f, +8.262485655e-01f, -5.943653515e-02f }, + { -1.344820127e-02f, +2.487175486e-01f, +8.265238393e-01f, -5.944160557e-02f }, + { -1.342565996e-02f, +2.484213694e-01f, +8.267989479e-01f, -5.944661222e-02f }, + { -1.340313855e-02f, +2.481253099e-01f, +8.270738912e-01f, -5.945155503e-02f }, + { -1.338063703e-02f, +2.478293703e-01f, +8.273486689e-01f, -5.945643390e-02f }, + { -1.335815541e-02f, +2.475335507e-01f, +8.276232810e-01f, -5.946124877e-02f }, + { -1.333569370e-02f, +2.472378511e-01f, +8.278977272e-01f, -5.946599953e-02f }, + { -1.331325190e-02f, +2.469422717e-01f, +8.281720074e-01f, -5.947068612e-02f }, + { -1.329083001e-02f, +2.466468125e-01f, +8.284461214e-01f, -5.947530845e-02f }, + { -1.326842806e-02f, +2.463514737e-01f, +8.287200691e-01f, -5.947986644e-02f }, + { -1.324604604e-02f, +2.460562553e-01f, +8.289938502e-01f, -5.948436000e-02f }, + { -1.322368395e-02f, +2.457611574e-01f, +8.292674647e-01f, -5.948878905e-02f }, + { -1.320134181e-02f, +2.454661802e-01f, +8.295409124e-01f, -5.949315351e-02f }, + { -1.317901962e-02f, +2.451713237e-01f, +8.298141930e-01f, -5.949745330e-02f }, + { -1.315671739e-02f, +2.448765881e-01f, +8.300873065e-01f, -5.950168834e-02f }, + { -1.313443511e-02f, +2.445819733e-01f, +8.303602527e-01f, -5.950585853e-02f }, + { -1.311217281e-02f, +2.442874796e-01f, +8.306330313e-01f, -5.950996381e-02f }, + { -1.308993048e-02f, +2.439931070e-01f, +8.309056424e-01f, -5.951400408e-02f }, + { -1.306770813e-02f, +2.436988556e-01f, +8.311780856e-01f, -5.951797926e-02f }, + { -1.304550576e-02f, +2.434047255e-01f, +8.314503608e-01f, -5.952188928e-02f }, + { -1.302332339e-02f, +2.431107168e-01f, +8.317224679e-01f, -5.952573404e-02f }, + { -1.300116101e-02f, +2.428168296e-01f, +8.319944067e-01f, -5.952951347e-02f }, + { -1.297901864e-02f, +2.425230639e-01f, +8.322661770e-01f, -5.953322748e-02f }, + { -1.295689627e-02f, +2.422294200e-01f, +8.325377786e-01f, -5.953687600e-02f }, + { -1.293479392e-02f, +2.419358978e-01f, +8.328092115e-01f, -5.954045893e-02f }, + { -1.291271159e-02f, +2.416424975e-01f, +8.330804754e-01f, -5.954397620e-02f }, + { -1.289064929e-02f, +2.413492191e-01f, +8.333515702e-01f, -5.954742771e-02f }, + { -1.286860701e-02f, +2.410560629e-01f, +8.336224957e-01f, -5.955081340e-02f }, + { -1.284658477e-02f, +2.407630287e-01f, +8.338932518e-01f, -5.955413318e-02f }, + { -1.282458258e-02f, +2.404701168e-01f, +8.341638383e-01f, -5.955738696e-02f }, + { -1.280260043e-02f, +2.401773273e-01f, +8.344342550e-01f, -5.956057466e-02f }, + { -1.278063833e-02f, +2.398846601e-01f, +8.347045017e-01f, -5.956369619e-02f }, + { -1.275869629e-02f, +2.395921155e-01f, +8.349745784e-01f, -5.956675149e-02f }, + { -1.273677432e-02f, +2.392996936e-01f, +8.352444848e-01f, -5.956974045e-02f }, + { -1.271487241e-02f, +2.390073943e-01f, +8.355142207e-01f, -5.957266301e-02f }, + { -1.269299057e-02f, +2.387152178e-01f, +8.357837861e-01f, -5.957551907e-02f }, + { -1.267112882e-02f, +2.384231642e-01f, +8.360531808e-01f, -5.957830856e-02f }, + { -1.264928715e-02f, +2.381312337e-01f, +8.363224045e-01f, -5.958103139e-02f }, + { -1.262746557e-02f, +2.378394262e-01f, +8.365914572e-01f, -5.958368747e-02f }, + { -1.260566408e-02f, +2.375477418e-01f, +8.368603387e-01f, -5.958627674e-02f }, + { -1.258388269e-02f, +2.372561808e-01f, +8.371290487e-01f, -5.958879909e-02f }, + { -1.256212141e-02f, +2.369647431e-01f, +8.373975872e-01f, -5.959125445e-02f }, + { -1.254038023e-02f, +2.366734288e-01f, +8.376659540e-01f, -5.959364274e-02f }, + { -1.251865917e-02f, +2.363822381e-01f, +8.379341490e-01f, -5.959596388e-02f }, + { -1.249695823e-02f, +2.360911710e-01f, +8.382021718e-01f, -5.959821777e-02f }, + { -1.247527741e-02f, +2.358002277e-01f, +8.384700225e-01f, -5.960040434e-02f }, + { -1.245361672e-02f, +2.355094081e-01f, +8.387377009e-01f, -5.960252351e-02f }, + { -1.243197617e-02f, +2.352187125e-01f, +8.390052067e-01f, -5.960457519e-02f }, + { -1.241035575e-02f, +2.349281409e-01f, +8.392725398e-01f, -5.960655929e-02f }, + { -1.238875548e-02f, +2.346376934e-01f, +8.395397001e-01f, -5.960847575e-02f }, + { -1.236717535e-02f, +2.343473700e-01f, +8.398066874e-01f, -5.961032446e-02f }, + { -1.234561537e-02f, +2.340571709e-01f, +8.400735015e-01f, -5.961210535e-02f }, + { -1.232407555e-02f, +2.337670962e-01f, +8.403401423e-01f, -5.961381834e-02f }, + { -1.230255589e-02f, +2.334771460e-01f, +8.406066096e-01f, -5.961546335e-02f }, + { -1.228105640e-02f, +2.331873202e-01f, +8.408729033e-01f, -5.961704028e-02f }, + { -1.225957708e-02f, +2.328976192e-01f, +8.411390231e-01f, -5.961854906e-02f }, + { -1.223811793e-02f, +2.326080428e-01f, +8.414049690e-01f, -5.961998961e-02f }, + { -1.221667896e-02f, +2.323185913e-01f, +8.416707408e-01f, -5.962136183e-02f }, + { -1.219526018e-02f, +2.320292646e-01f, +8.419363383e-01f, -5.962266566e-02f }, + { -1.217386158e-02f, +2.317400630e-01f, +8.422017613e-01f, -5.962390099e-02f }, + { -1.215248317e-02f, +2.314509865e-01f, +8.424670098e-01f, -5.962506776e-02f }, + { -1.213112496e-02f, +2.311620351e-01f, +8.427320835e-01f, -5.962616588e-02f }, + { -1.210978695e-02f, +2.308732090e-01f, +8.429969822e-01f, -5.962719526e-02f }, + { -1.208846914e-02f, +2.305845082e-01f, +8.432617059e-01f, -5.962815583e-02f }, + { -1.206717155e-02f, +2.302959329e-01f, +8.435262543e-01f, -5.962904749e-02f }, + { -1.204589416e-02f, +2.300074831e-01f, +8.437906274e-01f, -5.962987017e-02f }, + { -1.202463700e-02f, +2.297191590e-01f, +8.440548248e-01f, -5.963062378e-02f }, + { -1.200340005e-02f, +2.294309606e-01f, +8.443188466e-01f, -5.963130824e-02f }, + { -1.198218333e-02f, +2.291428879e-01f, +8.445826924e-01f, -5.963192347e-02f }, + { -1.196098683e-02f, +2.288549412e-01f, +8.448463623e-01f, -5.963246938e-02f }, + { -1.193981057e-02f, +2.285671204e-01f, +8.451098559e-01f, -5.963294588e-02f }, + { -1.191865455e-02f, +2.282794257e-01f, +8.453731732e-01f, -5.963335291e-02f }, + { -1.189751876e-02f, +2.279918571e-01f, +8.456363139e-01f, -5.963369036e-02f }, + { -1.187640322e-02f, +2.277044148e-01f, +8.458992780e-01f, -5.963395817e-02f }, + { -1.185530793e-02f, +2.274170988e-01f, +8.461620653e-01f, -5.963415624e-02f }, + { -1.183423289e-02f, +2.271299092e-01f, +8.464246755e-01f, -5.963428449e-02f }, + { -1.181317810e-02f, +2.268428462e-01f, +8.466871086e-01f, -5.963434285e-02f }, + { -1.179214358e-02f, +2.265559097e-01f, +8.469493644e-01f, -5.963433122e-02f }, + { -1.177112931e-02f, +2.262690999e-01f, +8.472114428e-01f, -5.963424952e-02f }, + { -1.175013531e-02f, +2.259824169e-01f, +8.474733435e-01f, -5.963409767e-02f }, + { -1.172916159e-02f, +2.256958607e-01f, +8.477350664e-01f, -5.963387559e-02f }, + { -1.170820813e-02f, +2.254094315e-01f, +8.479966114e-01f, -5.963358319e-02f }, + { -1.168727495e-02f, +2.251231293e-01f, +8.482579783e-01f, -5.963322039e-02f }, + { -1.166636205e-02f, +2.248369542e-01f, +8.485191669e-01f, -5.963278711e-02f }, + { -1.164546944e-02f, +2.245509063e-01f, +8.487801771e-01f, -5.963228326e-02f }, + { -1.162459711e-02f, +2.242649857e-01f, +8.490410088e-01f, -5.963170876e-02f }, + { -1.160374507e-02f, +2.239791925e-01f, +8.493016617e-01f, -5.963106352e-02f }, + { -1.158291333e-02f, +2.236935267e-01f, +8.495621358e-01f, -5.963034747e-02f }, + { -1.156210188e-02f, +2.234079885e-01f, +8.498224307e-01f, -5.962956051e-02f }, + { -1.154131073e-02f, +2.231225780e-01f, +8.500825465e-01f, -5.962870257e-02f }, + { -1.152053989e-02f, +2.228372951e-01f, +8.503424830e-01f, -5.962777357e-02f }, + { -1.149978935e-02f, +2.225521401e-01f, +8.506022399e-01f, -5.962677341e-02f }, + { -1.147905912e-02f, +2.222671129e-01f, +8.508618171e-01f, -5.962570201e-02f }, + { -1.145834920e-02f, +2.219822138e-01f, +8.511212145e-01f, -5.962455930e-02f }, + { -1.143765960e-02f, +2.216974426e-01f, +8.513804320e-01f, -5.962334519e-02f }, + { -1.141699032e-02f, +2.214127997e-01f, +8.516394693e-01f, -5.962205959e-02f }, + { -1.139634135e-02f, +2.211282850e-01f, +8.518983262e-01f, -5.962070242e-02f }, + { -1.137571272e-02f, +2.208438986e-01f, +8.521570028e-01f, -5.961927360e-02f }, + { -1.135510441e-02f, +2.205596406e-01f, +8.524154987e-01f, -5.961777305e-02f }, + { -1.133451643e-02f, +2.202755110e-01f, +8.526738139e-01f, -5.961620067e-02f }, + { -1.131394878e-02f, +2.199915101e-01f, +8.529319481e-01f, -5.961455639e-02f }, + { -1.129340147e-02f, +2.197076378e-01f, +8.531899012e-01f, -5.961284013e-02f }, + { -1.127287449e-02f, +2.194238943e-01f, +8.534476731e-01f, -5.961105179e-02f }, + { -1.125236786e-02f, +2.191402796e-01f, +8.537052637e-01f, -5.960919130e-02f }, + { -1.123188157e-02f, +2.188567938e-01f, +8.539626726e-01f, -5.960725858e-02f }, + { -1.121141563e-02f, +2.185734369e-01f, +8.542198999e-01f, -5.960525353e-02f }, + { -1.119097004e-02f, +2.182902092e-01f, +8.544769453e-01f, -5.960317608e-02f }, + { -1.117054480e-02f, +2.180071107e-01f, +8.547338087e-01f, -5.960102614e-02f }, + { -1.115013991e-02f, +2.177241413e-01f, +8.549904899e-01f, -5.959880364e-02f }, + { -1.112975538e-02f, +2.174413013e-01f, +8.552469888e-01f, -5.959650847e-02f }, + { -1.110939121e-02f, +2.171585908e-01f, +8.555033052e-01f, -5.959414057e-02f }, + { -1.108904740e-02f, +2.168760097e-01f, +8.557594390e-01f, -5.959169984e-02f }, + { -1.106872396e-02f, +2.165935582e-01f, +8.560153900e-01f, -5.958918621e-02f }, + { -1.104842088e-02f, +2.163112364e-01f, +8.562711580e-01f, -5.958659959e-02f }, + { -1.102813817e-02f, +2.160290443e-01f, +8.565267430e-01f, -5.958393990e-02f }, + { -1.100787583e-02f, +2.157469820e-01f, +8.567821446e-01f, -5.958120705e-02f }, + { -1.098763386e-02f, +2.154650497e-01f, +8.570373629e-01f, -5.957840096e-02f }, + { -1.096741227e-02f, +2.151832473e-01f, +8.572923976e-01f, -5.957552154e-02f }, + { -1.094721106e-02f, +2.149015750e-01f, +8.575472486e-01f, -5.957256872e-02f }, + { -1.092703022e-02f, +2.146200329e-01f, +8.578019157e-01f, -5.956954241e-02f }, + { -1.090686977e-02f, +2.143386210e-01f, +8.580563988e-01f, -5.956644252e-02f }, + { -1.088672970e-02f, +2.140573395e-01f, +8.583106977e-01f, -5.956326897e-02f }, + { -1.086661002e-02f, +2.137761883e-01f, +8.585648123e-01f, -5.956002168e-02f }, + { -1.084651073e-02f, +2.134951677e-01f, +8.588187423e-01f, -5.955670057e-02f }, + { -1.082643182e-02f, +2.132142776e-01f, +8.590724878e-01f, -5.955330554e-02f }, + { -1.080637331e-02f, +2.129335181e-01f, +8.593260484e-01f, -5.954983652e-02f }, + { -1.078633519e-02f, +2.126528894e-01f, +8.595794240e-01f, -5.954629343e-02f }, + { -1.076631747e-02f, +2.123723915e-01f, +8.598326146e-01f, -5.954267617e-02f }, + { -1.074632015e-02f, +2.120920245e-01f, +8.600856199e-01f, -5.953898467e-02f }, + { -1.072634322e-02f, +2.118117885e-01f, +8.603384398e-01f, -5.953521884e-02f }, + { -1.070638669e-02f, +2.115316835e-01f, +8.605910741e-01f, -5.953137860e-02f }, + { -1.068645057e-02f, +2.112517097e-01f, +8.608435227e-01f, -5.952746386e-02f }, + { -1.066653486e-02f, +2.109718671e-01f, +8.610957855e-01f, -5.952347454e-02f }, + { -1.064663954e-02f, +2.106921557e-01f, +8.613478622e-01f, -5.951941056e-02f }, + { -1.062676464e-02f, +2.104125758e-01f, +8.615997527e-01f, -5.951527184e-02f }, + { -1.060691015e-02f, +2.101331273e-01f, +8.618514569e-01f, -5.951105828e-02f }, + { -1.058707606e-02f, +2.098538103e-01f, +8.621029746e-01f, -5.950676981e-02f }, + { -1.056726239e-02f, +2.095746250e-01f, +8.623543057e-01f, -5.950240634e-02f }, + { -1.054746914e-02f, +2.092955714e-01f, +8.626054500e-01f, -5.949796779e-02f }, + { -1.052769630e-02f, +2.090166495e-01f, +8.628564073e-01f, -5.949345407e-02f }, + { -1.050794387e-02f, +2.087378595e-01f, +8.631071776e-01f, -5.948886510e-02f }, + { -1.048821187e-02f, +2.084592015e-01f, +8.633577606e-01f, -5.948420080e-02f }, + { -1.046850028e-02f, +2.081806754e-01f, +8.636081562e-01f, -5.947946108e-02f }, + { -1.044880911e-02f, +2.079022815e-01f, +8.638583642e-01f, -5.947464586e-02f }, + { -1.042913837e-02f, +2.076240197e-01f, +8.641083845e-01f, -5.946975506e-02f }, + { -1.040948805e-02f, +2.073458902e-01f, +8.643582170e-01f, -5.946478859e-02f }, + { -1.038985815e-02f, +2.070678930e-01f, +8.646078615e-01f, -5.945974637e-02f }, + { -1.037024868e-02f, +2.067900282e-01f, +8.648573178e-01f, -5.945462831e-02f }, + { -1.035065964e-02f, +2.065122959e-01f, +8.651065858e-01f, -5.944943433e-02f }, + { -1.033109103e-02f, +2.062346962e-01f, +8.653556654e-01f, -5.944416434e-02f }, + { -1.031154284e-02f, +2.059572292e-01f, +8.656045563e-01f, -5.943881827e-02f }, + { -1.029201508e-02f, +2.056798948e-01f, +8.658532585e-01f, -5.943339603e-02f }, + { -1.027250776e-02f, +2.054026933e-01f, +8.661017718e-01f, -5.942789753e-02f }, + { -1.025302087e-02f, +2.051256246e-01f, +8.663500959e-01f, -5.942232269e-02f }, + { -1.023355441e-02f, +2.048486889e-01f, +8.665982309e-01f, -5.941667144e-02f }, + { -1.021410838e-02f, +2.045718862e-01f, +8.668461765e-01f, -5.941094367e-02f }, + { -1.019468279e-02f, +2.042952167e-01f, +8.670939326e-01f, -5.940513931e-02f }, + { -1.017527764e-02f, +2.040186803e-01f, +8.673414990e-01f, -5.939925828e-02f }, + { -1.015589292e-02f, +2.037422772e-01f, +8.675888756e-01f, -5.939330049e-02f }, + { -1.013652864e-02f, +2.034660075e-01f, +8.678360622e-01f, -5.938726586e-02f }, + { -1.011718480e-02f, +2.031898712e-01f, +8.680830587e-01f, -5.938115430e-02f }, + { -1.009786140e-02f, +2.029138683e-01f, +8.683298650e-01f, -5.937496574e-02f }, + { -1.007855843e-02f, +2.026379991e-01f, +8.685764808e-01f, -5.936870008e-02f }, + { -1.005927591e-02f, +2.023622635e-01f, +8.688229060e-01f, -5.936235724e-02f }, + { -1.004001383e-02f, +2.020866616e-01f, +8.690691405e-01f, -5.935593714e-02f }, + { -1.002077218e-02f, +2.018111936e-01f, +8.693151841e-01f, -5.934943969e-02f }, + { -1.000155098e-02f, +2.015358594e-01f, +8.695610368e-01f, -5.934286482e-02f }, + { -9.982350225e-03f, +2.012606592e-01f, +8.698066982e-01f, -5.933621243e-02f }, + { -9.963169910e-03f, +2.009855930e-01f, +8.700521683e-01f, -5.932948245e-02f }, + { -9.944010038e-03f, +2.007106609e-01f, +8.702974470e-01f, -5.932267479e-02f }, + { -9.924870610e-03f, +2.004358631e-01f, +8.705425340e-01f, -5.931578936e-02f }, + { -9.905751626e-03f, +2.001611994e-01f, +8.707874293e-01f, -5.930882608e-02f }, + { -9.886653086e-03f, +1.998866701e-01f, +8.710321326e-01f, -5.930178487e-02f }, + { -9.867574990e-03f, +1.996122753e-01f, +8.712766439e-01f, -5.929466565e-02f }, + { -9.848517340e-03f, +1.993380149e-01f, +8.715209630e-01f, -5.928746832e-02f }, + { -9.829480135e-03f, +1.990638891e-01f, +8.717650897e-01f, -5.928019281e-02f }, + { -9.810463375e-03f, +1.987898979e-01f, +8.720090239e-01f, -5.927283903e-02f }, + { -9.791467061e-03f, +1.985160414e-01f, +8.722527654e-01f, -5.926540690e-02f }, + { -9.772491192e-03f, +1.982423197e-01f, +8.724963141e-01f, -5.925789634e-02f }, + { -9.753535770e-03f, +1.979687329e-01f, +8.727396699e-01f, -5.925030726e-02f }, + { -9.734600793e-03f, +1.976952810e-01f, +8.729828325e-01f, -5.924263957e-02f }, + { -9.715686262e-03f, +1.974219642e-01f, +8.732258019e-01f, -5.923489319e-02f }, + { -9.696792177e-03f, +1.971487824e-01f, +8.734685779e-01f, -5.922706804e-02f }, + { -9.677918538e-03f, +1.968757357e-01f, +8.737111603e-01f, -5.921916404e-02f }, + { -9.659065344e-03f, +1.966028244e-01f, +8.739535491e-01f, -5.921118110e-02f }, + { -9.640232597e-03f, +1.963300483e-01f, +8.741957439e-01f, -5.920311914e-02f }, + { -9.621420295e-03f, +1.960574076e-01f, +8.744377448e-01f, -5.919497807e-02f }, + { -9.602628439e-03f, +1.957849023e-01f, +8.746795516e-01f, -5.918675781e-02f }, + { -9.583857028e-03f, +1.955125326e-01f, +8.749211640e-01f, -5.917845827e-02f }, + { -9.565106062e-03f, +1.952402985e-01f, +8.751625821e-01f, -5.917007938e-02f }, + { -9.546375540e-03f, +1.949682000e-01f, +8.754038055e-01f, -5.916162104e-02f }, + { -9.527665464e-03f, +1.946962373e-01f, +8.756448342e-01f, -5.915308317e-02f }, + { -9.508975831e-03f, +1.944244105e-01f, +8.758856680e-01f, -5.914446570e-02f }, + { -9.490306643e-03f, +1.941527195e-01f, +8.761263068e-01f, -5.913576853e-02f }, + { -9.471657898e-03f, +1.938811645e-01f, +8.763667504e-01f, -5.912699159e-02f }, + { -9.453029596e-03f, +1.936097455e-01f, +8.766069987e-01f, -5.911813478e-02f }, + { -9.434421737e-03f, +1.933384626e-01f, +8.768470516e-01f, -5.910919802e-02f }, + { -9.415834320e-03f, +1.930673159e-01f, +8.770869088e-01f, -5.910018124e-02f }, + { -9.397267344e-03f, +1.927963055e-01f, +8.773265703e-01f, -5.909108434e-02f }, + { -9.378720810e-03f, +1.925254314e-01f, +8.775660358e-01f, -5.908190725e-02f }, + { -9.360194716e-03f, +1.922546937e-01f, +8.778053053e-01f, -5.907264987e-02f }, + { -9.341689062e-03f, +1.919840925e-01f, +8.780443786e-01f, -5.906331213e-02f }, + { -9.323203848e-03f, +1.917136278e-01f, +8.782832556e-01f, -5.905389393e-02f }, + { -9.304739072e-03f, +1.914432997e-01f, +8.785219361e-01f, -5.904439521e-02f }, + { -9.286294734e-03f, +1.911731083e-01f, +8.787604199e-01f, -5.903481587e-02f }, + { -9.267870833e-03f, +1.909030537e-01f, +8.789987070e-01f, -5.902515582e-02f }, + { -9.249467369e-03f, +1.906331359e-01f, +8.792367971e-01f, -5.901541499e-02f }, + { -9.231084340e-03f, +1.903633550e-01f, +8.794746902e-01f, -5.900559330e-02f }, + { -9.212721746e-03f, +1.900937110e-01f, +8.797123860e-01f, -5.899569065e-02f }, + { -9.194379586e-03f, +1.898242041e-01f, +8.799498845e-01f, -5.898570696e-02f }, + { -9.176057859e-03f, +1.895548343e-01f, +8.801871854e-01f, -5.897564215e-02f }, + { -9.157756564e-03f, +1.892856017e-01f, +8.804242888e-01f, -5.896549614e-02f }, + { -9.139475700e-03f, +1.890165064e-01f, +8.806611943e-01f, -5.895526884e-02f }, + { -9.121215266e-03f, +1.887475484e-01f, +8.808979018e-01f, -5.894496016e-02f }, + { -9.102975262e-03f, +1.884787277e-01f, +8.811344113e-01f, -5.893457003e-02f }, + { -9.084755685e-03f, +1.882100446e-01f, +8.813707226e-01f, -5.892409837e-02f }, + { -9.066556536e-03f, +1.879414989e-01f, +8.816068354e-01f, -5.891354507e-02f }, + { -9.048377812e-03f, +1.876730909e-01f, +8.818427498e-01f, -5.890291007e-02f }, + { -9.030219514e-03f, +1.874048205e-01f, +8.820784655e-01f, -5.889219328e-02f }, + { -9.012081638e-03f, +1.871366879e-01f, +8.823139824e-01f, -5.888139461e-02f }, + { -8.993964185e-03f, +1.868686931e-01f, +8.825493003e-01f, -5.887051398e-02f }, + { -8.975867154e-03f, +1.866008361e-01f, +8.827844191e-01f, -5.885955131e-02f }, + { -8.957790542e-03f, +1.863331172e-01f, +8.830193387e-01f, -5.884850651e-02f }, + { -8.939734348e-03f, +1.860655362e-01f, +8.832540589e-01f, -5.883737950e-02f }, + { -8.921698572e-03f, +1.857980933e-01f, +8.834885795e-01f, -5.882617019e-02f }, + { -8.903683211e-03f, +1.855307886e-01f, +8.837229005e-01f, -5.881487851e-02f }, + { -8.885688265e-03f, +1.852636221e-01f, +8.839570217e-01f, -5.880350436e-02f }, + { -8.867713732e-03f, +1.849965939e-01f, +8.841909429e-01f, -5.879204767e-02f }, + { -8.849759611e-03f, +1.847297040e-01f, +8.844246640e-01f, -5.878050834e-02f }, + { -8.831825899e-03f, +1.844629526e-01f, +8.846581849e-01f, -5.876888630e-02f }, + { -8.813912596e-03f, +1.841963397e-01f, +8.848915054e-01f, -5.875718146e-02f }, + { -8.796019700e-03f, +1.839298653e-01f, +8.851246253e-01f, -5.874539374e-02f }, + { -8.778147210e-03f, +1.836635296e-01f, +8.853575446e-01f, -5.873352306e-02f }, + { -8.760295123e-03f, +1.833973325e-01f, +8.855902631e-01f, -5.872156932e-02f }, + { -8.742463438e-03f, +1.831312743e-01f, +8.858227806e-01f, -5.870953245e-02f }, + { -8.724652154e-03f, +1.828653548e-01f, +8.860550970e-01f, -5.869741236e-02f }, + { -8.706861268e-03f, +1.825995743e-01f, +8.862872121e-01f, -5.868520898e-02f }, + { -8.689090780e-03f, +1.823339328e-01f, +8.865191259e-01f, -5.867292220e-02f }, + { -8.671340686e-03f, +1.820684302e-01f, +8.867508381e-01f, -5.866055196e-02f }, + { -8.653610986e-03f, +1.818030668e-01f, +8.869823487e-01f, -5.864809816e-02f }, + { -8.635901678e-03f, +1.815378426e-01f, +8.872136574e-01f, -5.863556073e-02f }, + { -8.618212759e-03f, +1.812727576e-01f, +8.874447642e-01f, -5.862293958e-02f }, + { -8.600544229e-03f, +1.810078118e-01f, +8.876756689e-01f, -5.861023462e-02f }, + { -8.582896084e-03f, +1.807430055e-01f, +8.879063714e-01f, -5.859744577e-02f }, + { -8.565268323e-03f, +1.804783386e-01f, +8.881368715e-01f, -5.858457295e-02f }, + { -8.547660944e-03f, +1.802138112e-01f, +8.883671691e-01f, -5.857161608e-02f }, + { -8.530073945e-03f, +1.799494234e-01f, +8.885972640e-01f, -5.855857506e-02f }, + { -8.512507324e-03f, +1.796851751e-01f, +8.888271561e-01f, -5.854544983e-02f }, + { -8.494961078e-03f, +1.794210666e-01f, +8.890568452e-01f, -5.853224028e-02f }, + { -8.477435207e-03f, +1.791570979e-01f, +8.892863313e-01f, -5.851894634e-02f }, + { -8.459929707e-03f, +1.788932690e-01f, +8.895156142e-01f, -5.850556793e-02f }, + { -8.442444576e-03f, +1.786295800e-01f, +8.897446936e-01f, -5.849210496e-02f }, + { -8.424979813e-03f, +1.783660309e-01f, +8.899735696e-01f, -5.847855735e-02f }, + { -8.407535414e-03f, +1.781026219e-01f, +8.902022419e-01f, -5.846492501e-02f }, + { -8.390111379e-03f, +1.778393529e-01f, +8.904307105e-01f, -5.845120786e-02f }, + { -8.372707704e-03f, +1.775762242e-01f, +8.906589751e-01f, -5.843740582e-02f }, + { -8.355324387e-03f, +1.773132356e-01f, +8.908870357e-01f, -5.842351880e-02f }, + { -8.337961425e-03f, +1.770503873e-01f, +8.911148920e-01f, -5.840954672e-02f }, + { -8.320618817e-03f, +1.767876794e-01f, +8.913425440e-01f, -5.839548949e-02f }, + { -8.303296561e-03f, +1.765251119e-01f, +8.915699915e-01f, -5.838134704e-02f }, + { -8.285994652e-03f, +1.762626848e-01f, +8.917972344e-01f, -5.836711927e-02f }, + { -8.268713090e-03f, +1.760003983e-01f, +8.920242725e-01f, -5.835280610e-02f }, + { -8.251451871e-03f, +1.757382524e-01f, +8.922511057e-01f, -5.833840746e-02f }, + { -8.234210994e-03f, +1.754762472e-01f, +8.924777339e-01f, -5.832392325e-02f }, + { -8.216990455e-03f, +1.752143827e-01f, +8.927041569e-01f, -5.830935339e-02f }, + { -8.199790252e-03f, +1.749526590e-01f, +8.929303746e-01f, -5.829469780e-02f }, + { -8.182610382e-03f, +1.746910762e-01f, +8.931563868e-01f, -5.827995640e-02f }, + { -8.165450843e-03f, +1.744296343e-01f, +8.933821934e-01f, -5.826512910e-02f }, + { -8.148311631e-03f, +1.741683333e-01f, +8.936077942e-01f, -5.825021582e-02f }, + { -8.131192745e-03f, +1.739071734e-01f, +8.938331892e-01f, -5.823521647e-02f }, + { -8.114094182e-03f, +1.736461547e-01f, +8.940583782e-01f, -5.822013097e-02f }, + { -8.097015938e-03f, +1.733852771e-01f, +8.942833610e-01f, -5.820495924e-02f }, + { -8.079958012e-03f, +1.731245407e-01f, +8.945081375e-01f, -5.818970119e-02f }, + { -8.062920399e-03f, +1.728639457e-01f, +8.947327076e-01f, -5.817435673e-02f }, + { -8.045903098e-03f, +1.726034920e-01f, +8.949570711e-01f, -5.815892580e-02f }, + { -8.028906105e-03f, +1.723431797e-01f, +8.951812279e-01f, -5.814340830e-02f }, + { -8.011929418e-03f, +1.720830089e-01f, +8.954051779e-01f, -5.812780414e-02f }, + { -7.994973033e-03f, +1.718229797e-01f, +8.956289209e-01f, -5.811211325e-02f }, + { -7.978036948e-03f, +1.715630920e-01f, +8.958524568e-01f, -5.809633554e-02f }, + { -7.961121159e-03f, +1.713033461e-01f, +8.960757854e-01f, -5.808047093e-02f }, + { -7.944225664e-03f, +1.710437419e-01f, +8.962989066e-01f, -5.806451933e-02f }, + { -7.927350459e-03f, +1.707842794e-01f, +8.965218203e-01f, -5.804848066e-02f }, + { -7.910495542e-03f, +1.705249588e-01f, +8.967445263e-01f, -5.803235484e-02f }, + { -7.893660909e-03f, +1.702657802e-01f, +8.969670245e-01f, -5.801614178e-02f }, + { -7.876846558e-03f, +1.700067435e-01f, +8.971893148e-01f, -5.799984140e-02f }, + { -7.860052484e-03f, +1.697478489e-01f, +8.974113969e-01f, -5.798345361e-02f }, + { -7.843278685e-03f, +1.694890963e-01f, +8.976332709e-01f, -5.796697834e-02f }, + { -7.826525157e-03f, +1.692304860e-01f, +8.978549365e-01f, -5.795041550e-02f }, + { -7.809791898e-03f, +1.689720178e-01f, +8.980763937e-01f, -5.793376500e-02f }, + { -7.793078904e-03f, +1.687136919e-01f, +8.982976422e-01f, -5.791702676e-02f }, + { -7.776386171e-03f, +1.684555084e-01f, +8.985186819e-01f, -5.790020070e-02f }, + { -7.759713697e-03f, +1.681974672e-01f, +8.987395128e-01f, -5.788328673e-02f }, + { -7.743061477e-03f, +1.679395686e-01f, +8.989601346e-01f, -5.786628478e-02f }, + { -7.726429509e-03f, +1.676818124e-01f, +8.991805472e-01f, -5.784919475e-02f }, + { -7.709817790e-03f, +1.674241988e-01f, +8.994007506e-01f, -5.783201657e-02f }, + { -7.693226314e-03f, +1.671667279e-01f, +8.996207445e-01f, -5.781475014e-02f }, + { -7.676655080e-03f, +1.669093997e-01f, +8.998405288e-01f, -5.779739540e-02f }, + { -7.660104084e-03f, +1.666522142e-01f, +9.000601034e-01f, -5.777995224e-02f }, + { -7.643573321e-03f, +1.663951716e-01f, +9.002794682e-01f, -5.776242060e-02f }, + { -7.627062789e-03f, +1.661382718e-01f, +9.004986230e-01f, -5.774480038e-02f }, + { -7.610572484e-03f, +1.658815150e-01f, +9.007175676e-01f, -5.772709151e-02f }, + { -7.594102403e-03f, +1.656249011e-01f, +9.009363021e-01f, -5.770929389e-02f }, + { -7.577652540e-03f, +1.653684303e-01f, +9.011548261e-01f, -5.769140745e-02f }, + { -7.561222894e-03f, +1.651121027e-01f, +9.013731396e-01f, -5.767343210e-02f }, + { -7.544813460e-03f, +1.648559182e-01f, +9.015912425e-01f, -5.765536777e-02f }, + { -7.528424234e-03f, +1.645998769e-01f, +9.018091345e-01f, -5.763721435e-02f }, + { -7.512055213e-03f, +1.643439789e-01f, +9.020268157e-01f, -5.761897178e-02f }, + { -7.495706392e-03f, +1.640882243e-01f, +9.022442858e-01f, -5.760063997e-02f }, + { -7.479377769e-03f, +1.638326131e-01f, +9.024615447e-01f, -5.758221883e-02f }, + { -7.463069339e-03f, +1.635771453e-01f, +9.026785922e-01f, -5.756370829e-02f }, + { -7.446781098e-03f, +1.633218211e-01f, +9.028954283e-01f, -5.754510825e-02f }, + { -7.430513042e-03f, +1.630666404e-01f, +9.031120528e-01f, -5.752641864e-02f }, + { -7.414265167e-03f, +1.628116034e-01f, +9.033284656e-01f, -5.750763937e-02f }, + { -7.398037471e-03f, +1.625567100e-01f, +9.035446666e-01f, -5.748877036e-02f }, + { -7.381829947e-03f, +1.623019604e-01f, +9.037606555e-01f, -5.746981153e-02f }, + { -7.365642593e-03f, +1.620473546e-01f, +9.039764323e-01f, -5.745076279e-02f }, + { -7.349475404e-03f, +1.617928927e-01f, +9.041919969e-01f, -5.743162405e-02f }, + { -7.333328376e-03f, +1.615385747e-01f, +9.044073490e-01f, -5.741239524e-02f }, + { -7.317201506e-03f, +1.612844007e-01f, +9.046224887e-01f, -5.739307627e-02f }, + { -7.301094788e-03f, +1.610303707e-01f, +9.048374156e-01f, -5.737366706e-02f }, + { -7.285008220e-03f, +1.607764848e-01f, +9.050521298e-01f, -5.735416753e-02f }, + { -7.268941796e-03f, +1.605227430e-01f, +9.052666311e-01f, -5.733457759e-02f }, + { -7.252895512e-03f, +1.602691455e-01f, +9.054809193e-01f, -5.731489716e-02f }, + { -7.236869364e-03f, +1.600156922e-01f, +9.056949943e-01f, -5.729512615e-02f }, + { -7.220863348e-03f, +1.597623832e-01f, +9.059088560e-01f, -5.727526448e-02f }, + { -7.204877460e-03f, +1.595092186e-01f, +9.061225043e-01f, -5.725531208e-02f }, + { -7.188911695e-03f, +1.592561984e-01f, +9.063359389e-01f, -5.723526885e-02f }, + { -7.172966049e-03f, +1.590033227e-01f, +9.065491599e-01f, -5.721513471e-02f }, + { -7.157040517e-03f, +1.587505915e-01f, +9.067621670e-01f, -5.719490958e-02f }, + { -7.141135096e-03f, +1.584980049e-01f, +9.069749601e-01f, -5.717459338e-02f }, + { -7.125249780e-03f, +1.582455630e-01f, +9.071875391e-01f, -5.715418602e-02f }, + { -7.109384565e-03f, +1.579932657e-01f, +9.073999039e-01f, -5.713368743e-02f }, + { -7.093539446e-03f, +1.577411133e-01f, +9.076120543e-01f, -5.711309750e-02f }, + { -7.077714420e-03f, +1.574891056e-01f, +9.078239902e-01f, -5.709241618e-02f }, + { -7.061909482e-03f, +1.572372428e-01f, +9.080357115e-01f, -5.707164336e-02f }, + { -7.046124626e-03f, +1.569855249e-01f, +9.082472180e-01f, -5.705077897e-02f }, + { -7.030359849e-03f, +1.567339520e-01f, +9.084585096e-01f, -5.702982292e-02f }, + { -7.014615145e-03f, +1.564825241e-01f, +9.086695861e-01f, -5.700877514e-02f }, + { -6.998890510e-03f, +1.562312413e-01f, +9.088804476e-01f, -5.698763554e-02f }, + { -6.983185940e-03f, +1.559801037e-01f, +9.090910937e-01f, -5.696640402e-02f }, + { -6.967501430e-03f, +1.557291112e-01f, +9.093015244e-01f, -5.694508053e-02f }, + { -6.951836974e-03f, +1.554782640e-01f, +9.095117396e-01f, -5.692366496e-02f }, + { -6.936192569e-03f, +1.552275620e-01f, +9.097217391e-01f, -5.690215723e-02f }, + { -6.920568209e-03f, +1.549770055e-01f, +9.099315228e-01f, -5.688055727e-02f }, + { -6.904963889e-03f, +1.547265943e-01f, +9.101410905e-01f, -5.685886499e-02f }, + { -6.889379605e-03f, +1.544763286e-01f, +9.103504422e-01f, -5.683708031e-02f }, + { -6.873815352e-03f, +1.542262084e-01f, +9.105595777e-01f, -5.681520314e-02f }, + { -6.858271125e-03f, +1.539762337e-01f, +9.107684969e-01f, -5.679323340e-02f }, + { -6.842746919e-03f, +1.537264047e-01f, +9.109771996e-01f, -5.677117101e-02f }, + { -6.827242728e-03f, +1.534767213e-01f, +9.111856858e-01f, -5.674901589e-02f }, + { -6.811758549e-03f, +1.532271837e-01f, +9.113939552e-01f, -5.672676795e-02f }, + { -6.796294376e-03f, +1.529777918e-01f, +9.116020078e-01f, -5.670442710e-02f }, + { -6.780850204e-03f, +1.527285458e-01f, +9.118098434e-01f, -5.668199328e-02f }, + { -6.765426027e-03f, +1.524794457e-01f, +9.120174619e-01f, -5.665946638e-02f }, + { -6.750021842e-03f, +1.522304914e-01f, +9.122248632e-01f, -5.663684634e-02f }, + { -6.734637642e-03f, +1.519816832e-01f, +9.124320471e-01f, -5.661413307e-02f }, + { -6.719273423e-03f, +1.517330210e-01f, +9.126390136e-01f, -5.659132648e-02f }, + { -6.703929179e-03f, +1.514845048e-01f, +9.128457625e-01f, -5.656842649e-02f }, + { -6.688604905e-03f, +1.512361348e-01f, +9.130522936e-01f, -5.654543302e-02f }, + { -6.673300597e-03f, +1.509879110e-01f, +9.132586068e-01f, -5.652234599e-02f }, + { -6.658016248e-03f, +1.507398335e-01f, +9.134647021e-01f, -5.649916531e-02f }, + { -6.642751853e-03f, +1.504919022e-01f, +9.136705792e-01f, -5.647589090e-02f }, + { -6.627507408e-03f, +1.502441173e-01f, +9.138762381e-01f, -5.645252268e-02f }, + { -6.612282907e-03f, +1.499964787e-01f, +9.140816786e-01f, -5.642906057e-02f }, + { -6.597078344e-03f, +1.497489866e-01f, +9.142869006e-01f, -5.640550448e-02f }, + { -6.581893714e-03f, +1.495016410e-01f, +9.144919040e-01f, -5.638185433e-02f }, + { -6.566729012e-03f, +1.492544420e-01f, +9.146966886e-01f, -5.635811004e-02f }, + { -6.551584232e-03f, +1.490073895e-01f, +9.149012543e-01f, -5.633427152e-02f }, + { -6.536459369e-03f, +1.487604837e-01f, +9.151056011e-01f, -5.631033869e-02f }, + { -6.521354417e-03f, +1.485137245e-01f, +9.153097287e-01f, -5.628631147e-02f }, + { -6.506269371e-03f, +1.482671122e-01f, +9.155136370e-01f, -5.626218978e-02f }, + { -6.491204225e-03f, +1.480206466e-01f, +9.157173259e-01f, -5.623797353e-02f }, + { -6.476158974e-03f, +1.477743278e-01f, +9.159207954e-01f, -5.621366265e-02f }, + { -6.461133612e-03f, +1.475281560e-01f, +9.161240451e-01f, -5.618925704e-02f }, + { -6.446128134e-03f, +1.472821311e-01f, +9.163270752e-01f, -5.616475663e-02f }, + { -6.431142534e-03f, +1.470362531e-01f, +9.165298853e-01f, -5.614016133e-02f }, + { -6.416176806e-03f, +1.467905223e-01f, +9.167324754e-01f, -5.611547107e-02f }, + { -6.401230944e-03f, +1.465449385e-01f, +9.169348454e-01f, -5.609068575e-02f }, + { -6.386304943e-03f, +1.462995018e-01f, +9.171369950e-01f, -5.606580530e-02f }, + { -6.371398797e-03f, +1.460542124e-01f, +9.173389243e-01f, -5.604082963e-02f }, + { -6.356512501e-03f, +1.458090702e-01f, +9.175406331e-01f, -5.601575866e-02f }, + { -6.341646048e-03f, +1.455640752e-01f, +9.177421213e-01f, -5.599059231e-02f }, + { -6.326799433e-03f, +1.453192276e-01f, +9.179433886e-01f, -5.596533050e-02f }, + { -6.311972650e-03f, +1.450745274e-01f, +9.181444351e-01f, -5.593997314e-02f }, + { -6.297165693e-03f, +1.448299746e-01f, +9.183452606e-01f, -5.591452015e-02f }, + { -6.282378556e-03f, +1.445855693e-01f, +9.185458649e-01f, -5.588897145e-02f }, + { -6.267611233e-03f, +1.443413115e-01f, +9.187462479e-01f, -5.586332696e-02f }, + { -6.252863718e-03f, +1.440972013e-01f, +9.189464096e-01f, -5.583758659e-02f }, + { -6.238136006e-03f, +1.438532387e-01f, +9.191463497e-01f, -5.581175026e-02f }, + { -6.223428090e-03f, +1.436094238e-01f, +9.193460682e-01f, -5.578581789e-02f }, + { -6.208739964e-03f, +1.433657566e-01f, +9.195455649e-01f, -5.575978940e-02f }, + { -6.194071622e-03f, +1.431222371e-01f, +9.197448398e-01f, -5.573366470e-02f }, + { -6.179423059e-03f, +1.428788655e-01f, +9.199438926e-01f, -5.570744371e-02f }, + { -6.164794268e-03f, +1.426356417e-01f, +9.201427233e-01f, -5.568112636e-02f }, + { -6.150185242e-03f, +1.423925658e-01f, +9.203413317e-01f, -5.565471255e-02f }, + { -6.135595977e-03f, +1.421496379e-01f, +9.205397178e-01f, -5.562820221e-02f }, + { -6.121026465e-03f, +1.419068580e-01f, +9.207378813e-01f, -5.560159525e-02f }, + { -6.106476701e-03f, +1.416642261e-01f, +9.209358223e-01f, -5.557489159e-02f }, + { -6.091946678e-03f, +1.414217423e-01f, +9.211335405e-01f, -5.554809115e-02f }, + { -6.077436389e-03f, +1.411794066e-01f, +9.213310358e-01f, -5.552119385e-02f }, + { -6.062945830e-03f, +1.409372192e-01f, +9.215283081e-01f, -5.549419960e-02f }, + { -6.048474993e-03f, +1.406951799e-01f, +9.217253573e-01f, -5.546710832e-02f }, + { -6.034023872e-03f, +1.404532889e-01f, +9.219221832e-01f, -5.543991994e-02f }, + { -6.019592461e-03f, +1.402115463e-01f, +9.221187858e-01f, -5.541263436e-02f }, + { -6.005180754e-03f, +1.399699520e-01f, +9.223151649e-01f, -5.538525151e-02f }, + { -5.990788743e-03f, +1.397285061e-01f, +9.225113204e-01f, -5.535777130e-02f }, + { -5.976416423e-03f, +1.394872087e-01f, +9.227072522e-01f, -5.533019365e-02f }, + { -5.962063788e-03f, +1.392460598e-01f, +9.229029601e-01f, -5.530251848e-02f }, + { -5.947730830e-03f, +1.390050594e-01f, +9.230984441e-01f, -5.527474572e-02f }, + { -5.933417543e-03f, +1.387642076e-01f, +9.232937039e-01f, -5.524687526e-02f }, + { -5.919123921e-03f, +1.385235045e-01f, +9.234887396e-01f, -5.521890704e-02f }, + { -5.904849957e-03f, +1.382829500e-01f, +9.236835509e-01f, -5.519084097e-02f }, + { -5.890595645e-03f, +1.380425443e-01f, +9.238781378e-01f, -5.516267698e-02f }, + { -5.876360977e-03f, +1.378022873e-01f, +9.240725001e-01f, -5.513441497e-02f }, + { -5.862145949e-03f, +1.375621792e-01f, +9.242666377e-01f, -5.510605486e-02f }, + { -5.847950552e-03f, +1.373222199e-01f, +9.244605504e-01f, -5.507759658e-02f }, + { -5.833774780e-03f, +1.370824095e-01f, +9.246542383e-01f, -5.504904005e-02f }, + { -5.819618626e-03f, +1.368427480e-01f, +9.248477010e-01f, -5.502038517e-02f }, + { -5.805482085e-03f, +1.366032356e-01f, +9.250409386e-01f, -5.499163187e-02f }, + { -5.791365148e-03f, +1.363638722e-01f, +9.252339509e-01f, -5.496278007e-02f }, + { -5.777267810e-03f, +1.361246578e-01f, +9.254267378e-01f, -5.493382968e-02f }, + { -5.763190063e-03f, +1.358855926e-01f, +9.256192991e-01f, -5.490478063e-02f }, + { -5.749131901e-03f, +1.356466765e-01f, +9.258116348e-01f, -5.487563282e-02f }, + { -5.735093317e-03f, +1.354079097e-01f, +9.260037447e-01f, -5.484638619e-02f }, + { -5.721074303e-03f, +1.351692920e-01f, +9.261956287e-01f, -5.481704064e-02f }, + { -5.707074854e-03f, +1.349308237e-01f, +9.263872867e-01f, -5.478759611e-02f }, + { -5.693094963e-03f, +1.346925048e-01f, +9.265787186e-01f, -5.475805249e-02f }, + { -5.679134621e-03f, +1.344543351e-01f, +9.267699242e-01f, -5.472840972e-02f }, + { -5.665193823e-03f, +1.342163150e-01f, +9.269609034e-01f, -5.469866771e-02f }, + { -5.651272561e-03f, +1.339784442e-01f, +9.271516562e-01f, -5.466882638e-02f }, + { -5.637370829e-03f, +1.337407230e-01f, +9.273421823e-01f, -5.463888565e-02f }, + { -5.623488619e-03f, +1.335031514e-01f, +9.275324817e-01f, -5.460884543e-02f }, + { -5.609625925e-03f, +1.332657293e-01f, +9.277225543e-01f, -5.457870565e-02f }, + { -5.595782739e-03f, +1.330284568e-01f, +9.279123998e-01f, -5.454846622e-02f }, + { -5.581959054e-03f, +1.327913341e-01f, +9.281020184e-01f, -5.451812706e-02f }, + { -5.568154863e-03f, +1.325543610e-01f, +9.282914097e-01f, -5.448768810e-02f }, + { -5.554370159e-03f, +1.323175377e-01f, +9.284805736e-01f, -5.445714924e-02f }, + { -5.540604935e-03f, +1.320808642e-01f, +9.286695102e-01f, -5.442651041e-02f }, + { -5.526859184e-03f, +1.318443405e-01f, +9.288582192e-01f, -5.439577153e-02f }, + { -5.513132898e-03f, +1.316079667e-01f, +9.290467005e-01f, -5.436493251e-02f }, + { -5.499426070e-03f, +1.313717428e-01f, +9.292349540e-01f, -5.433399327e-02f }, + { -5.485738694e-03f, +1.311356689e-01f, +9.294229797e-01f, -5.430295374e-02f }, + { -5.472070761e-03f, +1.308997450e-01f, +9.296107773e-01f, -5.427181382e-02f }, + { -5.458422264e-03f, +1.306639711e-01f, +9.297983467e-01f, -5.424057345e-02f }, + { -5.444793197e-03f, +1.304283474e-01f, +9.299856879e-01f, -5.420923253e-02f }, + { -5.431183551e-03f, +1.301928737e-01f, +9.301728008e-01f, -5.417779099e-02f }, + { -5.417593320e-03f, +1.299575502e-01f, +9.303596851e-01f, -5.414624875e-02f }, + { -5.404022496e-03f, +1.297223769e-01f, +9.305463408e-01f, -5.411460571e-02f }, + { -5.390471071e-03f, +1.294873538e-01f, +9.307327679e-01f, -5.408286181e-02f }, + { -5.376939039e-03f, +1.292524811e-01f, +9.309189660e-01f, -5.405101697e-02f }, + { -5.363426391e-03f, +1.290177586e-01f, +9.311049353e-01f, -5.401907109e-02f }, + { -5.349933121e-03f, +1.287831865e-01f, +9.312906754e-01f, -5.398702410e-02f }, + { -5.336459220e-03f, +1.285487648e-01f, +9.314761864e-01f, -5.395487592e-02f }, + { -5.323004682e-03f, +1.283144936e-01f, +9.316614680e-01f, -5.392262647e-02f }, + { -5.309569498e-03f, +1.280803728e-01f, +9.318465203e-01f, -5.389027566e-02f }, + { -5.296153661e-03f, +1.278464026e-01f, +9.320313430e-01f, -5.385782342e-02f }, + { -5.282757164e-03f, +1.276125829e-01f, +9.322159361e-01f, -5.382526966e-02f }, + { -5.269379998e-03f, +1.273789138e-01f, +9.324002994e-01f, -5.379261431e-02f }, + { -5.256022157e-03f, +1.271453953e-01f, +9.325844328e-01f, -5.375985728e-02f }, + { -5.242683633e-03f, +1.269120275e-01f, +9.327683363e-01f, -5.372699848e-02f }, + { -5.229364417e-03f, +1.266788105e-01f, +9.329520096e-01f, -5.369403785e-02f }, + { -5.216064503e-03f, +1.264457441e-01f, +9.331354527e-01f, -5.366097530e-02f }, + { -5.202783882e-03f, +1.262128286e-01f, +9.333186655e-01f, -5.362781074e-02f }, + { -5.189522547e-03f, +1.259800639e-01f, +9.335016478e-01f, -5.359454410e-02f }, + { -5.176280490e-03f, +1.257474501e-01f, +9.336843996e-01f, -5.356117530e-02f }, + { -5.163057703e-03f, +1.255149871e-01f, +9.338669207e-01f, -5.352770425e-02f }, + { -5.149854178e-03f, +1.252826751e-01f, +9.340492110e-01f, -5.349413088e-02f }, + { -5.136669908e-03f, +1.250505141e-01f, +9.342312704e-01f, -5.346045510e-02f }, + { -5.123504885e-03f, +1.248185041e-01f, +9.344130987e-01f, -5.342667683e-02f }, + { -5.110359100e-03f, +1.245866451e-01f, +9.345946960e-01f, -5.339279600e-02f }, + { -5.097232546e-03f, +1.243549372e-01f, +9.347760620e-01f, -5.335881251e-02f }, + { -5.084125216e-03f, +1.241233805e-01f, +9.349571966e-01f, -5.332472630e-02f }, + { -5.071037100e-03f, +1.238919749e-01f, +9.351380998e-01f, -5.329053728e-02f }, + { -5.057968191e-03f, +1.236607205e-01f, +9.353187714e-01f, -5.325624537e-02f }, + { -5.044918481e-03f, +1.234296174e-01f, +9.354992113e-01f, -5.322185049e-02f }, + { -5.031887963e-03f, +1.231986655e-01f, +9.356794194e-01f, -5.318735255e-02f }, + { -5.018876627e-03f, +1.229678649e-01f, +9.358593955e-01f, -5.315275148e-02f }, + { -5.005884466e-03f, +1.227372157e-01f, +9.360391397e-01f, -5.311804720e-02f }, + { -4.992911472e-03f, +1.225067179e-01f, +9.362186517e-01f, -5.308323963e-02f }, + { -4.979957637e-03f, +1.222763714e-01f, +9.363979314e-01f, -5.304832868e-02f }, + { -4.967022953e-03f, +1.220461765e-01f, +9.365769788e-01f, -5.301331428e-02f }, + { -4.954107411e-03f, +1.218161330e-01f, +9.367557936e-01f, -5.297819635e-02f }, + { -4.941211003e-03f, +1.215862410e-01f, +9.369343759e-01f, -5.294297479e-02f }, + { -4.928333721e-03f, +1.213565006e-01f, +9.371127255e-01f, -5.290764955e-02f }, + { -4.915475558e-03f, +1.211269118e-01f, +9.372908423e-01f, -5.287222052e-02f }, + { -4.902636504e-03f, +1.208974746e-01f, +9.374687261e-01f, -5.283668764e-02f }, + { -4.889816551e-03f, +1.206681891e-01f, +9.376463769e-01f, -5.280105083e-02f }, + { -4.877015692e-03f, +1.204390553e-01f, +9.378237946e-01f, -5.276531000e-02f }, + { -4.864233917e-03f, +1.202100732e-01f, +9.380009790e-01f, -5.272946506e-02f }, + { -4.851471219e-03f, +1.199812429e-01f, +9.381779301e-01f, -5.269351596e-02f }, + { -4.838727590e-03f, +1.197525644e-01f, +9.383546476e-01f, -5.265746259e-02f }, + { -4.826003020e-03f, +1.195240378e-01f, +9.385311316e-01f, -5.262130489e-02f }, + { -4.813297501e-03f, +1.192956630e-01f, +9.387073818e-01f, -5.258504277e-02f }, + { -4.800611026e-03f, +1.190674401e-01f, +9.388833983e-01f, -5.254867615e-02f }, + { -4.787943585e-03f, +1.188393692e-01f, +9.390591808e-01f, -5.251220495e-02f }, + { -4.775295171e-03f, +1.186114502e-01f, +9.392347294e-01f, -5.247562909e-02f }, + { -4.762665774e-03f, +1.183836832e-01f, +9.394100437e-01f, -5.243894849e-02f }, + { -4.750055387e-03f, +1.181560683e-01f, +9.395851238e-01f, -5.240216308e-02f }, + { -4.737464000e-03f, +1.179286055e-01f, +9.397599696e-01f, -5.236527277e-02f }, + { -4.724891606e-03f, +1.177012947e-01f, +9.399345809e-01f, -5.232827748e-02f }, + { -4.712338195e-03f, +1.174741362e-01f, +9.401089576e-01f, -5.229117713e-02f }, + { -4.699803759e-03f, +1.172471298e-01f, +9.402830997e-01f, -5.225397164e-02f }, + { -4.687288290e-03f, +1.170202755e-01f, +9.404570069e-01f, -5.221666093e-02f }, + { -4.674791779e-03f, +1.167935736e-01f, +9.406306792e-01f, -5.217924493e-02f }, + { -4.662314217e-03f, +1.165670239e-01f, +9.408041166e-01f, -5.214172354e-02f }, + { -4.649855595e-03f, +1.163406265e-01f, +9.409773188e-01f, -5.210409670e-02f }, + { -4.637415906e-03f, +1.161143815e-01f, +9.411502858e-01f, -5.206636432e-02f }, + { -4.624995140e-03f, +1.158882888e-01f, +9.413230174e-01f, -5.202852632e-02f }, + { -4.612593288e-03f, +1.156623486e-01f, +9.414955136e-01f, -5.199058263e-02f }, + { -4.600210342e-03f, +1.154365607e-01f, +9.416677743e-01f, -5.195253316e-02f }, + { -4.587846293e-03f, +1.152109254e-01f, +9.418397993e-01f, -5.191437783e-02f }, + { -4.575501133e-03f, +1.149854425e-01f, +9.420115885e-01f, -5.187611657e-02f }, + { -4.563174852e-03f, +1.147601122e-01f, +9.421831418e-01f, -5.183774929e-02f }, + { -4.550867441e-03f, +1.145349345e-01f, +9.423544592e-01f, -5.179927591e-02f }, + { -4.538578892e-03f, +1.143099093e-01f, +9.425255405e-01f, -5.176069636e-02f }, + { -4.526309197e-03f, +1.140850368e-01f, +9.426963856e-01f, -5.172201055e-02f }, + { -4.514058345e-03f, +1.138603169e-01f, +9.428669944e-01f, -5.168321841e-02f }, + { -4.501826329e-03f, +1.136357497e-01f, +9.430373667e-01f, -5.164431986e-02f }, + { -4.489613138e-03f, +1.134113352e-01f, +9.432075026e-01f, -5.160531481e-02f }, + { -4.477418765e-03f, +1.131870735e-01f, +9.433774019e-01f, -5.156620319e-02f }, + { -4.465243201e-03f, +1.129629646e-01f, +9.435470644e-01f, -5.152698491e-02f }, + { -4.453086436e-03f, +1.127390085e-01f, +9.437164901e-01f, -5.148765991e-02f }, + { -4.440948461e-03f, +1.125152052e-01f, +9.438856788e-01f, -5.144822810e-02f }, + { -4.428829267e-03f, +1.122915548e-01f, +9.440546305e-01f, -5.140868939e-02f }, + { -4.416728846e-03f, +1.120680573e-01f, +9.442233450e-01f, -5.136904371e-02f }, + { -4.404647188e-03f, +1.118447128e-01f, +9.443918223e-01f, -5.132929099e-02f }, + { -4.392584284e-03f, +1.116215212e-01f, +9.445600623e-01f, -5.128943114e-02f }, + { -4.380540125e-03f, +1.113984826e-01f, +9.447280647e-01f, -5.124946408e-02f }, + { -4.368514702e-03f, +1.111755970e-01f, +9.448958296e-01f, -5.120938973e-02f }, + { -4.356508006e-03f, +1.109528645e-01f, +9.450633568e-01f, -5.116920802e-02f }, + { -4.344520028e-03f, +1.107302850e-01f, +9.452306462e-01f, -5.112891887e-02f }, + { -4.332550758e-03f, +1.105078587e-01f, +9.453976978e-01f, -5.108852219e-02f }, + { -4.320600187e-03f, +1.102855855e-01f, +9.455645113e-01f, -5.104801790e-02f }, + { -4.308668306e-03f, +1.100634655e-01f, +9.457310868e-01f, -5.100740594e-02f }, + { -4.296755107e-03f, +1.098414987e-01f, +9.458974241e-01f, -5.096668621e-02f }, + { -4.284860578e-03f, +1.096196851e-01f, +9.460635230e-01f, -5.092585865e-02f }, + { -4.272984712e-03f, +1.093980247e-01f, +9.462293836e-01f, -5.088492316e-02f }, + { -4.261127499e-03f, +1.091765177e-01f, +9.463950056e-01f, -5.084387968e-02f }, + { -4.249288929e-03f, +1.089551640e-01f, +9.465603890e-01f, -5.080272812e-02f }, + { -4.237468994e-03f, +1.087339636e-01f, +9.467255337e-01f, -5.076146841e-02f }, + { -4.225667684e-03f, +1.085129166e-01f, +9.468904396e-01f, -5.072010046e-02f }, + { -4.213884989e-03f, +1.082920229e-01f, +9.470551065e-01f, -5.067862420e-02f }, + { -4.202120901e-03f, +1.080712828e-01f, +9.472195345e-01f, -5.063703954e-02f }, + { -4.190375409e-03f, +1.078506960e-01f, +9.473837233e-01f, -5.059534642e-02f }, + { -4.178648505e-03f, +1.076302628e-01f, +9.475476728e-01f, -5.055354474e-02f }, + { -4.166940178e-03f, +1.074099830e-01f, +9.477113830e-01f, -5.051163444e-02f }, + { -4.155250420e-03f, +1.071898568e-01f, +9.478748538e-01f, -5.046961543e-02f }, + { -4.143579220e-03f, +1.069698842e-01f, +9.480380851e-01f, -5.042748764e-02f }, + { -4.131926571e-03f, +1.067500652e-01f, +9.482010767e-01f, -5.038525098e-02f }, + { -4.120292461e-03f, +1.065303997e-01f, +9.483638285e-01f, -5.034290538e-02f }, + { -4.108676881e-03f, +1.063108880e-01f, +9.485263405e-01f, -5.030045076e-02f }, + { -4.097079822e-03f, +1.060915299e-01f, +9.486886126e-01f, -5.025788704e-02f }, + { -4.085501274e-03f, +1.058723254e-01f, +9.488506446e-01f, -5.021521414e-02f }, + { -4.073941228e-03f, +1.056532748e-01f, +9.490124364e-01f, -5.017243198e-02f }, + { -4.062399673e-03f, +1.054343779e-01f, +9.491739880e-01f, -5.012954049e-02f }, + { -4.050876601e-03f, +1.052156347e-01f, +9.493352993e-01f, -5.008653959e-02f }, + { -4.039372002e-03f, +1.049970454e-01f, +9.494963700e-01f, -5.004342920e-02f }, + { -4.027885865e-03f, +1.047786099e-01f, +9.496572003e-01f, -5.000020923e-02f }, + { -4.016418182e-03f, +1.045603282e-01f, +9.498177898e-01f, -4.995687962e-02f }, + { -4.004968942e-03f, +1.043422005e-01f, +9.499781386e-01f, -4.991344028e-02f }, + { -3.993538136e-03f, +1.041242266e-01f, +9.501382466e-01f, -4.986989114e-02f }, + { -3.982125754e-03f, +1.039064067e-01f, +9.502981136e-01f, -4.982623211e-02f }, + { -3.970731786e-03f, +1.036887408e-01f, +9.504577395e-01f, -4.978246313e-02f }, + { -3.959356223e-03f, +1.034712288e-01f, +9.506171243e-01f, -4.973858410e-02f }, + { -3.947999054e-03f, +1.032538708e-01f, +9.507762678e-01f, -4.969459496e-02f }, + { -3.936660271e-03f, +1.030366669e-01f, +9.509351700e-01f, -4.965049562e-02f }, + { -3.925339862e-03f, +1.028196171e-01f, +9.510938306e-01f, -4.960628601e-02f }, + { -3.914037818e-03f, +1.026027213e-01f, +9.512522498e-01f, -4.956196605e-02f }, + { -3.902754129e-03f, +1.023859797e-01f, +9.514104273e-01f, -4.951753566e-02f }, + { -3.891488786e-03f, +1.021693921e-01f, +9.515683630e-01f, -4.947299476e-02f }, + { -3.880241778e-03f, +1.019529588e-01f, +9.517260568e-01f, -4.942834328e-02f }, + { -3.869013095e-03f, +1.017366796e-01f, +9.518835087e-01f, -4.938358114e-02f }, + { -3.857802728e-03f, +1.015205546e-01f, +9.520407186e-01f, -4.933870825e-02f }, + { -3.846610666e-03f, +1.013045839e-01f, +9.521976863e-01f, -4.929372455e-02f }, + { -3.835436900e-03f, +1.010887674e-01f, +9.523544118e-01f, -4.924862995e-02f }, + { -3.824281419e-03f, +1.008731053e-01f, +9.525108949e-01f, -4.920342438e-02f }, + { -3.813144214e-03f, +1.006575974e-01f, +9.526671355e-01f, -4.915810776e-02f }, + { -3.802025274e-03f, +1.004422438e-01f, +9.528231336e-01f, -4.911268001e-02f }, + { -3.790924590e-03f, +1.002270446e-01f, +9.529788891e-01f, -4.906714105e-02f }, + { -3.779842151e-03f, +1.000119998e-01f, +9.531344018e-01f, -4.902149080e-02f }, + { -3.768777946e-03f, +9.979710935e-02f, +9.532896717e-01f, -4.897572920e-02f }, + { -3.757731967e-03f, +9.958237334e-02f, +9.534446987e-01f, -4.892985616e-02f }, + { -3.746704203e-03f, +9.936779178e-02f, +9.535994826e-01f, -4.888387160e-02f }, + { -3.735694643e-03f, +9.915336469e-02f, +9.537540234e-01f, -4.883777544e-02f }, + { -3.724703278e-03f, +9.893909208e-02f, +9.539083209e-01f, -4.879156762e-02f }, + { -3.713730097e-03f, +9.872497399e-02f, +9.540623752e-01f, -4.874524804e-02f }, + { -3.702775091e-03f, +9.851101044e-02f, +9.542161860e-01f, -4.869881664e-02f }, + { -3.691838248e-03f, +9.829720144e-02f, +9.543697533e-01f, -4.865227334e-02f }, + { -3.680919559e-03f, +9.808354703e-02f, +9.545230770e-01f, -4.860561805e-02f }, + { -3.670019013e-03f, +9.787004721e-02f, +9.546761570e-01f, -4.855885071e-02f }, + { -3.659136601e-03f, +9.765670203e-02f, +9.548289931e-01f, -4.851197123e-02f }, + { -3.648272311e-03f, +9.744351149e-02f, +9.549815854e-01f, -4.846497954e-02f }, + { -3.637426133e-03f, +9.723047561e-02f, +9.551339337e-01f, -4.841787556e-02f }, + { -3.626598058e-03f, +9.701759443e-02f, +9.552860379e-01f, -4.837065921e-02f }, + { -3.615788075e-03f, +9.680486796e-02f, +9.554378979e-01f, -4.832333042e-02f }, + { -3.604996173e-03f, +9.659229622e-02f, +9.555895136e-01f, -4.827588911e-02f }, + { -3.594222342e-03f, +9.637987924e-02f, +9.557408849e-01f, -4.822833521e-02f }, + { -3.583466571e-03f, +9.616761703e-02f, +9.558920118e-01f, -4.818066862e-02f }, + { -3.572728851e-03f, +9.595550962e-02f, +9.560428941e-01f, -4.813288929e-02f }, + { -3.562009171e-03f, +9.574355703e-02f, +9.561935317e-01f, -4.808499713e-02f }, + { -3.551307520e-03f, +9.553175927e-02f, +9.563439245e-01f, -4.803699206e-02f }, + { -3.540623888e-03f, +9.532011637e-02f, +9.564940726e-01f, -4.798887401e-02f }, + { -3.529958264e-03f, +9.510862835e-02f, +9.566439756e-01f, -4.794064290e-02f }, + { -3.519310638e-03f, +9.489729524e-02f, +9.567936336e-01f, -4.789229866e-02f }, + { -3.508680999e-03f, +9.468611704e-02f, +9.569430465e-01f, -4.784384120e-02f }, + { -3.498069337e-03f, +9.447509378e-02f, +9.570922142e-01f, -4.779527045e-02f }, + { -3.487475641e-03f, +9.426422548e-02f, +9.572411365e-01f, -4.774658634e-02f }, + { -3.476899901e-03f, +9.405351217e-02f, +9.573898135e-01f, -4.769778879e-02f }, + { -3.466342106e-03f, +9.384295385e-02f, +9.575382449e-01f, -4.764887772e-02f }, + { -3.455802245e-03f, +9.363255055e-02f, +9.576864307e-01f, -4.759985305e-02f }, + { -3.445280308e-03f, +9.342230229e-02f, +9.578343708e-01f, -4.755071471e-02f }, + { -3.434776284e-03f, +9.321220909e-02f, +9.579820651e-01f, -4.750146263e-02f }, + { -3.424290163e-03f, +9.300227097e-02f, +9.581295136e-01f, -4.745209672e-02f }, + { -3.413821934e-03f, +9.279248795e-02f, +9.582767160e-01f, -4.740261690e-02f }, + { -3.403371585e-03f, +9.258286004e-02f, +9.584236724e-01f, -4.735302311e-02f }, + { -3.392939107e-03f, +9.237338726e-02f, +9.585703827e-01f, -4.730331527e-02f }, + { -3.382524489e-03f, +9.216406964e-02f, +9.587168467e-01f, -4.725349330e-02f }, + { -3.372127720e-03f, +9.195490720e-02f, +9.588630643e-01f, -4.720355712e-02f }, + { -3.361748789e-03f, +9.174589994e-02f, +9.590090355e-01f, -4.715350666e-02f }, + { -3.351387685e-03f, +9.153704790e-02f, +9.591547602e-01f, -4.710334184e-02f }, + { -3.341044398e-03f, +9.132835108e-02f, +9.593002383e-01f, -4.705306259e-02f }, + { -3.330718916e-03f, +9.111980950e-02f, +9.594454696e-01f, -4.700266883e-02f }, + { -3.320411230e-03f, +9.091142320e-02f, +9.595904542e-01f, -4.695216048e-02f }, + { -3.310121328e-03f, +9.070319217e-02f, +9.597351919e-01f, -4.690153746e-02f }, + { -3.299849199e-03f, +9.049511645e-02f, +9.598796825e-01f, -4.685079971e-02f }, + { -3.289594832e-03f, +9.028719604e-02f, +9.600239261e-01f, -4.679994715e-02f }, + { -3.279358217e-03f, +9.007943096e-02f, +9.601679226e-01f, -4.674897969e-02f }, + { -3.269139342e-03f, +8.987182124e-02f, +9.603116718e-01f, -4.669789727e-02f }, + { -3.258938197e-03f, +8.966436689e-02f, +9.604551736e-01f, -4.664669981e-02f }, + { -3.248754771e-03f, +8.945706793e-02f, +9.605984280e-01f, -4.659538723e-02f }, + { -3.238589053e-03f, +8.924992437e-02f, +9.607414349e-01f, -4.654395945e-02f }, + { -3.228441031e-03f, +8.904293624e-02f, +9.608841941e-01f, -4.649241641e-02f }, + { -3.218310696e-03f, +8.883610354e-02f, +9.610267057e-01f, -4.644075802e-02f }, + { -3.208198035e-03f, +8.862942629e-02f, +9.611689695e-01f, -4.638898421e-02f }, + { -3.198103037e-03f, +8.842290452e-02f, +9.613109853e-01f, -4.633709491e-02f }, + { -3.188025693e-03f, +8.821653824e-02f, +9.614527532e-01f, -4.628509003e-02f }, + { -3.177965990e-03f, +8.801032746e-02f, +9.615942731e-01f, -4.623296951e-02f }, + { -3.167923918e-03f, +8.780427220e-02f, +9.617355447e-01f, -4.618073326e-02f }, + { -3.157899465e-03f, +8.759837247e-02f, +9.618765682e-01f, -4.612838122e-02f }, + { -3.147892621e-03f, +8.739262830e-02f, +9.620173433e-01f, -4.607591330e-02f }, + { -3.137903374e-03f, +8.718703970e-02f, +9.621578700e-01f, -4.602332944e-02f }, + { -3.127931713e-03f, +8.698160668e-02f, +9.622981482e-01f, -4.597062955e-02f }, + { -3.117977628e-03f, +8.677632927e-02f, +9.624381778e-01f, -4.591781356e-02f }, + { -3.108041106e-03f, +8.657120747e-02f, +9.625779587e-01f, -4.586488140e-02f }, + { -3.098122137e-03f, +8.636624129e-02f, +9.627174908e-01f, -4.581183299e-02f }, + { -3.088220709e-03f, +8.616143077e-02f, +9.628567741e-01f, -4.575866826e-02f }, + { -3.078336812e-03f, +8.595677591e-02f, +9.629958084e-01f, -4.570538712e-02f }, + { -3.068470433e-03f, +8.575227672e-02f, +9.631345937e-01f, -4.565198951e-02f }, + { -3.058621563e-03f, +8.554793322e-02f, +9.632731298e-01f, -4.559847535e-02f }, + { -3.048790189e-03f, +8.534374543e-02f, +9.634114168e-01f, -4.554484457e-02f }, + { -3.038976300e-03f, +8.513971336e-02f, +9.635494545e-01f, -4.549109708e-02f }, + { -3.029179886e-03f, +8.493583703e-02f, +9.636872427e-01f, -4.543723283e-02f }, + { -3.019400934e-03f, +8.473211644e-02f, +9.638247816e-01f, -4.538325172e-02f }, + { -3.009639433e-03f, +8.452855162e-02f, +9.639620708e-01f, -4.532915369e-02f }, + { -2.999895373e-03f, +8.432514258e-02f, +9.640991104e-01f, -4.527493866e-02f }, + { -2.990168741e-03f, +8.412188933e-02f, +9.642359003e-01f, -4.522060655e-02f }, + { -2.980459527e-03f, +8.391879188e-02f, +9.643724404e-01f, -4.516615730e-02f }, + { -2.970767718e-03f, +8.371585026e-02f, +9.645087305e-01f, -4.511159083e-02f }, + { -2.961093304e-03f, +8.351306447e-02f, +9.646447707e-01f, -4.505690705e-02f }, + { -2.951436274e-03f, +8.331043452e-02f, +9.647805608e-01f, -4.500210591e-02f }, + { -2.941796615e-03f, +8.310796044e-02f, +9.649161008e-01f, -4.494718732e-02f }, + { -2.932174316e-03f, +8.290564223e-02f, +9.650513905e-01f, -4.489215120e-02f }, + { -2.922569366e-03f, +8.270347990e-02f, +9.651864298e-01f, -4.483699749e-02f }, + { -2.912981754e-03f, +8.250147348e-02f, +9.653212188e-01f, -4.478172612e-02f }, + { -2.903411467e-03f, +8.229962297e-02f, +9.654557573e-01f, -4.472633699e-02f }, + { -2.893858495e-03f, +8.209792838e-02f, +9.655900451e-01f, -4.467083005e-02f }, + { -2.884322825e-03f, +8.189638974e-02f, +9.657240824e-01f, -4.461520522e-02f }, + { -2.874804447e-03f, +8.169500704e-02f, +9.658578688e-01f, -4.455946242e-02f }, + { -2.865303349e-03f, +8.149378031e-02f, +9.659914044e-01f, -4.450360157e-02f }, + { -2.855819519e-03f, +8.129270955e-02f, +9.661246891e-01f, -4.444762262e-02f }, + { -2.846352946e-03f, +8.109179479e-02f, +9.662577228e-01f, -4.439152547e-02f }, + { -2.836903618e-03f, +8.089103602e-02f, +9.663905054e-01f, -4.433531006e-02f }, + { -2.827471523e-03f, +8.069043326e-02f, +9.665230369e-01f, -4.427897631e-02f }, + { -2.818056650e-03f, +8.048998653e-02f, +9.666553170e-01f, -4.422252415e-02f }, + { -2.808658988e-03f, +8.028969584e-02f, +9.667873459e-01f, -4.416595350e-02f }, + { -2.799278524e-03f, +8.008956119e-02f, +9.669191233e-01f, -4.410926430e-02f }, + { -2.789915247e-03f, +7.988958260e-02f, +9.670506492e-01f, -4.405245646e-02f }, + { -2.780569145e-03f, +7.968976008e-02f, +9.671819235e-01f, -4.399552991e-02f }, + { -2.771240206e-03f, +7.949009365e-02f, +9.673129462e-01f, -4.393848458e-02f }, + { -2.761928420e-03f, +7.929058330e-02f, +9.674437171e-01f, -4.388132040e-02f }, + { -2.752633774e-03f, +7.909122907e-02f, +9.675742361e-01f, -4.382403729e-02f }, + { -2.743356256e-03f, +7.889203094e-02f, +9.677045033e-01f, -4.376663518e-02f }, + { -2.734095855e-03f, +7.869298894e-02f, +9.678345184e-01f, -4.370911400e-02f }, + { -2.724852558e-03f, +7.849410308e-02f, +9.679642815e-01f, -4.365147366e-02f }, + { -2.715626355e-03f, +7.829537336e-02f, +9.680937924e-01f, -4.359371410e-02f }, + { -2.706417234e-03f, +7.809679980e-02f, +9.682230510e-01f, -4.353583525e-02f }, + { -2.697225181e-03f, +7.789838241e-02f, +9.683520574e-01f, -4.347783703e-02f }, + { -2.688050187e-03f, +7.770012120e-02f, +9.684808113e-01f, -4.341971936e-02f }, + { -2.678892238e-03f, +7.750201617e-02f, +9.686093127e-01f, -4.336148218e-02f }, + { -2.669751324e-03f, +7.730406734e-02f, +9.687375615e-01f, -4.330312541e-02f }, + { -2.660627431e-03f, +7.710627472e-02f, +9.688655578e-01f, -4.324464897e-02f }, + { -2.651520549e-03f, +7.690863832e-02f, +9.689933012e-01f, -4.318605280e-02f }, + { -2.642430666e-03f, +7.671115814e-02f, +9.691207919e-01f, -4.312733682e-02f }, + { -2.633357769e-03f, +7.651383420e-02f, +9.692480296e-01f, -4.306850096e-02f }, + { -2.624301846e-03f, +7.631666650e-02f, +9.693750144e-01f, -4.300954515e-02f }, + { -2.615262886e-03f, +7.611965506e-02f, +9.695017462e-01f, -4.295046931e-02f }, + { -2.606240877e-03f, +7.592279989e-02f, +9.696282248e-01f, -4.289127336e-02f }, + { -2.597235807e-03f, +7.572610098e-02f, +9.697544501e-01f, -4.283195724e-02f }, + { -2.588247664e-03f, +7.552955836e-02f, +9.698804222e-01f, -4.277252088e-02f }, + { -2.579276435e-03f, +7.533317203e-02f, +9.700061410e-01f, -4.271296420e-02f }, + { -2.570322110e-03f, +7.513694200e-02f, +9.701316062e-01f, -4.265328712e-02f }, + { -2.561384675e-03f, +7.494086827e-02f, +9.702568180e-01f, -4.259348958e-02f }, + { -2.552464119e-03f, +7.474495086e-02f, +9.703817761e-01f, -4.253357150e-02f }, + { -2.543560430e-03f, +7.454918978e-02f, +9.705064805e-01f, -4.247353281e-02f }, + { -2.534673595e-03f, +7.435358503e-02f, +9.706309312e-01f, -4.241337343e-02f }, + { -2.525803603e-03f, +7.415813662e-02f, +9.707551280e-01f, -4.235309331e-02f }, + { -2.516950442e-03f, +7.396284455e-02f, +9.708790709e-01f, -4.229269235e-02f }, + { -2.508114099e-03f, +7.376770885e-02f, +9.710027598e-01f, -4.223217049e-02f }, + { -2.499294563e-03f, +7.357272950e-02f, +9.711261947e-01f, -4.217152766e-02f }, + { -2.490491821e-03f, +7.337790653e-02f, +9.712493753e-01f, -4.211076378e-02f }, + { -2.481705861e-03f, +7.318323994e-02f, +9.713723017e-01f, -4.204987879e-02f }, + { -2.472936671e-03f, +7.298872973e-02f, +9.714949738e-01f, -4.198887261e-02f }, + { -2.464184239e-03f, +7.279437592e-02f, +9.716173916e-01f, -4.192774516e-02f }, + { -2.455448552e-03f, +7.260017851e-02f, +9.717395548e-01f, -4.186649638e-02f }, + { -2.446729599e-03f, +7.240613750e-02f, +9.718614635e-01f, -4.180512620e-02f }, + { -2.438027368e-03f, +7.221225291e-02f, +9.719831176e-01f, -4.174363453e-02f }, + { -2.429341845e-03f, +7.201852474e-02f, +9.721045170e-01f, -4.168202131e-02f }, + { -2.420673020e-03f, +7.182495300e-02f, +9.722256616e-01f, -4.162028648e-02f }, + { -2.412020878e-03f, +7.163153769e-02f, +9.723465513e-01f, -4.155842994e-02f }, + { -2.403385410e-03f, +7.143827882e-02f, +9.724671862e-01f, -4.149645164e-02f }, + { -2.394766601e-03f, +7.124517640e-02f, +9.725875660e-01f, -4.143435151e-02f }, + { -2.386164441e-03f, +7.105223044e-02f, +9.727076907e-01f, -4.137212946e-02f }, + { -2.377578915e-03f, +7.085944093e-02f, +9.728275603e-01f, -4.130978543e-02f }, + { -2.369010014e-03f, +7.066680788e-02f, +9.729471746e-01f, -4.124731934e-02f }, + { -2.360457723e-03f, +7.047433131e-02f, +9.730665337e-01f, -4.118473113e-02f }, + { -2.351922030e-03f, +7.028201121e-02f, +9.731856373e-01f, -4.112202073e-02f }, + { -2.343402924e-03f, +7.008984759e-02f, +9.733044855e-01f, -4.105918805e-02f }, + { -2.334900392e-03f, +6.989784046e-02f, +9.734230782e-01f, -4.099623304e-02f }, + { -2.326414422e-03f, +6.970598983e-02f, +9.735414153e-01f, -4.093315561e-02f }, + { -2.317945001e-03f, +6.951429569e-02f, +9.736594966e-01f, -4.086995570e-02f }, + { -2.309492116e-03f, +6.932275805e-02f, +9.737773222e-01f, -4.080663324e-02f }, + { -2.301055756e-03f, +6.913137692e-02f, +9.738948920e-01f, -4.074318815e-02f }, + { -2.292635908e-03f, +6.894015231e-02f, +9.740122059e-01f, -4.067962036e-02f }, + { -2.284232560e-03f, +6.874908421e-02f, +9.741292638e-01f, -4.061592981e-02f }, + { -2.275845698e-03f, +6.855817263e-02f, +9.742460656e-01f, -4.055211641e-02f }, + { -2.267475312e-03f, +6.836741758e-02f, +9.743626113e-01f, -4.048818011e-02f }, + { -2.259121387e-03f, +6.817681906e-02f, +9.744789009e-01f, -4.042412082e-02f }, + { -2.250783913e-03f, +6.798637707e-02f, +9.745949341e-01f, -4.035993848e-02f }, + { -2.242462875e-03f, +6.779609163e-02f, +9.747107110e-01f, -4.029563302e-02f }, + { -2.234158263e-03f, +6.760596272e-02f, +9.748262314e-01f, -4.023120436e-02f }, + { -2.225870062e-03f, +6.741599037e-02f, +9.749414954e-01f, -4.016665244e-02f }, + { -2.217598262e-03f, +6.722617456e-02f, +9.750565028e-01f, -4.010197718e-02f }, + { -2.209342848e-03f, +6.703651531e-02f, +9.751712536e-01f, -4.003717851e-02f }, + { -2.201103809e-03f, +6.684701262e-02f, +9.752857476e-01f, -3.997225637e-02f }, + { -2.192881133e-03f, +6.665766648e-02f, +9.753999849e-01f, -3.990721068e-02f }, + { -2.184674805e-03f, +6.646847692e-02f, +9.755139653e-01f, -3.984204137e-02f }, + { -2.176484815e-03f, +6.627944392e-02f, +9.756276888e-01f, -3.977674836e-02f }, + { -2.168311149e-03f, +6.609056749e-02f, +9.757411552e-01f, -3.971133160e-02f }, + { -2.160153795e-03f, +6.590184763e-02f, +9.758543646e-01f, -3.964579101e-02f }, + { -2.152012740e-03f, +6.571328435e-02f, +9.759673169e-01f, -3.958012651e-02f }, + { -2.143887971e-03f, +6.552487765e-02f, +9.760800119e-01f, -3.951433805e-02f }, + { -2.135779477e-03f, +6.533662753e-02f, +9.761924497e-01f, -3.944842554e-02f }, + { -2.127687243e-03f, +6.514853400e-02f, +9.763046301e-01f, -3.938238892e-02f }, + { -2.119611258e-03f, +6.496059705e-02f, +9.764165530e-01f, -3.931622812e-02f }, + { -2.111551509e-03f, +6.477281670e-02f, +9.765282185e-01f, -3.924994306e-02f }, + { -2.103507983e-03f, +6.458519293e-02f, +9.766396264e-01f, -3.918353368e-02f }, + { -2.095480667e-03f, +6.439772576e-02f, +9.767507766e-01f, -3.911699991e-02f }, + { -2.087469549e-03f, +6.421041518e-02f, +9.768616692e-01f, -3.905034167e-02f }, + { -2.079474617e-03f, +6.402326120e-02f, +9.769723040e-01f, -3.898355890e-02f }, + { -2.071495856e-03f, +6.383626381e-02f, +9.770826809e-01f, -3.891665153e-02f }, + { -2.063533255e-03f, +6.364942303e-02f, +9.771927998e-01f, -3.884961949e-02f }, + { -2.055586801e-03f, +6.346273885e-02f, +9.773026608e-01f, -3.878246270e-02f }, + { -2.047656480e-03f, +6.327621127e-02f, +9.774122638e-01f, -3.871518110e-02f }, + { -2.039742281e-03f, +6.308984030e-02f, +9.775216086e-01f, -3.864777462e-02f }, + { -2.031844191e-03f, +6.290362593e-02f, +9.776306952e-01f, -3.858024318e-02f }, + { -2.023962196e-03f, +6.271756817e-02f, +9.777395235e-01f, -3.851258673e-02f }, + { -2.016096283e-03f, +6.253166701e-02f, +9.778480935e-01f, -3.844480518e-02f }, + { -2.008246441e-03f, +6.234592246e-02f, +9.779564051e-01f, -3.837689847e-02f }, + { -2.000412656e-03f, +6.216033452e-02f, +9.780644583e-01f, -3.830886653e-02f }, + { -1.992594915e-03f, +6.197490319e-02f, +9.781722528e-01f, -3.824070929e-02f }, + { -1.984793206e-03f, +6.178962847e-02f, +9.782797888e-01f, -3.817242668e-02f }, + { -1.977007515e-03f, +6.160451036e-02f, +9.783870661e-01f, -3.810401864e-02f }, + { -1.969237830e-03f, +6.141954886e-02f, +9.784940847e-01f, -3.803548508e-02f }, + { -1.961484138e-03f, +6.123474396e-02f, +9.786008444e-01f, -3.796682595e-02f }, + { -1.953746425e-03f, +6.105009568e-02f, +9.787073453e-01f, -3.789804118e-02f }, + { -1.946024680e-03f, +6.086560401e-02f, +9.788135872e-01f, -3.782913069e-02f }, + { -1.938318888e-03f, +6.068126894e-02f, +9.789195701e-01f, -3.776009441e-02f }, + { -1.930629038e-03f, +6.049709048e-02f, +9.790252939e-01f, -3.769093228e-02f }, + { -1.922955116e-03f, +6.031306864e-02f, +9.791307585e-01f, -3.762164423e-02f }, + { -1.915297108e-03f, +6.012920340e-02f, +9.792359640e-01f, -3.755223018e-02f }, + { -1.907655004e-03f, +5.994549476e-02f, +9.793409101e-01f, -3.748269008e-02f }, + { -1.900028788e-03f, +5.976194274e-02f, +9.794455969e-01f, -3.741302385e-02f }, + { -1.892418449e-03f, +5.957854731e-02f, +9.795500243e-01f, -3.734323142e-02f }, + { -1.884823973e-03f, +5.939530849e-02f, +9.796541922e-01f, -3.727331272e-02f }, + { -1.877245347e-03f, +5.921222628e-02f, +9.797581006e-01f, -3.720326769e-02f }, + { -1.869682558e-03f, +5.902930066e-02f, +9.798617493e-01f, -3.713309626e-02f }, + { -1.862135594e-03f, +5.884653165e-02f, +9.799651384e-01f, -3.706279835e-02f }, + { -1.854604440e-03f, +5.866391923e-02f, +9.800682677e-01f, -3.699237391e-02f }, + { -1.847089085e-03f, +5.848146341e-02f, +9.801711372e-01f, -3.692182285e-02f }, + { -1.839589515e-03f, +5.829916418e-02f, +9.802737469e-01f, -3.685114512e-02f }, + { -1.832105717e-03f, +5.811702155e-02f, +9.803760966e-01f, -3.678034064e-02f }, + { -1.824637677e-03f, +5.793503550e-02f, +9.804781863e-01f, -3.670940934e-02f }, + { -1.817185384e-03f, +5.775320605e-02f, +9.805800159e-01f, -3.663835117e-02f }, + { -1.809748823e-03f, +5.757153318e-02f, +9.806815854e-01f, -3.656716604e-02f }, + { -1.802327981e-03f, +5.739001690e-02f, +9.807828947e-01f, -3.649585390e-02f }, + { -1.794922846e-03f, +5.720865720e-02f, +9.808839437e-01f, -3.642441467e-02f }, + { -1.787533404e-03f, +5.702745407e-02f, +9.809847324e-01f, -3.635284829e-02f }, + { -1.780159642e-03f, +5.684640752e-02f, +9.810852607e-01f, -3.628115468e-02f }, + { -1.772801548e-03f, +5.666551755e-02f, +9.811855286e-01f, -3.620933378e-02f }, + { -1.765459107e-03f, +5.648478415e-02f, +9.812855360e-01f, -3.613738552e-02f }, + { -1.758132306e-03f, +5.630420731e-02f, +9.813852827e-01f, -3.606530984e-02f }, + { -1.750821133e-03f, +5.612378704e-02f, +9.814847688e-01f, -3.599310667e-02f }, + { -1.743525575e-03f, +5.594352333e-02f, +9.815839943e-01f, -3.592077593e-02f }, + { -1.736245617e-03f, +5.576341617e-02f, +9.816829589e-01f, -3.584831757e-02f }, + { -1.728981247e-03f, +5.558346557e-02f, +9.817816627e-01f, -3.577573150e-02f }, + { -1.721732452e-03f, +5.540367152e-02f, +9.818801056e-01f, -3.570301768e-02f }, + { -1.714499218e-03f, +5.522403402e-02f, +9.819782876e-01f, -3.563017602e-02f }, + { -1.707281532e-03f, +5.504455306e-02f, +9.820762086e-01f, -3.555720646e-02f }, + { -1.700079381e-03f, +5.486522863e-02f, +9.821738684e-01f, -3.548410894e-02f }, + { -1.692892751e-03f, +5.468606075e-02f, +9.822712671e-01f, -3.541088338e-02f }, + { -1.685721630e-03f, +5.450704939e-02f, +9.823684047e-01f, -3.533752973e-02f }, + { -1.678566004e-03f, +5.432819456e-02f, +9.824652809e-01f, -3.526404790e-02f }, + { -1.671425859e-03f, +5.414949625e-02f, +9.825618958e-01f, -3.519043784e-02f }, + { -1.664301183e-03f, +5.397095446e-02f, +9.826582494e-01f, -3.511669948e-02f }, + { -1.657191962e-03f, +5.379256918e-02f, +9.827543414e-01f, -3.504283275e-02f }, + { -1.650098183e-03f, +5.361434040e-02f, +9.828501720e-01f, -3.496883758e-02f }, + { -1.643019832e-03f, +5.343626813e-02f, +9.829457410e-01f, -3.489471391e-02f }, + { -1.635956896e-03f, +5.325835236e-02f, +9.830410484e-01f, -3.482046167e-02f }, + { -1.628909362e-03f, +5.308059308e-02f, +9.831360941e-01f, -3.474608080e-02f }, + { -1.621877216e-03f, +5.290299029e-02f, +9.832308780e-01f, -3.467157122e-02f }, + { -1.614860445e-03f, +5.272554398e-02f, +9.833254001e-01f, -3.459693287e-02f }, + { -1.607859036e-03f, +5.254825415e-02f, +9.834196603e-01f, -3.452216568e-02f }, + { -1.600872975e-03f, +5.237112079e-02f, +9.835136587e-01f, -3.444726959e-02f }, + { -1.593902249e-03f, +5.219414389e-02f, +9.836073950e-01f, -3.437224453e-02f }, + { -1.586946844e-03f, +5.201732345e-02f, +9.837008692e-01f, -3.429709044e-02f }, + { -1.580006747e-03f, +5.184065947e-02f, +9.837940814e-01f, -3.422180724e-02f }, + { -1.573081945e-03f, +5.166415193e-02f, +9.838870314e-01f, -3.414639488e-02f }, + { -1.566172424e-03f, +5.148780084e-02f, +9.839797191e-01f, -3.407085327e-02f }, + { -1.559278170e-03f, +5.131160618e-02f, +9.840721446e-01f, -3.399518237e-02f }, + { -1.552399171e-03f, +5.113556795e-02f, +9.841643077e-01f, -3.391938210e-02f }, + { -1.545535412e-03f, +5.095968615e-02f, +9.842562085e-01f, -3.384345240e-02f }, + { -1.538686881e-03f, +5.078396076e-02f, +9.843478467e-01f, -3.376739320e-02f }, + { -1.531853564e-03f, +5.060839177e-02f, +9.844392225e-01f, -3.369120443e-02f }, + { -1.525035446e-03f, +5.043297919e-02f, +9.845303356e-01f, -3.361488603e-02f }, + { -1.518232516e-03f, +5.025772301e-02f, +9.846211862e-01f, -3.353843793e-02f }, + { -1.511444759e-03f, +5.008262322e-02f, +9.847117740e-01f, -3.346186007e-02f }, + { -1.504672161e-03f, +4.990767980e-02f, +9.848020991e-01f, -3.338515239e-02f }, + { -1.497914710e-03f, +4.973289276e-02f, +9.848921614e-01f, -3.330831480e-02f }, + { -1.491172391e-03f, +4.955826209e-02f, +9.849819608e-01f, -3.323134726e-02f }, + { -1.484445192e-03f, +4.938378778e-02f, +9.850714973e-01f, -3.315424969e-02f }, + { -1.477733098e-03f, +4.920946982e-02f, +9.851607708e-01f, -3.307702203e-02f }, + { -1.471036096e-03f, +4.903530820e-02f, +9.852497812e-01f, -3.299966421e-02f }, + { -1.464354173e-03f, +4.886130292e-02f, +9.853385286e-01f, -3.292217617e-02f }, + { -1.457687314e-03f, +4.868745396e-02f, +9.854270129e-01f, -3.284455785e-02f }, + { -1.451035507e-03f, +4.851376133e-02f, +9.855152339e-01f, -3.276680917e-02f }, + { -1.444398738e-03f, +4.834022501e-02f, +9.856031917e-01f, -3.268893007e-02f }, + { -1.437776992e-03f, +4.816684499e-02f, +9.856908861e-01f, -3.261092049e-02f }, + { -1.431170257e-03f, +4.799362127e-02f, +9.857783172e-01f, -3.253278036e-02f }, + { -1.424578519e-03f, +4.782055384e-02f, +9.858654848e-01f, -3.245450962e-02f }, + { -1.418001764e-03f, +4.764764268e-02f, +9.859523890e-01f, -3.237610820e-02f }, + { -1.411439979e-03f, +4.747488779e-02f, +9.860390297e-01f, -3.229757604e-02f }, + { -1.404893149e-03f, +4.730228917e-02f, +9.861254067e-01f, -3.221891307e-02f }, + { -1.398361262e-03f, +4.712984679e-02f, +9.862115201e-01f, -3.214011922e-02f }, + { -1.391844303e-03f, +4.695756066e-02f, +9.862973698e-01f, -3.206119444e-02f }, + { -1.385342260e-03f, +4.678543077e-02f, +9.863829557e-01f, -3.198213866e-02f }, + { -1.378855117e-03f, +4.661345709e-02f, +9.864682779e-01f, -3.190295181e-02f }, + { -1.372382862e-03f, +4.644163964e-02f, +9.865533361e-01f, -3.182363382e-02f }, + { -1.365925481e-03f, +4.626997838e-02f, +9.866381305e-01f, -3.174418465e-02f }, + { -1.359482960e-03f, +4.609847333e-02f, +9.867226608e-01f, -3.166460421e-02f }, + { -1.353055286e-03f, +4.592712446e-02f, +9.868069272e-01f, -3.158489244e-02f }, + { -1.346642444e-03f, +4.575593177e-02f, +9.868909295e-01f, -3.150504929e-02f }, + { -1.340244422e-03f, +4.558489524e-02f, +9.869746676e-01f, -3.142507468e-02f }, + { -1.333861204e-03f, +4.541401487e-02f, +9.870581415e-01f, -3.134496856e-02f }, + { -1.327492778e-03f, +4.524329065e-02f, +9.871413513e-01f, -3.126473085e-02f }, + { -1.321139130e-03f, +4.507272256e-02f, +9.872242967e-01f, -3.118436150e-02f }, + { -1.314800245e-03f, +4.490231060e-02f, +9.873069778e-01f, -3.110386044e-02f }, + { -1.308476111e-03f, +4.473205475e-02f, +9.873893944e-01f, -3.102322761e-02f }, + { -1.302166714e-03f, +4.456195501e-02f, +9.874715467e-01f, -3.094246293e-02f }, + { -1.295872038e-03f, +4.439201136e-02f, +9.875534344e-01f, -3.086156636e-02f }, + { -1.289592072e-03f, +4.422222380e-02f, +9.876350576e-01f, -3.078053782e-02f }, + { -1.283326801e-03f, +4.405259231e-02f, +9.877164161e-01f, -3.069937725e-02f }, + { -1.277076211e-03f, +4.388311688e-02f, +9.877975101e-01f, -3.061808459e-02f }, + { -1.270840289e-03f, +4.371379750e-02f, +9.878783393e-01f, -3.053665977e-02f }, + { -1.264619020e-03f, +4.354463416e-02f, +9.879589037e-01f, -3.045510273e-02f }, + { -1.258412391e-03f, +4.337562684e-02f, +9.880392034e-01f, -3.037341341e-02f }, + { -1.252220388e-03f, +4.320677555e-02f, +9.881192381e-01f, -3.029159174e-02f }, + { -1.246042996e-03f, +4.303808025e-02f, +9.881990080e-01f, -3.020963766e-02f }, + { -1.239880203e-03f, +4.286954095e-02f, +9.882785129e-01f, -3.012755111e-02f }, + { -1.233731995e-03f, +4.270115763e-02f, +9.883577528e-01f, -3.004533202e-02f }, + { -1.227598357e-03f, +4.253293028e-02f, +9.884367276e-01f, -2.996298034e-02f }, + { -1.221479275e-03f, +4.236485889e-02f, +9.885154374e-01f, -2.988049599e-02f }, + { -1.215374737e-03f, +4.219694344e-02f, +9.885938819e-01f, -2.979787891e-02f }, + { -1.209284727e-03f, +4.202918393e-02f, +9.886720613e-01f, -2.971512904e-02f }, + { -1.203209232e-03f, +4.186158033e-02f, +9.887499753e-01f, -2.963224632e-02f }, + { -1.197148238e-03f, +4.169413264e-02f, +9.888276241e-01f, -2.954923069e-02f }, + { -1.191101731e-03f, +4.152684085e-02f, +9.889050075e-01f, -2.946608208e-02f }, + { -1.185069698e-03f, +4.135970494e-02f, +9.889821255e-01f, -2.938280043e-02f }, + { -1.179052123e-03f, +4.119272490e-02f, +9.890589780e-01f, -2.929938568e-02f }, + { -1.173048994e-03f, +4.102590072e-02f, +9.891355651e-01f, -2.921583776e-02f }, + { -1.167060297e-03f, +4.085923238e-02f, +9.892118865e-01f, -2.913215661e-02f }, + { -1.161086016e-03f, +4.069271988e-02f, +9.892879424e-01f, -2.904834218e-02f }, + { -1.155126140e-03f, +4.052636319e-02f, +9.893637326e-01f, -2.896439439e-02f }, + { -1.149180652e-03f, +4.036016230e-02f, +9.894392571e-01f, -2.888031318e-02f }, + { -1.143249541e-03f, +4.019411721e-02f, +9.895145159e-01f, -2.879609850e-02f }, + { -1.137332791e-03f, +4.002822789e-02f, +9.895895088e-01f, -2.871175028e-02f }, + { -1.131430388e-03f, +3.986249434e-02f, +9.896642360e-01f, -2.862726845e-02f }, + { -1.125542319e-03f, +3.969691653e-02f, +9.897386972e-01f, -2.854265296e-02f }, + { -1.119668570e-03f, +3.953149447e-02f, +9.898128925e-01f, -2.845790375e-02f }, + { -1.113809126e-03f, +3.936622812e-02f, +9.898868218e-01f, -2.837302075e-02f }, + { -1.107963974e-03f, +3.920111748e-02f, +9.899604850e-01f, -2.828800389e-02f }, + { -1.102133100e-03f, +3.903616254e-02f, +9.900338822e-01f, -2.820285313e-02f }, + { -1.096316489e-03f, +3.887136328e-02f, +9.901070133e-01f, -2.811756839e-02f }, + { -1.090514127e-03f, +3.870671968e-02f, +9.901798782e-01f, -2.803214962e-02f }, + { -1.084726001e-03f, +3.854223173e-02f, +9.902524768e-01f, -2.794659675e-02f }, + { -1.078952096e-03f, +3.837789942e-02f, +9.903248092e-01f, -2.786090972e-02f }, + { -1.073192399e-03f, +3.821372273e-02f, +9.903968753e-01f, -2.777508847e-02f }, + { -1.067446895e-03f, +3.804970164e-02f, +9.904686751e-01f, -2.768913294e-02f }, + { -1.061715570e-03f, +3.788583615e-02f, +9.905402084e-01f, -2.760304307e-02f }, + { -1.055998411e-03f, +3.772212623e-02f, +9.906114753e-01f, -2.751681879e-02f }, + { -1.050295402e-03f, +3.755857188e-02f, +9.906824756e-01f, -2.743046005e-02f }, + { -1.044606531e-03f, +3.739517307e-02f, +9.907532095e-01f, -2.734396678e-02f }, + { -1.038931782e-03f, +3.723192979e-02f, +9.908236768e-01f, -2.725733893e-02f }, + { -1.033271142e-03f, +3.706884203e-02f, +9.908938774e-01f, -2.717057642e-02f }, + { -1.027624597e-03f, +3.690590976e-02f, +9.909638114e-01f, -2.708367921e-02f }, + { -1.021992133e-03f, +3.674313298e-02f, +9.910334786e-01f, -2.699664722e-02f }, + { -1.016373735e-03f, +3.658051167e-02f, +9.911028791e-01f, -2.690948040e-02f }, + { -1.010769389e-03f, +3.641804581e-02f, +9.911720128e-01f, -2.682217869e-02f }, + { -1.005179082e-03f, +3.625573538e-02f, +9.912408796e-01f, -2.673474203e-02f }, + { -9.996027983e-04f, +3.609358038e-02f, +9.913094795e-01f, -2.664717035e-02f }, + { -9.940405249e-04f, +3.593158078e-02f, +9.913778125e-01f, -2.655946360e-02f }, + { -9.884922474e-04f, +3.576973656e-02f, +9.914458785e-01f, -2.647162171e-02f }, + { -9.829579515e-04f, +3.560804772e-02f, +9.915136775e-01f, -2.638364463e-02f }, + { -9.774376231e-04f, +3.544651423e-02f, +9.915812094e-01f, -2.629553230e-02f }, + { -9.719312480e-04f, +3.528513608e-02f, +9.916484743e-01f, -2.620728464e-02f }, + { -9.664388120e-04f, +3.512391325e-02f, +9.917154719e-01f, -2.611890161e-02f }, + { -9.609603011e-04f, +3.496284573e-02f, +9.917822024e-01f, -2.603038315e-02f }, + { -9.554957009e-04f, +3.480193349e-02f, +9.918486656e-01f, -2.594172918e-02f }, + { -9.500449974e-04f, +3.464117652e-02f, +9.919148616e-01f, -2.585293966e-02f }, + { -9.446081762e-04f, +3.448057480e-02f, +9.919807902e-01f, -2.576401452e-02f }, + { -9.391852233e-04f, +3.432012832e-02f, +9.920464515e-01f, -2.567495371e-02f }, + { -9.337761243e-04f, +3.415983706e-02f, +9.921118453e-01f, -2.558575716e-02f }, + { -9.283808652e-04f, +3.399970099e-02f, +9.921769718e-01f, -2.549642481e-02f }, + { -9.229994316e-04f, +3.383972011e-02f, +9.922418307e-01f, -2.540695661e-02f }, + { -9.176318093e-04f, +3.367989440e-02f, +9.923064221e-01f, -2.531735249e-02f }, + { -9.122779842e-04f, +3.352022383e-02f, +9.923707459e-01f, -2.522761239e-02f }, + { -9.069379419e-04f, +3.336070839e-02f, +9.924348021e-01f, -2.513773626e-02f }, + { -9.016116683e-04f, +3.320134807e-02f, +9.924985907e-01f, -2.504772404e-02f }, + { -8.962991490e-04f, +3.304214283e-02f, +9.925621116e-01f, -2.495757566e-02f }, + { -8.910003699e-04f, +3.288309267e-02f, +9.926253647e-01f, -2.486729107e-02f }, + { -8.857153167e-04f, +3.272419757e-02f, +9.926883501e-01f, -2.477687020e-02f }, + { -8.804439750e-04f, +3.256545750e-02f, +9.927510676e-01f, -2.468631300e-02f }, + { -8.751863308e-04f, +3.240687246e-02f, +9.928135173e-01f, -2.459561942e-02f }, + { -8.699423695e-04f, +3.224844242e-02f, +9.928756991e-01f, -2.450478938e-02f }, + { -8.647120771e-04f, +3.209016735e-02f, +9.929376130e-01f, -2.441382283e-02f }, + { -8.594954392e-04f, +3.193204725e-02f, +9.929992589e-01f, -2.432271972e-02f }, + { -8.542924415e-04f, +3.177408210e-02f, +9.930606368e-01f, -2.423147998e-02f }, + { -8.491030697e-04f, +3.161627187e-02f, +9.931217466e-01f, -2.414010355e-02f }, + { -8.439273095e-04f, +3.145861654e-02f, +9.931825884e-01f, -2.404859038e-02f }, + { -8.387651466e-04f, +3.130111610e-02f, +9.932431620e-01f, -2.395694040e-02f }, + { -8.336165668e-04f, +3.114377053e-02f, +9.933034675e-01f, -2.386515357e-02f }, + { -8.284815556e-04f, +3.098657981e-02f, +9.933635047e-01f, -2.377322981e-02f }, + { -8.233600987e-04f, +3.082954391e-02f, +9.934232738e-01f, -2.368116908e-02f }, + { -8.182521819e-04f, +3.067266283e-02f, +9.934827745e-01f, -2.358897131e-02f }, + { -8.131577908e-04f, +3.051593653e-02f, +9.935420069e-01f, -2.349663644e-02f }, + { -8.080769110e-04f, +3.035936500e-02f, +9.936009710e-01f, -2.340416442e-02f }, + { -8.030095283e-04f, +3.020294821e-02f, +9.936596666e-01f, -2.331155519e-02f }, + { -7.979556282e-04f, +3.004668616e-02f, +9.937180939e-01f, -2.321880869e-02f }, + { -7.929151965e-04f, +2.989057881e-02f, +9.937762527e-01f, -2.312592486e-02f }, + { -7.878882187e-04f, +2.973462615e-02f, +9.938341429e-01f, -2.303290364e-02f }, + { -7.828746805e-04f, +2.957882816e-02f, +9.938917647e-01f, -2.293974499e-02f }, + { -7.778745675e-04f, +2.942318481e-02f, +9.939491178e-01f, -2.284644883e-02f }, + { -7.728878654e-04f, +2.926769610e-02f, +9.940062023e-01f, -2.275301511e-02f }, + { -7.679145598e-04f, +2.911236198e-02f, +9.940630182e-01f, -2.265944377e-02f }, + { -7.629546363e-04f, +2.895718245e-02f, +9.941195654e-01f, -2.256573476e-02f }, + { -7.580080805e-04f, +2.880215748e-02f, +9.941758439e-01f, -2.247188802e-02f }, + { -7.530748780e-04f, +2.864728706e-02f, +9.942318536e-01f, -2.237790348e-02f }, + { -7.481550144e-04f, +2.849257115e-02f, +9.942875945e-01f, -2.228378110e-02f }, + { -7.432484754e-04f, +2.833800975e-02f, +9.943430666e-01f, -2.218952082e-02f }, + { -7.383552465e-04f, +2.818360282e-02f, +9.943982699e-01f, -2.209512257e-02f }, + { -7.334753133e-04f, +2.802935035e-02f, +9.944532042e-01f, -2.200058631e-02f }, + { -7.286086614e-04f, +2.787525232e-02f, +9.945078696e-01f, -2.190591197e-02f }, + { -7.237552763e-04f, +2.772130869e-02f, +9.945622660e-01f, -2.181109950e-02f }, + { -7.189151437e-04f, +2.756751946e-02f, +9.946163934e-01f, -2.171614883e-02f }, + { -7.140882492e-04f, +2.741388460e-02f, +9.946702518e-01f, -2.162105992e-02f }, + { -7.092745782e-04f, +2.726040409e-02f, +9.947238411e-01f, -2.152583271e-02f }, + { -7.044741164e-04f, +2.710707790e-02f, +9.947771613e-01f, -2.143046713e-02f }, + { -6.996868493e-04f, +2.695390602e-02f, +9.948302124e-01f, -2.133496314e-02f }, + { -6.949127625e-04f, +2.680088842e-02f, +9.948829943e-01f, -2.123932068e-02f }, + { -6.901518415e-04f, +2.664802507e-02f, +9.949355069e-01f, -2.114353968e-02f }, + { -6.854040719e-04f, +2.649531596e-02f, +9.949877504e-01f, -2.104762010e-02f }, + { -6.806694392e-04f, +2.634276107e-02f, +9.950397245e-01f, -2.095156187e-02f }, + { -6.759479289e-04f, +2.619036036e-02f, +9.950914294e-01f, -2.085536494e-02f }, + { -6.712395266e-04f, +2.603811383e-02f, +9.951428649e-01f, -2.075902926e-02f }, + { -6.665442179e-04f, +2.588602143e-02f, +9.951940310e-01f, -2.066255477e-02f }, + { -6.618619881e-04f, +2.573408316e-02f, +9.952449278e-01f, -2.056594140e-02f }, + { -6.571928229e-04f, +2.558229899e-02f, +9.952955551e-01f, -2.046918912e-02f }, + { -6.525367078e-04f, +2.543066889e-02f, +9.953459129e-01f, -2.037229785e-02f }, + { -6.478936283e-04f, +2.527919285e-02f, +9.953960012e-01f, -2.027526754e-02f }, + { -6.432635698e-04f, +2.512787083e-02f, +9.954458200e-01f, -2.017809815e-02f }, + { -6.386465180e-04f, +2.497670282e-02f, +9.954953692e-01f, -2.008078960e-02f }, + { -6.340424582e-04f, +2.482568879e-02f, +9.955446489e-01f, -1.998334185e-02f }, + { -6.294513760e-04f, +2.467482872e-02f, +9.955936589e-01f, -1.988575485e-02f }, + { -6.248732570e-04f, +2.452412258e-02f, +9.956423992e-01f, -1.978802853e-02f }, + { -6.203080865e-04f, +2.437357035e-02f, +9.956908698e-01f, -1.969016283e-02f }, + { -6.157558500e-04f, +2.422317200e-02f, +9.957390708e-01f, -1.959215772e-02f }, + { -6.112165332e-04f, +2.407292752e-02f, +9.957870019e-01f, -1.949401312e-02f }, + { -6.066901213e-04f, +2.392283688e-02f, +9.958346633e-01f, -1.939572898e-02f }, + { -6.021765999e-04f, +2.377290004e-02f, +9.958820549e-01f, -1.929730525e-02f }, + { -5.976759545e-04f, +2.362311700e-02f, +9.959291766e-01f, -1.919874188e-02f }, + { -5.931881705e-04f, +2.347348772e-02f, +9.959760285e-01f, -1.910003880e-02f }, + { -5.887132334e-04f, +2.332401218e-02f, +9.960226105e-01f, -1.900119597e-02f }, + { -5.842511287e-04f, +2.317469035e-02f, +9.960689225e-01f, -1.890221333e-02f }, + { -5.798018418e-04f, +2.302552221e-02f, +9.961149645e-01f, -1.880309082e-02f }, + { -5.753653581e-04f, +2.287650774e-02f, +9.961607366e-01f, -1.870382839e-02f }, + { -5.709416631e-04f, +2.272764690e-02f, +9.962062387e-01f, -1.860442598e-02f }, + { -5.665307423e-04f, +2.257893968e-02f, +9.962514707e-01f, -1.850488354e-02f }, + { -5.621325811e-04f, +2.243038605e-02f, +9.962964326e-01f, -1.840520102e-02f }, + { -5.577471650e-04f, +2.228198598e-02f, +9.963411244e-01f, -1.830537836e-02f }, + { -5.533744792e-04f, +2.213373945e-02f, +9.963855461e-01f, -1.820541550e-02f }, + { -5.490145094e-04f, +2.198564643e-02f, +9.964296976e-01f, -1.810531240e-02f }, + { -5.446672410e-04f, +2.183770690e-02f, +9.964735789e-01f, -1.800506899e-02f }, + { -5.403326592e-04f, +2.168992083e-02f, +9.965171900e-01f, -1.790468523e-02f }, + { -5.360107497e-04f, +2.154228819e-02f, +9.965605309e-01f, -1.780416106e-02f }, + { -5.317014977e-04f, +2.139480896e-02f, +9.966036014e-01f, -1.770349642e-02f }, + { -5.274048887e-04f, +2.124748312e-02f, +9.966464017e-01f, -1.760269126e-02f }, + { -5.231209082e-04f, +2.110031063e-02f, +9.966889317e-01f, -1.750174553e-02f }, + { -5.188495414e-04f, +2.095329147e-02f, +9.967311913e-01f, -1.740065918e-02f }, + { -5.145907739e-04f, +2.080642562e-02f, +9.967731805e-01f, -1.729943214e-02f }, + { -5.103445911e-04f, +2.065971304e-02f, +9.968148993e-01f, -1.719806437e-02f }, + { -5.061109782e-04f, +2.051315372e-02f, +9.968563476e-01f, -1.709655581e-02f }, + { -5.018899208e-04f, +2.036674762e-02f, +9.968975255e-01f, -1.699490642e-02f }, + { -4.976814042e-04f, +2.022049471e-02f, +9.969384329e-01f, -1.689311613e-02f }, + { -4.934854139e-04f, +2.007439498e-02f, +9.969790698e-01f, -1.679118489e-02f }, + { -4.893019351e-04f, +1.992844839e-02f, +9.970194362e-01f, -1.668911265e-02f }, + { -4.851309533e-04f, +1.978265492e-02f, +9.970595319e-01f, -1.658689935e-02f }, + { -4.809724538e-04f, +1.963701453e-02f, +9.970993571e-01f, -1.648454495e-02f }, + { -4.768264221e-04f, +1.949152721e-02f, +9.971389117e-01f, -1.638204939e-02f }, + { -4.726928435e-04f, +1.934619292e-02f, +9.971781956e-01f, -1.627941262e-02f }, + { -4.685717034e-04f, +1.920101164e-02f, +9.972172089e-01f, -1.617663458e-02f }, + { -4.644629872e-04f, +1.905598334e-02f, +9.972559515e-01f, -1.607371522e-02f }, + { -4.603666801e-04f, +1.891110799e-02f, +9.972944233e-01f, -1.597065449e-02f }, + { -4.562827677e-04f, +1.876638556e-02f, +9.973326244e-01f, -1.586745234e-02f }, + { -4.522112352e-04f, +1.862181603e-02f, +9.973705548e-01f, -1.576410871e-02f }, + { -4.481520680e-04f, +1.847739937e-02f, +9.974082143e-01f, -1.566062355e-02f }, + { -4.441052515e-04f, +1.833313554e-02f, +9.974456031e-01f, -1.555699680e-02f }, + { -4.400707710e-04f, +1.818902453e-02f, +9.974827210e-01f, -1.545322843e-02f }, + { -4.360486119e-04f, +1.804506631e-02f, +9.975195680e-01f, -1.534931837e-02f }, + { -4.320387594e-04f, +1.790126083e-02f, +9.975561442e-01f, -1.524526657e-02f }, + { -4.280411991e-04f, +1.775760809e-02f, +9.975924494e-01f, -1.514107297e-02f }, + { -4.240559161e-04f, +1.761410804e-02f, +9.976284837e-01f, -1.503673754e-02f }, + { -4.200828959e-04f, +1.747076066e-02f, +9.976642471e-01f, -1.493226021e-02f }, + { -4.161221238e-04f, +1.732756592e-02f, +9.976997395e-01f, -1.482764093e-02f }, + { -4.121735850e-04f, +1.718452380e-02f, +9.977349608e-01f, -1.472287966e-02f }, + { -4.082372651e-04f, +1.704163425e-02f, +9.977699112e-01f, -1.461797634e-02f }, + { -4.043131492e-04f, +1.689889726e-02f, +9.978045905e-01f, -1.451293091e-02f }, + { -4.004012227e-04f, +1.675631280e-02f, +9.978389988e-01f, -1.440774333e-02f }, + { -3.965014710e-04f, +1.661388082e-02f, +9.978731359e-01f, -1.430241355e-02f }, + { -3.926138794e-04f, +1.647160132e-02f, +9.979070020e-01f, -1.419694151e-02f }, + { -3.887384331e-04f, +1.632947425e-02f, +9.979405969e-01f, -1.409132716e-02f }, + { -3.848751175e-04f, +1.618749959e-02f, +9.979739207e-01f, -1.398557045e-02f }, + { -3.810239179e-04f, +1.604567730e-02f, +9.980069732e-01f, -1.387967133e-02f }, + { -3.771848197e-04f, +1.590400737e-02f, +9.980397546e-01f, -1.377362975e-02f }, + { -3.733578082e-04f, +1.576248975e-02f, +9.980722648e-01f, -1.366744566e-02f }, + { -3.695428686e-04f, +1.562112441e-02f, +9.981045038e-01f, -1.356111900e-02f }, + { -3.657399862e-04f, +1.547991134e-02f, +9.981364714e-01f, -1.345464973e-02f }, + { -3.619491465e-04f, +1.533885049e-02f, +9.981681678e-01f, -1.334803780e-02f }, + { -3.581703346e-04f, +1.519794184e-02f, +9.981995929e-01f, -1.324128315e-02f }, + { -3.544035359e-04f, +1.505718535e-02f, +9.982307467e-01f, -1.313438573e-02f }, + { -3.506487357e-04f, +1.491658101e-02f, +9.982616292e-01f, -1.302734550e-02f }, + { -3.469059193e-04f, +1.477612876e-02f, +9.982922403e-01f, -1.292016240e-02f }, + { -3.431750720e-04f, +1.463582860e-02f, +9.983225800e-01f, -1.281283638e-02f }, + { -3.394561791e-04f, +1.449568047e-02f, +9.983526483e-01f, -1.270536739e-02f }, + { -3.357492258e-04f, +1.435568436e-02f, +9.983824452e-01f, -1.259775538e-02f }, + { -3.320541975e-04f, +1.421584024e-02f, +9.984119707e-01f, -1.249000030e-02f }, + { -3.283710794e-04f, +1.407614806e-02f, +9.984412247e-01f, -1.238210211e-02f }, + { -3.246998569e-04f, +1.393660781e-02f, +9.984702072e-01f, -1.227406075e-02f }, + { -3.210405152e-04f, +1.379721944e-02f, +9.984989183e-01f, -1.216587616e-02f }, + { -3.173930397e-04f, +1.365798293e-02f, +9.985273578e-01f, -1.205754831e-02f }, + { -3.137574155e-04f, +1.351889825e-02f, +9.985555259e-01f, -1.194907714e-02f }, + { -3.101336280e-04f, +1.337996537e-02f, +9.985834223e-01f, -1.184046260e-02f }, + { -3.065216624e-04f, +1.324118424e-02f, +9.986110473e-01f, -1.173170465e-02f }, + { -3.029215041e-04f, +1.310255485e-02f, +9.986384006e-01f, -1.162280322e-02f }, + { -2.993331383e-04f, +1.296407716e-02f, +9.986654823e-01f, -1.151375828e-02f }, + { -2.957565503e-04f, +1.282575114e-02f, +9.986922924e-01f, -1.140456977e-02f }, + { -2.921917254e-04f, +1.268757675e-02f, +9.987188309e-01f, -1.129523765e-02f }, + { -2.886386488e-04f, +1.254955397e-02f, +9.987450978e-01f, -1.118576186e-02f }, + { -2.850973058e-04f, +1.241168275e-02f, +9.987710929e-01f, -1.107614236e-02f }, + { -2.815676816e-04f, +1.227396308e-02f, +9.987968164e-01f, -1.096637910e-02f }, + { -2.780497616e-04f, +1.213639492e-02f, +9.988222682e-01f, -1.085647202e-02f }, + { -2.745435310e-04f, +1.199897823e-02f, +9.988474483e-01f, -1.074642108e-02f }, + { -2.710489751e-04f, +1.186171298e-02f, +9.988723567e-01f, -1.063622623e-02f }, + { -2.675660791e-04f, +1.172459914e-02f, +9.988969933e-01f, -1.052588743e-02f }, + { -2.640948284e-04f, +1.158763668e-02f, +9.989213581e-01f, -1.041540461e-02f }, + { -2.606352080e-04f, +1.145082556e-02f, +9.989454512e-01f, -1.030477774e-02f }, + { -2.571872034e-04f, +1.131416575e-02f, +9.989692724e-01f, -1.019400677e-02f }, + { -2.537507998e-04f, +1.117765722e-02f, +9.989928219e-01f, -1.008309164e-02f }, + { -2.503259824e-04f, +1.104129994e-02f, +9.990160995e-01f, -9.972032308e-03f }, + { -2.469127365e-04f, +1.090509386e-02f, +9.990391053e-01f, -9.860828729e-03f }, + { -2.435110474e-04f, +1.076903897e-02f, +9.990618393e-01f, -9.749480853e-03f }, + { -2.401209002e-04f, +1.063313522e-02f, +9.990843014e-01f, -9.637988631e-03f }, + { -2.367422804e-04f, +1.049738258e-02f, +9.991064916e-01f, -9.526352014e-03f }, + { -2.333751730e-04f, +1.036178102e-02f, +9.991284099e-01f, -9.414570956e-03f }, + { -2.300195634e-04f, +1.022633050e-02f, +9.991500563e-01f, -9.302645409e-03f }, + { -2.266754367e-04f, +1.009103099e-02f, +9.991714307e-01f, -9.190575323e-03f }, + { -2.233427784e-04f, +9.955882461e-03f, +9.991925333e-01f, -9.078360653e-03f }, + { -2.200215735e-04f, +9.820884872e-03f, +9.992133639e-01f, -8.966001349e-03f }, + { -2.167118075e-04f, +9.686038192e-03f, +9.992339225e-01f, -8.853497366e-03f }, + { -2.134134654e-04f, +9.551342385e-03f, +9.992542091e-01f, -8.740848654e-03f }, + { -2.101265325e-04f, +9.416797418e-03f, +9.992742238e-01f, -8.628055168e-03f }, + { -2.068509942e-04f, +9.282403256e-03f, +9.992939664e-01f, -8.515116858e-03f }, + { -2.035868356e-04f, +9.148159865e-03f, +9.993134371e-01f, -8.402033679e-03f }, + { -2.003340419e-04f, +9.014067211e-03f, +9.993326357e-01f, -8.288805583e-03f }, + { -1.970925985e-04f, +8.880125258e-03f, +9.993515622e-01f, -8.175432524e-03f }, + { -1.938624906e-04f, +8.746333973e-03f, +9.993702168e-01f, -8.061914453e-03f }, + { -1.906437034e-04f, +8.612693320e-03f, +9.993885992e-01f, -7.948251325e-03f }, + { -1.874362221e-04f, +8.479203263e-03f, +9.994067096e-01f, -7.834443092e-03f }, + { -1.842400320e-04f, +8.345863769e-03f, +9.994245479e-01f, -7.720489707e-03f }, + { -1.810551183e-04f, +8.212674803e-03f, +9.994421141e-01f, -7.606391125e-03f }, + { -1.778814663e-04f, +8.079636328e-03f, +9.994594082e-01f, -7.492147298e-03f }, + { -1.747190612e-04f, +7.946748310e-03f, +9.994764302e-01f, -7.377758181e-03f }, + { -1.715678882e-04f, +7.814010713e-03f, +9.994931800e-01f, -7.263223725e-03f }, + { -1.684279326e-04f, +7.681423501e-03f, +9.995096577e-01f, -7.148543887e-03f }, + { -1.652991797e-04f, +7.548986640e-03f, +9.995258632e-01f, -7.033718618e-03f }, + { -1.621816145e-04f, +7.416700094e-03f, +9.995417966e-01f, -6.918747873e-03f }, + { -1.590752225e-04f, +7.284563826e-03f, +9.995574578e-01f, -6.803631606e-03f }, + { -1.559799888e-04f, +7.152577801e-03f, +9.995728468e-01f, -6.688369772e-03f }, + { -1.528958987e-04f, +7.020741983e-03f, +9.995879637e-01f, -6.572962323e-03f }, + { -1.498229373e-04f, +6.889056337e-03f, +9.996028083e-01f, -6.457409214e-03f }, + { -1.467610900e-04f, +6.757520824e-03f, +9.996173807e-01f, -6.341710400e-03f }, + { -1.437103420e-04f, +6.626135411e-03f, +9.996316809e-01f, -6.225865834e-03f }, + { -1.406706784e-04f, +6.494900059e-03f, +9.996457089e-01f, -6.109875472e-03f }, + { -1.376420846e-04f, +6.363814734e-03f, +9.996594646e-01f, -5.993739268e-03f }, + { -1.346245458e-04f, +6.232879398e-03f, +9.996729481e-01f, -5.877457176e-03f }, + { -1.316180471e-04f, +6.102094014e-03f, +9.996861593e-01f, -5.761029151e-03f }, + { -1.286225739e-04f, +5.971458547e-03f, +9.996990983e-01f, -5.644455148e-03f }, + { -1.256381113e-04f, +5.840972959e-03f, +9.997117650e-01f, -5.527735122e-03f }, + { -1.226646447e-04f, +5.710637213e-03f, +9.997241594e-01f, -5.410869028e-03f }, + { -1.197021592e-04f, +5.580451273e-03f, +9.997362815e-01f, -5.293856820e-03f }, + { -1.167506400e-04f, +5.450415101e-03f, +9.997481313e-01f, -5.176698454e-03f }, + { -1.138100725e-04f, +5.320528660e-03f, +9.997597089e-01f, -5.059393885e-03f }, + { -1.108804418e-04f, +5.190791913e-03f, +9.997710141e-01f, -4.941943068e-03f }, + { -1.079617332e-04f, +5.061204824e-03f, +9.997820469e-01f, -4.824345959e-03f }, + { -1.050539318e-04f, +4.931767353e-03f, +9.997928075e-01f, -4.706602513e-03f }, + { -1.021570230e-04f, +4.802479464e-03f, +9.998032957e-01f, -4.588712686e-03f }, + { -9.927099199e-05f, +4.673341119e-03f, +9.998135116e-01f, -4.470676433e-03f }, + { -9.639582397e-05f, +4.544352281e-03f, +9.998234552e-01f, -4.352493710e-03f }, + { -9.353150418e-05f, +4.415512912e-03f, +9.998331264e-01f, -4.234164473e-03f }, + { -9.067801786e-05f, +4.286822973e-03f, +9.998425252e-01f, -4.115688677e-03f }, + { -8.783535025e-05f, +4.158282427e-03f, +9.998516517e-01f, -3.997066279e-03f }, + { -8.500348659e-05f, +4.029891236e-03f, +9.998605058e-01f, -3.878297235e-03f }, + { -8.218241209e-05f, +3.901649361e-03f, +9.998690875e-01f, -3.759381500e-03f }, + { -7.937211202e-05f, +3.773556765e-03f, +9.998773969e-01f, -3.640319031e-03f }, + { -7.657257158e-05f, +3.645613409e-03f, +9.998854338e-01f, -3.521109785e-03f }, + { -7.378377604e-05f, +3.517819255e-03f, +9.998931984e-01f, -3.401753717e-03f }, + { -7.100571061e-05f, +3.390174264e-03f, +9.999006906e-01f, -3.282250785e-03f }, + { -6.823836055e-05f, +3.262678397e-03f, +9.999079103e-01f, -3.162600944e-03f }, + { -6.548171107e-05f, +3.135331617e-03f, +9.999148577e-01f, -3.042804151e-03f }, + { -6.273574744e-05f, +3.008133883e-03f, +9.999215326e-01f, -2.922860364e-03f }, + { -6.000045487e-05f, +2.881085158e-03f, +9.999279352e-01f, -2.802769538e-03f }, + { -5.727581862e-05f, +2.754185402e-03f, +9.999340653e-01f, -2.682531632e-03f }, + { -5.456182391e-05f, +2.627434576e-03f, +9.999399230e-01f, -2.562146601e-03f }, + { -5.185845600e-05f, +2.500832641e-03f, +9.999455083e-01f, -2.441614402e-03f }, + { -4.916570012e-05f, +2.374379558e-03f, +9.999508211e-01f, -2.320934994e-03f }, + { -4.648354151e-05f, +2.248075287e-03f, +9.999558615e-01f, -2.200108333e-03f }, + { -4.381196542e-05f, +2.121919790e-03f, +9.999606295e-01f, -2.079134377e-03f }, + { -4.115095708e-05f, +1.995913026e-03f, +9.999651250e-01f, -1.958013083e-03f }, + { -3.850050175e-05f, +1.870054956e-03f, +9.999693481e-01f, -1.836744408e-03f }, + { -3.586058466e-05f, +1.744345541e-03f, +9.999732988e-01f, -1.715328311e-03f }, + { -3.323119106e-05f, +1.618784740e-03f, +9.999769770e-01f, -1.593764748e-03f }, + { -3.061230620e-05f, +1.493372514e-03f, +9.999803827e-01f, -1.472053677e-03f }, + { -2.800391533e-05f, +1.368108822e-03f, +9.999835160e-01f, -1.350195058e-03f }, + { -2.540600368e-05f, +1.242993626e-03f, +9.999863768e-01f, -1.228188846e-03f }, + { -2.281855651e-05f, +1.118026884e-03f, +9.999889652e-01f, -1.106035001e-03f }, + { -2.024155907e-05f, +9.932085563e-04f, +9.999912812e-01f, -9.837334803e-04f }, + { -1.767499661e-05f, +8.685386028e-04f, +9.999933246e-01f, -8.612842424e-04f }, + { -1.511885438e-05f, +7.440169831e-04f, +9.999950956e-01f, -7.386872455e-04f }, + { -1.257311763e-05f, +6.196436566e-04f, +9.999965942e-01f, -6.159424479e-04f }, + { -1.003777162e-05f, +4.954185828e-04f, +9.999978203e-01f, -4.930498082e-04f }, + { -7.512801591e-06f, +3.713417210e-04f, +9.999987739e-01f, -3.700092848e-04f }, + { -4.998192808e-06f, +2.474130305e-04f, +9.999994551e-01f, -2.468208365e-04f }, + { -2.493930525e-06f, +1.236324705e-04f, +9.999998638e-01f, -1.234844220e-04f }, +}; diff --git a/Alc/mixer.c b/Alc/mixer.c index 69e52a6e..f4374882 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -43,8 +43,6 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, extern inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); -alignas(16) ALfloat ResampleCoeffs_FIR4[FRACTIONONE][4]; - enum Resampler { PointResampler, @@ -155,91 +153,10 @@ static inline ResamplerFunc SelectResampler(enum Resampler resampler) } -/* The sinc resampler makes use of a Kaiser window to limit the needed sample - * points to 4. - */ - -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif -static inline double Sinc(double x) -{ - if(x == 0.0) return 1.0; - return sin(x*M_PI) / (x*M_PI); -} - -/* The zero-order modified Bessel function of the first kind, used for the - * Kaiser window. - * - * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k) - * = sum_{k=0}^inf ((x / 2)^k / k!)^2 - */ -static double BesselI_0(double x) -{ - double term, sum, x2, y, last_sum; - int k; - - /* Start at k=1 since k=0 is trivial. */ - term = 1.0; - sum = 1.0; - x2 = x / 2.0; - k = 1; - - /* Let the integration converge until the term of the sum is no longer - * significant. - */ - do { - y = x2 / k; - k ++; - last_sum = sum; - term *= y * y; - sum += term; - } while(sum != last_sum); - return sum; -} - -/* Calculate a Kaiser window from the given beta value and a normalized k - * [-1, 1]. - * - * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1 - * { 0, elsewhere. - * - * Where k can be calculated as: - * - * k = i / l, where -l <= i <= l. - * - * or: - * - * k = 2 i / M - 1, where 0 <= i <= M. - */ -static inline double Kaiser(double b, double k) -{ - if(k <= -1.0 || k >= 1.0) return 0.0; - return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b); -} - -static inline double CalcKaiserBeta(double rejection) -{ - if(rejection > 50.0) - return 0.1102 * (rejection - 8.7); - if(rejection >= 21.0) - return (0.5842 * pow(rejection - 21.0, 0.4)) + - (0.07886 * (rejection - 21.0)); - return 0.0; -} - -static float SincKaiser(double r, double x) -{ - /* Limit rippling to -60dB. */ - return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x)); -} - - void aluInitMixer(void) { enum Resampler resampler = ResamplerDefault; const char *str; - ALuint i; if(ConfigValueStr(NULL, NULL, "resampler", &str)) { @@ -267,15 +184,6 @@ void aluInitMixer(void) } } - for(i = 0;i < FRACTIONONE;i++) - { - ALdouble mu = (ALdouble)i / FRACTIONONE; - ResampleCoeffs_FIR4[i][0] = SincKaiser(2.0, mu - -1.0); - ResampleCoeffs_FIR4[i][1] = SincKaiser(2.0, mu - 0.0); - ResampleCoeffs_FIR4[i][2] = SincKaiser(2.0, mu - 1.0); - ResampleCoeffs_FIR4[i][3] = SincKaiser(2.0, mu - 2.0); - } - MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); ResampleSamples = SelectResampler(resampler); diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 390a1dd2..0ceb9328 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -90,10 +90,10 @@ const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), const float32x4_t val1 = vld1q_f32(&src[pos_[1]]); const float32x4_t val2 = vld1q_f32(&src[pos_[2]]); const float32x4_t val3 = vld1q_f32(&src[pos_[3]]); - float32x4_t k0 = vld1q_f32(ResampleCoeffs_FIR4[frac_[0]]); - float32x4_t k1 = vld1q_f32(ResampleCoeffs_FIR4[frac_[1]]); - float32x4_t k2 = vld1q_f32(ResampleCoeffs_FIR4[frac_[2]]); - float32x4_t k3 = vld1q_f32(ResampleCoeffs_FIR4[frac_[3]]); + float32x4_t k0 = vld1q_f32(sinc4Tab[frac_[0]]); + float32x4_t k1 = vld1q_f32(sinc4Tab[frac_[1]]); + float32x4_t k2 = vld1q_f32(sinc4Tab[frac_[2]]); + float32x4_t k3 = vld1q_f32(sinc4Tab[frac_[3]]); float32x4_t out; k0 = vmulq_f32(k0, val0); diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 861cfc38..142cd363 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -55,10 +55,10 @@ const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state), const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[3]]); + __m128 k0 = _mm_load_ps(sinc4Tab[frac_.i[0]]); + __m128 k1 = _mm_load_ps(sinc4Tab[frac_.i[1]]); + __m128 k2 = _mm_load_ps(sinc4Tab[frac_.i[2]]); + __m128 k3 = _mm_load_ps(sinc4Tab[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index 61be4cae..d5f06d90 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -109,10 +109,10 @@ const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state), const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); - __m128 k0 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[0]]); - __m128 k1 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[1]]); - __m128 k2 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[2]]); - __m128 k3 = _mm_load_ps(ResampleCoeffs_FIR4[frac_.i[3]]); + __m128 k0 = _mm_load_ps(sinc4Tab[frac_.i[0]]); + __m128 k1 = _mm_load_ps(sinc4Tab[frac_.i[1]]); + __m128 k2 = _mm_load_ps(sinc4Tab[frac_.i[2]]); + __m128 k3 = _mm_load_ps(sinc4Tab[frac_.i[3]]); __m128 out; k0 = _mm_mul_ps(k0, val0); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 48520b41..7a29915f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -287,9 +287,8 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) { return minu64(max, maxu64(min, val)); } -extern alignas(16) ALfloat ResampleCoeffs_FIR4[FRACTIONONE][4]; - extern alignas(16) const ALfloat bsincTab[18840]; +extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4]; inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) @@ -298,8 +297,8 @@ inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) } inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac) { - const ALfloat *k = ResampleCoeffs_FIR4[frac]; - return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3; + return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 + + sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3; } diff --git a/utils/bsincgen.c b/utils/bsincgen.c index d53b3cb5..33783a27 100644 --- a/utils/bsincgen.c +++ b/utils/bsincgen.c @@ -364,11 +364,49 @@ static void BsiGenerateTables() fprintf(stdout, " },\n {"); for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) fprintf(stdout, " %d,", mt[si]); - fprintf(stdout, " 0 }\n };\n"); + fprintf(stdout, " 0 }\n };\n\n"); +} + + +/* These methods generate a much simplified 4-point sinc interpolator using a + * Kaiser windows. This is much simpler to process at run-time, but has notably + * more aliasing noise. + */ + +/* Same as in alu.h! */ +#define FRACTIONBITS (12) +#define FRACTIONONE (1< Date: Sat, 8 Apr 2017 14:29:08 -0700 Subject: Handle the source offset fraction as an ALsizei --- Alc/mixer.c | 4 ++-- Alc/mixer_c.c | 15 +++++++-------- Alc/mixer_defs.h | 28 ++++++++++++++-------------- Alc/mixer_neon.c | 40 ++++++++++++++++++++-------------------- Alc/mixer_sse.c | 2 +- Alc/mixer_sse2.c | 4 ++-- Alc/mixer_sse3.c | 4 ++-- Alc/mixer_sse41.c | 8 ++++---- OpenAL32/Include/alu.h | 4 ++-- OpenAL32/alSource.c | 16 +++++++++------- 10 files changed, 63 insertions(+), 62 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index f4374882..2a30e323 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -41,7 +41,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); +extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); enum Resampler { @@ -280,7 +280,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei NumChannels, SampleSize; ResamplerFunc Resample; ALsizei DataPosInt; - ALuint DataPosFrac; + ALsizei DataPosFrac; ALint64 DataSize64; ALint increment; ALsizei Counter; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index bb945e88..f0db2ebc 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -8,16 +8,16 @@ #include "alAuxEffectSlot.h" -static inline ALfloat point32(const ALfloat *restrict vals, ALuint UNUSED(frac)) +static inline ALfloat point32(const ALfloat *restrict vals, ALsizei UNUSED(frac)) { return vals[0]; } -static inline ALfloat lerp32(const ALfloat *restrict vals, ALuint frac) +static inline ALfloat lerp32(const ALfloat *restrict vals, ALsizei frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat fir4_32(const ALfloat *restrict vals, ALuint frac) +static inline ALfloat fir4_32(const ALfloat *restrict vals, ALsizei frac) { return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); } const ALfloat *Resample_copy32_C(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint UNUSED(frac), ALint UNUSED(increment), + const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment), ALfloat *restrict dst, ALsizei numsamples) { #if defined(HAVE_SSE) || defined(HAVE_NEON) @@ -31,7 +31,7 @@ const ALfloat *Resample_copy32_C(const InterpState* UNUSED(state), #define DECL_TEMPLATE(Sampler) \ const ALfloat *Resample_##Sampler##_C(const InterpState* UNUSED(state), \ - const ALfloat *restrict src, ALuint frac, ALint increment, \ + const ALfloat *restrict src, ALsizei frac, ALint increment, \ ALfloat *restrict dst, ALsizei numsamples) \ { \ ALsizei i; \ @@ -53,7 +53,7 @@ DECL_TEMPLATE(fir4_32) #undef DECL_TEMPLATE const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { const ALfloat *fil, *scd, *phd, *spd; @@ -79,8 +79,7 @@ const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restr // Apply the scale and phase interpolated filter. r = 0.0f; for(j_f = 0;j_f < m;j_f++) - r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * - src[j_f]; + r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * src[j_f]; dst[i] = r; frac += increment; diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index d4a49b53..dce748c5 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -12,11 +12,11 @@ struct MixHrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_point32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_lerp32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_fir4_32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALuint frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_copy32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_point32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_lerp32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_fir4_32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_bsinc32_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); /* C mixers */ @@ -52,7 +52,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALsizei InPos, ALsizei BufferSize); /* SSE resamplers */ -inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) +inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) { ALsizei i; @@ -67,21 +67,21 @@ inline void InitiatePositionArrays(ALuint frac, ALint increment, ALuint *restric } const ALfloat *Resample_lerp32_SSE2(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_lerp32_SSE41(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_fir4_32_SSE3(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_fir4_32_SSE41(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); /* Neon mixers */ @@ -102,13 +102,13 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, /* Neon resamplers */ const ALfloat *Resample_lerp32_Neon(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_fir4_32_Neon(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples); const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); #endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 0ceb9328..65dd608c 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -11,21 +11,21 @@ const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); - const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); + const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); alignas(16) ALint pos_[4]; - alignas(16) ALuint frac_[4]; + alignas(16) ALsizei frac_[4]; int32x4_t pos4; - uint32x4_t frac4; + int32x4_t frac4; ALsizei i; InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_u32(frac_); + frac4 = vld1q_s32(frac_); pos4 = vld1q_s32(pos_); for(i = 0;numsamples-i > 3;i += 4) @@ -35,14 +35,14 @@ const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state), /* val1 + (val2-val1)*mu */ const float32x4_t r0 = vsubq_f32(val2, val1); - const float32x4_t mu = vmulq_f32(vcvtq_f32_u32(frac4), fracOne4); + const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); const float32x4_t out = vmlaq_f32(val1, mu, r0); vst1q_f32(&dst[i], out); - frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); - pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); - frac4 = vandq_u32(frac4, fracMask4); + frac4 = vaddq_s32(frac4, increment4); + pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); + frac4 = vandq_s32(frac4, fracMask4); vst1q_s32(pos_, pos4); } @@ -54,7 +54,7 @@ const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state), * resample. */ ALint pos = pos_[0]; - frac = vgetq_lane_u32(frac4, 0); + frac = vgetq_lane_s32(frac4, 0); do { dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); @@ -67,20 +67,20 @@ const ALfloat *Resample_lerp32_Neon(const InterpState* UNUSED(state), } const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const int32x4_t increment4 = vdupq_n_s32(increment*4); - const uint32x4_t fracMask4 = vdupq_n_u32(FRACTIONMASK); + const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); alignas(16) ALint pos_[4]; - alignas(16) ALuint frac_[4]; + alignas(16) ALsizei frac_[4]; int32x4_t pos4; - uint32x4_t frac4; + int32x4_t frac4; ALsizei i; InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_u32(frac_); + frac4 = vld1q_s32(frac_); pos4 = vld1q_s32(pos_); --src; @@ -109,12 +109,12 @@ const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), vst1q_f32(&dst[i], out); - frac4 = vaddq_u32(frac4, (uint32x4_t)increment4); - pos4 = vaddq_s32(pos4, (int32x4_t)vshrq_n_u32(frac4, FRACTIONBITS)); - frac4 = vandq_u32(frac4, fracMask4); + frac4 = vaddq_s32(frac4, increment4); + pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); + frac4 = vandq_s32(frac4, fracMask4); vst1q_s32(pos_, pos4); - vst1q_u32(frac_, frac4); + vst1q_s32(frac_, frac4); } if(i < numsamples) @@ -137,7 +137,7 @@ const ALfloat *Resample_fir4_32_Neon(const InterpState* UNUSED(state), } const ALfloat *Resample_bsinc32_Neon(const InterpState *state, - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index 37ce953f..d30ec982 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -13,7 +13,7 @@ const ALfloat *Resample_bsinc32_SSE(const InterpState *state, const ALfloat *restrict src, - ALuint frac, ALint increment, ALfloat *restrict dst, + ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen) { const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c index a1e8507e..84cc35dd 100644 --- a/Alc/mixer_sse2.c +++ b/Alc/mixer_sse2.c @@ -28,14 +28,14 @@ const ALfloat *Resample_lerp32_SSE2(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALint pos; ALsizei i; diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c index 142cd363..78603c87 100644 --- a/Alc/mixer_sse3.c +++ b/Alc/mixer_sse3.c @@ -32,13 +32,13 @@ const ALfloat *Resample_fir4_32_SSE3(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALint pos; ALsizei i; diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c index d5f06d90..613a89ff 100644 --- a/Alc/mixer_sse41.c +++ b/Alc/mixer_sse41.c @@ -29,14 +29,14 @@ const ALfloat *Resample_lerp32_SSE41(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALint pos; ALsizei i; @@ -86,13 +86,13 @@ const ALfloat *Resample_lerp32_SSE41(const InterpState* UNUSED(state), } const ALfloat *Resample_fir4_32_SSE41(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALuint i[4]; float f[4]; } frac_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; __m128i frac4, pos4; ALint pos; ALsizei i; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 7a29915f..4d0ee196 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -173,7 +173,7 @@ typedef struct ALvoice { * sample. */ ATOMIC(ALuint) position; - ATOMIC(ALuint) position_fraction; + ATOMIC(ALsizei) position_fraction; /** * Number of channels and bytes-per-sample for the attached source's @@ -211,7 +211,7 @@ typedef struct ALvoice { typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, - const ALfloat *restrict src, ALuint frac, ALint increment, + const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen ); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 071ac8d4..a8c4ce2f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -53,7 +53,7 @@ static void UpdateSourceProps(ALsource *source, ALsizei num_sends); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); typedef enum SourceProp { @@ -3158,7 +3158,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; - readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << + readPos |= (ALuint64)ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); } ATOMIC_THREAD_FENCE(almemory_order_acquire); @@ -3258,7 +3258,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; ALboolean readFin = AL_FALSE; - ALuint readPos, readPosFrac; + ALuint readPos; + ALsizei readPosFrac; ALuint totalBufferLen; ALboolean looping; ALuint refcount; @@ -3367,7 +3368,8 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ALbufferlistitem *BufferList; const ALbuffer *Buffer; ALuint bufferLen, totalBufferLen; - ALuint offset=0, frac=0; + ALuint offset = 0; + ALsizei frac = 0; /* Get sample frame offset */ if(!GetSampleOffset(Source, &offset, &frac)) @@ -3405,7 +3407,7 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) * or Second offset supplied by the application). This takes into account the * fact that the buffer format may have been modifed since. */ -static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) { const ALbuffer *Buffer = NULL; const ALbufferlistitem *BufferList; @@ -3454,13 +3456,13 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) case AL_SAMPLE_OFFSET: dblfrac = modf(Source->Offset, &dbloff); *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; case AL_SEC_OFFSET: dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff); *offset = (ALuint)mind(dbloff, UINT_MAX); - *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); + *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; } Source->OffsetType = AL_NONE; -- cgit v1.2.3 From 81527cdbddc52338f5fb3c8b79139bf9d9186d3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 9 Apr 2017 11:21:02 -0700 Subject: Convert the CoreAudio backend to the updated backend API --- Alc/ALc.c | 2 +- Alc/backends/base.h | 1 + Alc/backends/coreaudio.c | 460 ++++++++++++++++++++++++++++------------------ OpenAL32/Include/alMain.h | 3 - 4 files changed, 284 insertions(+), 182 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0cc36cad..7d4f4de3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -72,7 +72,7 @@ static struct BackendInfo BackendList[] = { { "alsa", ALCalsaBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_COREAUDIO - { "core", NULL, alc_ca_init, alc_ca_deinit, alc_ca_probe, EmptyFuncs }, + { "core", ALCcoreAudioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_OSS { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 4f398047..961a4d1a 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -137,6 +137,7 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ ALCbackendFactory *ALCpulseBackendFactory_getFactory(void); ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 5e0b03bd..435c0fae 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -33,6 +33,8 @@ #include #include +#include "backends/base.h" + typedef struct { AudioUnit audioUnit; @@ -51,17 +53,6 @@ typedef struct { static const ALCchar ca_device[] = "CoreAudio Default"; -static void destroy_buffer_list(AudioBufferList* list) -{ - if(list) - { - UInt32 i; - for(i = 0;i < list->mNumberBuffers;i++) - free(list->mBuffers[i].mData); - free(list); - } -} - static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) { AudioBufferList *list; @@ -83,70 +74,85 @@ static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSiz return list; } -static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +static void destroy_buffer_list(AudioBufferList* list) { - ALCdevice *device = (ALCdevice*)inRefCon; - ca_data *data = (ca_data*)device->ExtraData; - - ALCdevice_Lock(device); - aluMixData(device, ioData->mBuffers[0].mData, - ioData->mBuffers[0].mDataByteSize / data->frameSize); - ALCdevice_Unlock(device); - - return noErr; + if(list) + { + UInt32 i; + for(i = 0;i < list->mNumberBuffers;i++) + free(list->mBuffers[i].mData); + free(list); + } } -static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, - AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData) -{ - ALCdevice *device = (ALCdevice*)inUserData; - ca_data *data = (ca_data*)device->ExtraData; - // Read from the ring buffer and store temporarily in a large buffer - ll_ringbuffer_read(data->ring, data->resampleBuffer, *ioNumberDataPackets); +typedef struct ALCcoreAudioPlayback { + DERIVE_FROM_TYPE(ALCbackend); - // Set the input data - ioData->mNumberBuffers = 1; - ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; - ioData->mBuffers[0].mData = data->resampleBuffer; - ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame; + AudioUnit audioUnit; - return noErr; + ALuint frameSize; + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD +} ALCcoreAudioPlayback; + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); +static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self); +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); +static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback); + + +static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self); + + self->frameSize = 0; + memset(&self->format, 0, sizeof(self->format)); } -static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, - UInt32 inNumberFrames, AudioBufferList *ioData) +static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { - ALCdevice *device = (ALCdevice*)inRefCon; - ca_data *data = (ca_data*)device->ExtraData; - AudioUnitRenderActionFlags flags = 0; - OSStatus err; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} - // fill the bufferList with data from the input device - err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList); - if(err != noErr) - { - ERR("AudioUnitRender error: %d\n", err); - return err; - } - ll_ringbuffer_write(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); +static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp), + UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData) +{ + ALCcoreAudioPlayback *self = inRefCon; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + + ALCdevice_Lock(device); + aluMixData(device, ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / self->frameSize); + ALCdevice_Unlock(device); return noErr; } -static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name) { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioComponentDescription desc; AudioComponent comp; - ca_data *data; OSStatus err; - if(!deviceName) - deviceName = ca_device; - else if(strcmp(deviceName, ca_device) != 0) + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) return ALC_INVALID_VALUE; /* open the default output unit */ @@ -163,57 +169,47 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - - err = AudioComponentInstanceNew(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); - free(data); return ALC_INVALID_VALUE; } /* init and start the default audio unit... */ - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); - AudioComponentInstanceDispose(data->audioUnit); - free(data); + AudioComponentInstanceDispose(self->audioUnit); return ALC_INVALID_VALUE; } - alstr_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; } -static void ca_close_playback(ALCdevice *device) +static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - - AudioUnitUninitialize(data->audioUnit); - AudioComponentInstanceDispose(data->audioUnit); - - free(data); - device->ExtraData = NULL; + AudioUnitUninitialize(self->audioUnit); + AudioComponentInstanceDispose(self->audioUnit); } -static ALCboolean ca_reset_playback(ALCdevice *device) +static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioStreamBasicDescription streamFormat; AURenderCallbackStruct input; OSStatus err; UInt32 size; - err = AudioUnitUninitialize(data->audioUnit); + err = AudioUnitUninitialize(self->audioUnit); if(err != noErr) ERR("-- AudioUnitUninitialize failed.\n"); /* retrieve default output unit's properties (output side) */ size = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); if(err != noErr || size != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -231,7 +227,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) #endif /* set default output unit's input side to match output side */ - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -315,7 +311,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -323,11 +319,11 @@ static ALCboolean ca_reset_playback(ALCdevice *device) } /* setup callback */ - data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - input.inputProc = ca_callback; - input.inputProcRefCon = device; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + input.inputProc = ALCcoreAudioPlayback_MixerProc; + input.inputProcRefCon = self; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -335,7 +331,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device) } /* init the default audio unit... */ - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -345,12 +341,9 @@ static ALCboolean ca_reset_playback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean ca_start_playback(ALCdevice *device) +static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err; - - err = AudioOutputUnitStart(data->audioUnit); + OSStatus err = AudioOutputUnitStart(self->audioUnit); if(err != noErr) { ERR("AudioOutputUnitStart failed\n"); @@ -360,18 +353,107 @@ static ALCboolean ca_start_playback(ALCdevice *device) return ALC_TRUE; } -static void ca_stop_playback(ALCdevice *device) +static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self) { - ca_data *data = (ca_data*)device->ExtraData; + OSStatus err = AudioOutputUnitStop(self->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + + + + +typedef struct ALCcoreAudioCapture { + DERIVE_FROM_TYPE(ALCbackend); + + AudioUnit audioUnit; + + ALuint frameSize; + ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + + AudioConverterRef audioConverter; // Sample rate converter if needed + AudioBufferList *bufferList; // Buffer for data coming from the input device + ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling + + ll_ringbuffer_t *ring; +} ALCcoreAudioCapture; + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); +static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self); +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); + + +static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); + +} + +static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) +{ + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon, + AudioUnitRenderActionFlags* UNUSED(ioActionFlags), + const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber), + UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData)) +{ + ALCcoreAudioCapture *self = inRefCon; + AudioUnitRenderActionFlags flags = 0; OSStatus err; - err = AudioOutputUnitStop(data->audioUnit); + // fill the bufferList with data from the input device + err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList); if(err != noErr) - ERR("AudioOutputUnitStop failed\n"); + { + ERR("AudioUnitRender error: %d\n", err); + return err; + } + + ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames); + + return noErr; +} + +static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter), + UInt32 *ioNumberDataPackets, AudioBufferList *ioData, + AudioStreamPacketDescription** UNUSED(outDataPacketDescription), + void *inUserData) +{ + ALCcoreAudioCapture *self = inUserData; + + // Read from the ring buffer and store temporarily in a large buffer + ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets); + + // Set the input data + ioData->mNumberBuffers = 1; + ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + ioData->mBuffers[0].mData = self->resampleBuffer; + ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame; + + return noErr; } -static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name) { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; AudioStreamBasicDescription requestedFormat; // The application requested format AudioStreamBasicDescription hardwareFormat; // The hardware format AudioStreamBasicDescription outputFormat; // The AudioUnit output format @@ -383,12 +465,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) AudioObjectPropertyAddress propertyAddress; UInt32 enableIO; AudioComponent comp; - ca_data *data; OSStatus err; - if(!deviceName) - deviceName = ca_device; - else if(strcmp(deviceName, ca_device) != 0) + if(!name) + name = ca_device; + else if(strcmp(name, ca_device) != 0) return ALC_INVALID_VALUE; desc.componentType = kAudioUnitType_Output; @@ -405,11 +486,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) return ALC_INVALID_VALUE; } - data = calloc(1, sizeof(*data)); - device->ExtraData = data; - // Open the component - err = AudioComponentInstanceNew(comp, &data->audioUnit); + err = AudioComponentInstanceNew(comp, &self->audioUnit); if(err != noErr) { ERR("AudioComponentInstanceNew failed\n"); @@ -418,7 +496,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // Turn off AudioUnit output enableIO = 0; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -427,7 +505,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // Turn on AudioUnit input enableIO = 1; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -455,7 +533,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Track the input device - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -463,10 +541,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // set capture callback - input.inputProc = ca_capture_callback; - input.inputProcRefCon = device; + input.inputProc = ALCcoreAudioCapture_RecordProc; + input.inputProcRefCon = self; - err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -474,7 +552,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Initialize the device - err = AudioUnitInitialize(data->audioUnit); + err = AudioUnitInitialize(self->audioUnit); if(err != noErr) { ERR("AudioUnitInitialize failed\n"); @@ -483,7 +561,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) // Get the hardware format propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) { ERR("AudioUnitGetProperty failed\n"); @@ -545,8 +623,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) requestedFormat.mFramesPerPacket = 1; // save requested format description for later use - data->format = requestedFormat; - data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->format = requestedFormat; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later @@ -554,11 +632,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) outputFormat.mSampleRate = hardwareFormat.mSampleRate; // Determine sample rate ratio for resampling - data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; + self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; // The output format should be the requested format, but using the hardware sample rate // This is because the AudioUnit will automatically scale other properties, except for sample rate - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); if(err != noErr) { ERR("AudioUnitSetProperty failed\n"); @@ -566,8 +644,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Set the AudioUnit output format frame count - outputFrameCount = device->UpdateSize * data->sampleRateRatio; - err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + outputFrameCount = device->UpdateSize * self->sampleRateRatio; + err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); if(err != noErr) { ERR("AudioUnitSetProperty failed: %d\n", err); @@ -575,7 +653,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Set up sample converter - err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter); + err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter); if(err != noErr) { ERR("AudioConverterNew failed: %d\n", err); @@ -583,75 +661,71 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) } // Create a buffer for use in the resample callback - data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio); + self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio); // Allocate buffer for the AudioUnit output - data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio); - if(data->bufferList == NULL) + self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio); + if(self->bufferList == NULL) goto error; - data->ring = ll_ringbuffer_create( - device->UpdateSize*data->sampleRateRatio*device->NumUpdates + 1, - data->frameSize + self->ring = ll_ringbuffer_create( + device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1, + self->frameSize ); - if(!data->ring) goto error; + if(!self->ring) goto error; - alstr_copy_cstr(&device->DeviceName, deviceName); + alstr_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; error: - ll_ringbuffer_free(data->ring); - data->ring = NULL; - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); - - if(data->audioConverter) - AudioConverterDispose(data->audioConverter); - if(data->audioUnit) - AudioComponentInstanceDispose(data->audioUnit); + ll_ringbuffer_free(self->ring); + self->ring = NULL; + free(self->resampleBuffer); + destroy_buffer_list(self->bufferList); - free(data); - device->ExtraData = NULL; + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); return ALC_INVALID_VALUE; } -static void ca_close_capture(ALCdevice *device) + +static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; + ll_ringbuffer_free(self->ring); + self->ring = NULL; - ll_ringbuffer_free(data->ring); - data->ring = NULL; - free(data->resampleBuffer); - destroy_buffer_list(data->bufferList); + free(self->resampleBuffer); - AudioConverterDispose(data->audioConverter); - AudioComponentInstanceDispose(data->audioUnit); + destroy_buffer_list(self->bufferList); - free(data); - device->ExtraData = NULL; + AudioConverterDispose(self->audioConverter); + AudioComponentInstanceDispose(self->audioUnit); } -static void ca_start_capture(ALCdevice *device) +static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err = AudioOutputUnitStart(data->audioUnit); + OSStatus err = AudioOutputUnitStart(self->audioUnit); if(err != noErr) + { ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + return ALC_TRUE; } -static void ca_stop_capture(ALCdevice *device) +static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) { - ca_data *data = (ca_data*)device->ExtraData; - OSStatus err = AudioOutputUnitStop(data->audioUnit); + OSStatus err = AudioOutputUnitStop(self->audioUnit); if(err != noErr) ERR("AudioOutputUnitStop failed\n"); } -static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) { - ca_data *data = (ca_data*)device->ExtraData; AudioBufferList *list; UInt32 frameCount; OSStatus err; @@ -665,14 +739,15 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa // Point the resampling buffer to the capture buffer list->mNumberBuffers = 1; - list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; - list->mBuffers[0].mDataByteSize = samples * data->frameSize; + list->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + list->mBuffers[0].mDataByteSize = samples * self->frameSize; list->mBuffers[0].mData = buffer; // Resample into another AudioBufferList frameCount = samples; - err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback, - device, &frameCount, list, NULL); + err = AudioConverterFillComplexBuffer(self->audioConverter, + ALCcoreAudioCapture_ConvertCallback, self, &frameCount, list, NULL + ); if(err != noErr) { ERR("AudioConverterFillComplexBuffer error: %d\n", err); @@ -681,38 +756,47 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa return ALC_NO_ERROR; } -static ALCuint ca_available_samples(ALCdevice *device) +static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self) { - ca_data *data = device->ExtraData; - return ll_ringbuffer_read_space(data->ring) / data->sampleRateRatio; + return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio; } -static const BackendFuncs ca_funcs = { - ca_open_playback, - ca_close_playback, - ca_reset_playback, - ca_start_playback, - ca_stop_playback, - ca_open_capture, - ca_close_capture, - ca_start_capture, - ca_stop_capture, - ca_capture_samples, - ca_available_samples -}; - -ALCboolean alc_ca_init(BackendFuncs *func_list) +typedef struct ALCcoreAudioBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCcoreAudioBackendFactory; +#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } } + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); +static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); + + +ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void) +{ + static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self)) { - *func_list = ca_funcs; return ALC_TRUE; } -void alc_ca_deinit(void) +static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback || ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; } -void alc_ca_probe(enum DevProbe type) +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -724,3 +808,23 @@ void alc_ca_probe(enum DevProbe type) break; } } + +static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCcoreAudioPlayback *backend; + NEW_OBJ(backend, ALCcoreAudioPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCcoreAudioCapture *backend; + NEW_OBJ(backend, ALCcoreAudioCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7add9310..1919a257 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -429,9 +429,6 @@ typedef struct { ALCuint (*AvailableSamples)(ALCdevice*); } BackendFuncs; -ALCboolean alc_ca_init(BackendFuncs *func_list); -void alc_ca_deinit(void); -void alc_ca_probe(enum DevProbe type); ALCboolean alc_qsa_init(BackendFuncs *func_list); void alc_qsa_deinit(void); void alc_qsa_probe(enum DevProbe type); -- cgit v1.2.3 From 6cc69c8d94744d66e68ffffb9b71f6714d86e710 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Apr 2017 09:17:10 -0700 Subject: Add a sample converter This is intended to do conversions for interleaved samples, and supports changing from one DevFmtType to another as well as resampling. It does not handle remixing channels. The mixer is more optimized to use the resampling functions directly. However, this should prove useful for recording with certain backends that won't do the conversion themselves. --- Alc/converter.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++ Alc/converter.h | 42 +++++++ Alc/mixer.c | 11 +- CMakeLists.txt | 1 + OpenAL32/Include/alu.h | 10 ++ 5 files changed, 386 insertions(+), 10 deletions(-) create mode 100644 Alc/converter.c create mode 100644 Alc/converter.h diff --git a/Alc/converter.c b/Alc/converter.c new file mode 100644 index 00000000..68752693 --- /dev/null +++ b/Alc/converter.c @@ -0,0 +1,332 @@ + +#include "config.h" + +#include "converter.h" + +#include "mixer_defs.h" + + +SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) +{ + SampleConverter *converter; + + if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) + return NULL; + + converter = al_calloc(16, offsetof(SampleConverter, Chan[numchans])); + converter->mSrcType = srcType; + converter->mDstType = dstType; + converter->mNumChannels = numchans; + converter->mSrcTypeSize = BytesFromDevFmt(srcType); + converter->mDstTypeSize = BytesFromDevFmt(dstType); + + converter->mSrcPrepCount = 0; + + converter->mFracOffset = 0; + converter->mIncrement = (ALsizei)clampu64((ALuint64)srcRate*FRACTIONONE/dstRate, + 1, MAX_PITCH*FRACTIONONE); + if(converter->mIncrement == FRACTIONONE) + converter->mResample = Resample_copy32_C; + else + { + /* TODO: Allow other resamplers. */ + converter->mResample = SelectResampler(LinearResampler); + } + + return converter; +} + +void DestroySampleConverter(SampleConverter **converter) +{ + if(converter) + { + al_free(*converter); + *converter = NULL; + } +} + + +static inline ALfloat Sample_ALbyte(ALbyte val) +{ return val * (1.0f/128.0f); } +static inline ALfloat Sample_ALubyte(ALubyte val) +{ return Sample_ALbyte((ALint)val - 128); } + +static inline ALfloat Sample_ALshort(ALshort val) +{ return val * (1.0f/32768.0f); } +static inline ALfloat Sample_ALushort(ALushort val) +{ return Sample_ALshort((ALint)val - 32768); } + +static inline ALfloat Sample_ALint(ALint val) +{ return (val>>7) * (1.0f/16777216.0f); } +static inline ALfloat Sample_ALuint(ALuint val) +{ return ((ALint)(val>>7) - 16777216) * (1.0f/16777216.0f); } + +static inline ALfloat Sample_ALfloat(ALfloat val) +{ return val; } + +#define DECL_TEMPLATE(T) \ +static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i] = Sample_##T(src[i*srcstep]); \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples) +{ + switch(srctype) + { + case DevFmtByte: + Load_ALbyte(dst, src, srcstep, samples); + break; + case DevFmtUByte: + Load_ALubyte(dst, src, srcstep, samples); + break; + case DevFmtShort: + Load_ALshort(dst, src, srcstep, samples); + break; + case DevFmtUShort: + Load_ALushort(dst, src, srcstep, samples); + break; + case DevFmtInt: + Load_ALint(dst, src, srcstep, samples); + break; + case DevFmtUInt: + Load_ALuint(dst, src, srcstep, samples); + break; + case DevFmtFloat: + Load_ALfloat(dst, src, srcstep, samples); + break; + } +} + + +static inline ALbyte ALbyte_Sample(ALfloat val) +{ return (ALbyte)clampf(val*128.0f, -128.0f, 127.0f); } +static inline ALubyte ALubyte_Sample(ALfloat val) +{ return ALbyte_Sample(val)+128; } + +static inline ALshort ALshort_Sample(ALfloat val) +{ return (ALshort)clampf(val*32768.0f, -32768.0f, 32767.0f); } +static inline ALushort ALushort_Sample(ALfloat val) +{ return ALshort_Sample(val)+32768; } + +static inline ALint ALint_Sample(ALfloat val) +{ return (ALint)clampf(val*16777216.0f, -16777216.0f, 16777215.0f) << 7; } +static inline ALuint ALuint_Sample(ALfloat val) +{ return ALint_Sample(val)+INT_MAX+1; } + +static inline ALfloat ALfloat_Sample(ALfloat val) +{ return val; } + +#define DECL_TEMPLATE(T) \ +static inline void Store_##T(T *dst, const ALfloat *src, ALint dststep, ALsizei samples)\ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i*dststep] = T##_Sample(src[i]); \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples) +{ + switch(dsttype) + { + case DevFmtByte: + Store_ALbyte(dst, src, dststep, samples); + break; + case DevFmtUByte: + Store_ALubyte(dst, src, dststep, samples); + break; + case DevFmtShort: + Store_ALshort(dst, src, dststep, samples); + break; + case DevFmtUShort: + Store_ALushort(dst, src, dststep, samples); + break; + case DevFmtInt: + Store_ALint(dst, src, dststep, samples); + break; + case DevFmtUInt: + Store_ALuint(dst, src, dststep, samples); + break; + case DevFmtFloat: + Store_ALfloat(dst, src, dststep, samples); + break; + } +} + + +ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes) +{ + ALint prepcount = converter->mSrcPrepCount; + ALsizei increment = converter->mIncrement; + ALsizei DataPosFrac = converter->mFracOffset; + ALuint64 DataSize64; + + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= srcframes) + return 0; + srcframes += prepcount; + prepcount = 0; + } + + if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES && + MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= srcframes) + { + /* Not enough input samples to generate an output sample. */ + return 0; + } + + DataSize64 = prepcount; + DataSize64 += srcframes; + DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + + /* If we have a full prep, we can generate at least one sample. */ + return (ALsizei)clampu64(DataSize64/increment, 1, INT_MAX); +} + + +ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +{ + const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; + const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize; + const ALsizei increment = converter->mIncrement; + ALsizei pos = 0; + + while(pos < dstframes) + { + ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16); + ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16); + ALint prepcount = converter->mSrcPrepCount; + ALsizei DataPosFrac = converter->mFracOffset; + ALuint64 DataSize64; + ALsizei DstSize; + ALint toread; + ALsizei chan; + + if(prepcount < 0) + { + /* Negative prepcount means we need to skip that many input samples. */ + if(-prepcount >= *srcframes) + { + converter->mSrcPrepCount = prepcount + *srcframes; + *srcframes = 0; + break; + } + src = (ALbyte*)src + SrcFrameSize*-prepcount; + *srcframes += prepcount; + prepcount = 0; + } + toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES)); + + if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES && + MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= toread) + { + /* Not enough input samples to generate an output sample. Store + * what we're given for later. + */ + for(chan = 0;chan < converter->mNumChannels;chan++) + LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], + (const ALbyte*)src + converter->mSrcTypeSize*chan, + converter->mNumChannels, converter->mSrcType, toread + ); + + converter->mSrcPrepCount = prepcount + toread; + *srcframes = 0; + break; + } + + DataSize64 = prepcount; + DataSize64 += toread; + DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + + /* If we have a full prep, we can generate at least one sample. */ + DstSize = (ALsizei)clampu64(DataSize64/increment, 1, BUFFERSIZE); + DstSize = mini(DstSize, dstframes-pos); + + for(chan = 0;chan < converter->mNumChannels;chan++) + { + const ALbyte *SrcSamples = (const ALbyte*)src + converter->mSrcTypeSize*chan; + ALbyte *DstSamples = (ALbyte*)dst + converter->mSrcTypeSize*chan; + const ALfloat *ResampledData; + ALsizei SrcDataEnd; + + /* Load the previous samples into the source data first, then the + * new samples from the input buffer. + */ + memcpy(SrcData, converter->Chan[chan].mPrevSamples, + prepcount*sizeof(ALfloat)); + LoadSamples(SrcData + prepcount, SrcSamples, + converter->mNumChannels, converter->mSrcType, toread + ); + + /* Store as many prep samples for next time as possible, given the + * number of output samples being generated. + */ + SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS; + if(SrcDataEnd >= prepcount+toread) + memset(converter->Chan[chan].mPrevSamples, 0, + sizeof(converter->Chan[chan].mPrevSamples)); + else + { + size_t len = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, prepcount+toread-SrcDataEnd); + memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd], + len*sizeof(ALfloat)); + memset(converter->Chan[chan].mPrevSamples+len, 0, + sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat)); + } + + /* Now resample, and store the result in the output buffer. */ + ResampledData = converter->mResample(NULL, + SrcData+MAX_PRE_SAMPLES, DataPosFrac, increment, + DstData, DstSize + ); + + StoreSamples(DstSamples, ResampledData, converter->mNumChannels, + converter->mDstType, DstSize); + } + + /* Update the number of prep samples still available, as well as the + * fractional offset. + */ + DataPosFrac += increment*DstSize; + converter->mSrcPrepCount = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, + prepcount+toread-(DataPosFrac>>FRACTIONBITS)); + converter->mFracOffset = DataPosFrac & FRACTIONMASK; + + /* Update the src and dst pointers in case there's still more to do. */ + src = (const ALbyte*)src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); + *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS)); + + dst = (ALbyte*)dst + DstFrameSize*DstSize; + pos += DstSize; + } + + return pos; +} diff --git a/Alc/converter.h b/Alc/converter.h new file mode 100644 index 00000000..76b2520f --- /dev/null +++ b/Alc/converter.h @@ -0,0 +1,42 @@ +#ifndef CONVERTER_H +#define CONVERTER_H + +#include "alMain.h" +#include "alu.h" + +#ifdef __cpluspluc +extern "C" { +#endif + +typedef struct SampleConverter { + enum DevFmtType mSrcType; + enum DevFmtType mDstType; + ALsizei mNumChannels; + ALsizei mSrcTypeSize; + ALsizei mDstTypeSize; + + ALint mSrcPrepCount; + + ALsizei mFracOffset; + ALsizei mIncrement; + ResamplerFunc mResample; + + alignas(16) ALfloat mSrcSamples[BUFFERSIZE+MAX_PRE_SAMPLES+MAX_POST_SAMPLES]; + alignas(16) ALfloat mDstSamples[BUFFERSIZE]; + + struct { + alignas(16) ALfloat mPrevSamples[MAX_PRE_SAMPLES+MAX_POST_SAMPLES]; + } Chan[]; +} SampleConverter; + +SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate); +void DestroySampleConverter(SampleConverter **converter); + +ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); +ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); + +#ifdef __cpluspluc +} +#endif + +#endif /* CONVERTER_H */ diff --git a/Alc/mixer.c b/Alc/mixer.c index 2a30e323..90f3e05e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -44,15 +44,6 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); -enum Resampler { - PointResampler, - LinearResampler, - FIR4Resampler, - BSincResampler, - - ResamplerDefault = LinearResampler -}; - /* BSinc requires up to 11 extra samples before the current position, and 12 after. */ static_assert(MAX_PRE_SAMPLES >= 11, "MAX_PRE_SAMPLES must be at least 11!"); static_assert(MAX_POST_SAMPLES >= 12, "MAX_POST_SAMPLES must be at least 12!"); @@ -103,7 +94,7 @@ static inline HrtfMixerFunc SelectHrtfMixer(void) return MixHrtf_C; } -static inline ResamplerFunc SelectResampler(enum Resampler resampler) +ResamplerFunc SelectResampler(enum Resampler resampler) { switch(resampler) { diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cb95402..ee1c9e57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -689,6 +689,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/alcConfig.c Alc/alcRing.c Alc/bs2b.c + Alc/converter.c Alc/effects/chorus.c Alc/effects/compressor.c Alc/effects/dedicated.c diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 4d0ee196..51c43d85 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -302,6 +302,15 @@ inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat v } +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + BSincResampler, + + ResamplerDefault = LinearResampler +}; + enum HrtfRequestMode { Hrtf_Default = 0, Hrtf_Enable = 1, @@ -313,6 +322,7 @@ void aluInitMixer(void); MixerFunc SelectMixer(void); RowMixerFunc SelectRowMixer(void); +ResamplerFunc SelectResampler(enum Resampler resampler); /* aluInitRenderer * -- cgit v1.2.3 From 8a7bc9ab4f6346fcff4584368d94e7098772ce40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Apr 2017 09:28:25 -0700 Subject: Trace the capture device format --- Alc/ALc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7d4f4de3..47bd19e4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -4124,6 +4124,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = samples; device->NumUpdates = 1; + TRACE("Capture format: %s, %s, %uhz, %u update size x%d\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { al_free(device); -- cgit v1.2.3 From cc79cb803ad27d92e3e44e89b59c5a6521e06d44 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Apr 2017 09:31:25 -0700 Subject: Reduce the size of the temp input buffer --- Alc/converter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/converter.h b/Alc/converter.h index 76b2520f..51d579b5 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -21,7 +21,7 @@ typedef struct SampleConverter { ALsizei mIncrement; ResamplerFunc mResample; - alignas(16) ALfloat mSrcSamples[BUFFERSIZE+MAX_PRE_SAMPLES+MAX_POST_SAMPLES]; + alignas(16) ALfloat mSrcSamples[BUFFERSIZE]; alignas(16) ALfloat mDstSamples[BUFFERSIZE]; struct { -- cgit v1.2.3 From caae349fdc16a761cda511f74c4cc5c611f5591a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Apr 2017 13:40:45 -0700 Subject: Update the given source pointer in the sample converter --- Alc/converter.c | 8 ++++---- Alc/converter.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index 68752693..1ea2e70f 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -210,7 +210,7 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe } -ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) +ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes) { const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize; const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize; @@ -237,7 +237,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsi *srcframes = 0; break; } - src = (ALbyte*)src + SrcFrameSize*-prepcount; + *src = (const ALbyte*)*src + SrcFrameSize*-prepcount; *srcframes += prepcount; prepcount = 0; } @@ -272,7 +272,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsi for(chan = 0;chan < converter->mNumChannels;chan++) { - const ALbyte *SrcSamples = (const ALbyte*)src + converter->mSrcTypeSize*chan; + const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan; ALbyte *DstSamples = (ALbyte*)dst + converter->mSrcTypeSize*chan; const ALfloat *ResampledData; ALsizei SrcDataEnd; @@ -321,7 +321,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsi converter->mFracOffset = DataPosFrac & FRACTIONMASK; /* Update the src and dst pointers in case there's still more to do. */ - src = (const ALbyte*)src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); + *src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS); *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS)); dst = (ALbyte*)dst + DstFrameSize*DstSize; diff --git a/Alc/converter.h b/Alc/converter.h index 51d579b5..5bbbf691 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -32,7 +32,7 @@ typedef struct SampleConverter { SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate); void DestroySampleConverter(SampleConverter **converter); -ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid *src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); +ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); #ifdef __cpluspluc -- cgit v1.2.3 From bcdd1cee10f6f2ebe51191b104b0e45c261801e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Apr 2017 07:25:55 -0700 Subject: Add a mono<->stereo converter This converter always outputs floats, and uses energy-preserving scaling. --- Alc/converter.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Alc/converter.h | 12 ++++++ 2 files changed, 134 insertions(+) diff --git a/Alc/converter.c b/Alc/converter.c index 1ea2e70f..ebbc0966 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -330,3 +330,125 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs return pos; } + + +ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans) +{ + ChannelConverter *converter; + + if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) || + (srcChans == DevFmtStereo && dstChans == DevFmtMono))) + return NULL; + + converter = al_calloc(DEF_ALIGN, sizeof(*converter)); + converter->mSrcType = srcType; + converter->mSrcChans = srcChans; + converter->mDstChans = dstChans; + + return converter; +} + +void DestroyChannelConverter(ChannelConverter **converter) +{ + if(converter) + { + al_free(*converter); + *converter = NULL; + } +} + + +#define DECL_TEMPLATE(T) \ +static void MonoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +{ \ + const T *data = (T*)src; \ + ALsizei i; \ + \ + for(i = 0;i < frames;i++) \ + dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(data[i]) * 0.707106781187f; \ +} \ + \ +static void StereoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +{ \ + const T *data = (T*)src; \ + ALsizei i; \ + \ + for(i = 0;i < frames;i++) \ + dst[i] = (Sample_##T(data[i*2 + 0])+Sample_##T(data[i*2 + 1])) * \ + 0.707106781187f; \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames) +{ + if(converter->mSrcChans == converter->mDstChans) + { + LoadSamples(dst, src, 1, converter->mSrcType, + frames*ChannelsFromDevFmt(converter->mSrcChans)); + return; + } + + if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono) + { + switch(converter->mSrcType) + { + case DevFmtByte: + MonoConvertALbyte(dst, src, frames); + break; + case DevFmtUByte: + MonoConvertALubyte(dst, src, frames); + break; + case DevFmtShort: + MonoConvertALshort(dst, src, frames); + break; + case DevFmtUShort: + MonoConvertALushort(dst, src, frames); + break; + case DevFmtInt: + MonoConvertALint(dst, src, frames); + break; + case DevFmtUInt: + MonoConvertALuint(dst, src, frames); + break; + case DevFmtFloat: + MonoConvertALfloat(dst, src, frames); + break; + } + } + else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/ + { + switch(converter->mSrcType) + { + case DevFmtByte: + StereoConvertALbyte(dst, src, frames); + break; + case DevFmtUByte: + StereoConvertALubyte(dst, src, frames); + break; + case DevFmtShort: + StereoConvertALshort(dst, src, frames); + break; + case DevFmtUShort: + StereoConvertALushort(dst, src, frames); + break; + case DevFmtInt: + StereoConvertALint(dst, src, frames); + break; + case DevFmtUInt: + StereoConvertALuint(dst, src, frames); + break; + case DevFmtFloat: + StereoConvertALfloat(dst, src, frames); + break; + } + } +} diff --git a/Alc/converter.h b/Alc/converter.h index 5bbbf691..db3f1daa 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -35,6 +35,18 @@ void DestroySampleConverter(SampleConverter **converter); ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes); ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes); + +typedef struct ChannelConverter { + enum DevFmtType mSrcType; + enum DevFmtChannels mSrcChans; + enum DevFmtChannels mDstChans; +} ChannelConverter; + +ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans); +void DestroyChannelConverter(ChannelConverter **converter); + +void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames); + #ifdef __cpluspluc } #endif -- cgit v1.2.3 From 78d5492d2c66ab6bb0141b5034a0b95b18fbf69a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Apr 2017 09:41:23 -0700 Subject: Use the converters to enable mmdevapi capture --- Alc/backends/mmdevapi.c | 213 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 171 insertions(+), 42 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 339ea8d3..a70607e4 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -44,6 +44,7 @@ #include "threads.h" #include "compat.h" #include "alstring.h" +#include "converter.h" #include "backends/base.h" @@ -1206,6 +1207,8 @@ typedef struct ALCmmdevCapture { HANDLE MsgEvent; + ChannelConverter *ChannelConv; + SampleConverter *SampleConv; ll_ringbuffer_t *Ring; volatile int killNow; @@ -1253,6 +1256,8 @@ static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) self->MsgEvent = NULL; + self->ChannelConv = NULL; + self->SampleConv = NULL; self->Ring = NULL; self->killNow = 0; @@ -1263,6 +1268,9 @@ static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) ll_ringbuffer_free(self->Ring); self->Ring = NULL; + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + if(self->NotifyEvent != NULL) CloseHandle(self->NotifyEvent); self->NotifyEvent = NULL; @@ -1282,6 +1290,8 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) { ALCmmdevCapture *self = arg; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALfloat *samples = NULL; + size_t samplesmax = 0; HRESULT hr; hr = CoInitialize(NULL); @@ -1304,33 +1314,74 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); if(FAILED(hr)) ERR("Failed to get next packet size: 0x%08lx\n", hr); - else while(avail > 0 && SUCCEEDED(hr)) + else if(avail > 0) { UINT32 numsamples; DWORD flags; - BYTE *data; + BYTE *rdata; hr = IAudioCaptureClient_GetBuffer(self->capture, - &data, &numsamples, &flags, NULL, NULL + &rdata, &numsamples, &flags, NULL, NULL ); if(FAILED(hr)) - { ERR("Failed to get capture buffer: 0x%08lx\n", hr); - break; - } + else + { + ll_ringbuffer_data_t data[2]; + size_t dstframes = 0; - ll_ringbuffer_write(self->Ring, (char*)data, numsamples); + if(self->ChannelConv) + { + if(samplesmax < numsamples) + { + size_t newmax = RoundUp(numsamples, 4096); + ALfloat *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); + al_free(samples); + samples = tmp; + samplesmax = newmax; + } + ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); + rdata = (BYTE*)samples; + } - hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); - if(FAILED(hr)) - { - ERR("Failed to release capture buffer: 0x%08lx\n", hr); - break; - } + ll_ringbuffer_get_write_vector(self->Ring, data); - hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); - if(FAILED(hr)) - ERR("Failed to get next packet size: 0x%08lx\n", hr); + if(self->SampleConv) + { + const ALvoid *srcdata = rdata; + ALsizei srcframes = numsamples; + + dstframes = SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[0].buf, data[0].len + ); + if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) + { + /* If some source samples remain, all of the first dest + * block was filled, and there's space in the second + * dest block, do another run for the second block. + */ + dstframes += SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[1].buf, data[1].len + ); + } + } + else + { + size_t framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + ALuint len1 = minu(data[0].len, numsamples); + ALuint len2 = minu(data[1].len, numsamples-len1); + + memcpy(data[0].buf, rdata, len1*framesize); + if(len2 > 0) + memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); + dstframes = len1 + len2; + } + + ll_ringbuffer_write_advance(self->Ring, dstframes); + + hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); + if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); + } } if(FAILED(hr)) @@ -1346,6 +1397,10 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) ERR("WaitForSingleObjectEx error: 0x%lx\n", res); } + al_free(samples); + samples = NULL; + samplesmax = 0; + CoUninitialize(); return 0; } @@ -1528,6 +1583,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; WAVEFORMATEXTENSIBLE OutputType; WAVEFORMATEX *wfx = NULL; + enum DevFmtType srcType; REFERENCE_TIME buf_time; UINT32 buffer_len; void *ptr = NULL; @@ -1587,33 +1643,28 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) } switch(device->FmtType) { + /* NOTE: Signedness doesn't matter, the converter will handle it. */ + case DevFmtByte: case DevFmtUByte: OutputType.Format.wBitsPerSample = 8; - OutputType.Samples.wValidBitsPerSample = 8; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; case DevFmtShort: + case DevFmtUShort: OutputType.Format.wBitsPerSample = 16; - OutputType.Samples.wValidBitsPerSample = 16; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; case DevFmtInt: + case DevFmtUInt: OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break; case DevFmtFloat: OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; break; - - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - return E_FAIL; } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; OutputType.Format.nSamplesPerSec = device->Frequency; OutputType.Format.nBlockAlign = OutputType.Format.nChannels * @@ -1631,27 +1682,103 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) return hr; } - /* FIXME: We should do conversion/resampling if we didn't get a matching format. */ - if(wfx->nSamplesPerSec != OutputType.Format.nSamplesPerSec || - wfx->wBitsPerSample != OutputType.Format.wBitsPerSample || - wfx->nChannels != OutputType.Format.nChannels || - wfx->nBlockAlign != OutputType.Format.nBlockAlign) + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + + if(wfx != NULL) { - ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, - wfx->nSamplesPerSec); + if(!(wfx->nChannels == OutputType.Format.nChannels || + (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || + (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) + { + ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + wfx->nSamplesPerSec); + CoTaskMemFree(wfx); + return E_FAIL; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } CoTaskMemFree(wfx); - return E_FAIL; + wfx = NULL; } - if(!MakeExtensible(&OutputType, wfx)) + if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) { - CoTaskMemFree(wfx); + if(OutputType.Format.wBitsPerSample == 8) + srcType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + srcType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtInt; + else + { + ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtFloat; + else + { + ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else + { + ERR("Unhandled format sub-type\n"); return E_FAIL; } - CoTaskMemFree(wfx); - wfx = NULL; + + if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, + device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create stereo-to-mono converter\n"); + return E_FAIL; + } + /* The channel converter always outputs float, so change the input type + * for the resampler/type-converter. + */ + srcType = DevFmtFloat; + } + else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, + device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create mono-to-stereo converter\n"); + return E_FAIL; + } + srcType = DevFmtFloat; + } + + if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) + { + self->SampleConv = CreateSampleConverter( + srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans), + OutputType.Format.nSamplesPerSec, device->Frequency + ); + if(!self->SampleConv) + { + ERR("Failed to create converter for format, dst: %s %s %uhz, src: %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, OutputType.Format.wBitsPerSample, + OutputType.Format.nSamplesPerSec); + return E_FAIL; + } + } hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, @@ -1672,7 +1799,9 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len); ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(buffer_len, OutputType.Format.nBlockAlign); + self->Ring = ll_ringbuffer_create(buffer_len, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType) + ); if(!self->Ring) { ERR("Failed to allocate capture ring buffer\n"); @@ -1851,7 +1980,7 @@ static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UN * stereo input, for example, and the app asks for 22050hz mono, * initialization will fail. */ - if(type == ALCbackend_Playback /*|| type == ALCbackend_Capture*/) + if(type == ALCbackend_Playback || type == ALCbackend_Capture) return ALC_TRUE; return ALC_FALSE; } -- cgit v1.2.3 From 05531fbee465e364fdbe5aa2c32e2c57e8f988b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Apr 2017 11:47:23 -0700 Subject: Use the correct channel conversion functions --- Alc/converter.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index ebbc0966..fa51f2f4 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -359,7 +359,7 @@ void DestroyChannelConverter(ChannelConverter **converter) #define DECL_TEMPLATE(T) \ -static void MonoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +static void Mono2Stereo##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ { \ const T *data = (T*)src; \ ALsizei i; \ @@ -368,7 +368,7 @@ static void MonoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(data[i]) * 0.707106781187f; \ } \ \ -static void StereoConvert##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ +static void Stereo2Mono##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ { \ const T *data = (T*)src; \ ALsizei i; \ @@ -402,25 +402,25 @@ void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALflo switch(converter->mSrcType) { case DevFmtByte: - MonoConvertALbyte(dst, src, frames); + Stereo2MonoALbyte(dst, src, frames); break; case DevFmtUByte: - MonoConvertALubyte(dst, src, frames); + Stereo2MonoALubyte(dst, src, frames); break; case DevFmtShort: - MonoConvertALshort(dst, src, frames); + Stereo2MonoALshort(dst, src, frames); break; case DevFmtUShort: - MonoConvertALushort(dst, src, frames); + Stereo2MonoALushort(dst, src, frames); break; case DevFmtInt: - MonoConvertALint(dst, src, frames); + Stereo2MonoALint(dst, src, frames); break; case DevFmtUInt: - MonoConvertALuint(dst, src, frames); + Stereo2MonoALuint(dst, src, frames); break; case DevFmtFloat: - MonoConvertALfloat(dst, src, frames); + Stereo2MonoALfloat(dst, src, frames); break; } } @@ -429,25 +429,25 @@ void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALflo switch(converter->mSrcType) { case DevFmtByte: - StereoConvertALbyte(dst, src, frames); + Mono2StereoALbyte(dst, src, frames); break; case DevFmtUByte: - StereoConvertALubyte(dst, src, frames); + Mono2StereoALubyte(dst, src, frames); break; case DevFmtShort: - StereoConvertALshort(dst, src, frames); + Mono2StereoALshort(dst, src, frames); break; case DevFmtUShort: - StereoConvertALushort(dst, src, frames); + Mono2StereoALushort(dst, src, frames); break; case DevFmtInt: - StereoConvertALint(dst, src, frames); + Mono2StereoALint(dst, src, frames); break; case DevFmtUInt: - StereoConvertALuint(dst, src, frames); + Mono2StereoALuint(dst, src, frames); break; case DevFmtFloat: - StereoConvertALfloat(dst, src, frames); + Mono2StereoALfloat(dst, src, frames); break; } } -- cgit v1.2.3 From 46046f9caa2f9014d70c0f8553ada6dafa16c1e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Apr 2017 12:06:57 -0700 Subject: Remove an unnecessary variable --- Alc/converter.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index fa51f2f4..38d51d47 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -361,20 +361,16 @@ void DestroyChannelConverter(ChannelConverter **converter) #define DECL_TEMPLATE(T) \ static void Mono2Stereo##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ { \ - const T *data = (T*)src; \ ALsizei i; \ - \ for(i = 0;i < frames;i++) \ - dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(data[i]) * 0.707106781187f; \ + dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f; \ } \ \ static void Stereo2Mono##T(ALfloat *restrict dst, const T *src, ALsizei frames)\ { \ - const T *data = (T*)src; \ ALsizei i; \ - \ for(i = 0;i < frames;i++) \ - dst[i] = (Sample_##T(data[i*2 + 0])+Sample_##T(data[i*2 + 1])) * \ + dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) * \ 0.707106781187f; \ } -- cgit v1.2.3 From 901804d724d49f316cd2bf51ec1cd2cd9fb9eb91 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Apr 2017 18:26:07 -0700 Subject: Store the ambisonic order separate from the channel enum --- Alc/ALc.c | 157 +++++++++++++++++------------------------ Alc/backends/alsa.c | 11 +-- Alc/backends/coreaudio.c | 8 +-- Alc/backends/dsound.c | 176 ++++++++++++++++++++++------------------------ Alc/backends/jack.c | 10 ++- Alc/backends/mmdevapi.c | 15 ++-- Alc/backends/opensl.c | 10 ++- Alc/backends/oss.c | 16 +++-- Alc/backends/portaudio.c | 4 +- Alc/backends/pulseaudio.c | 48 +++++++++++-- Alc/backends/qsa.c | 20 +++--- Alc/backends/sndio.c | 6 +- Alc/backends/solaris.c | 12 ++-- Alc/backends/wave.c | 25 ++++--- Alc/backends/winmm.c | 8 +-- Alc/converter.c | 2 +- Alc/panning.c | 31 ++++---- OpenAL32/Include/alMain.h | 13 ++-- 18 files changed, 285 insertions(+), 287 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 47bd19e4..2a636c59 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1367,14 +1367,12 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) case DevFmtX51Rear: return "5.1 Surround (Rear)"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; - case DevFmtAmbi1: return "Ambisonic (1st Order)"; - case DevFmtAmbi2: return "Ambisonic (2nd Order)"; - case DevFmtAmbi3: return "Ambisonic (3rd Order)"; + case DevFmtAmbi3D: return "Ambisonic 3D"; } return "(unknown channels)"; } -extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type); +extern inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder); ALsizei BytesFromDevFmt(enum DevFmtType type) { switch(type) @@ -1389,7 +1387,7 @@ ALsizei BytesFromDevFmt(enum DevFmtType type) } return 0; } -ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans) +ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder) { switch(chans) { @@ -1400,9 +1398,9 @@ ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans) case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; - case DevFmtAmbi1: return 4; - case DevFmtAmbi2: return 9; - case DevFmtAmbi3: return 16; + case DevFmtAmbi3D: return (ambiorder >= 3) ? 16 : + (ambiorder == 2) ? 9 : + (ambiorder == 1) ? 4 : 1; } return 0; } @@ -1585,40 +1583,32 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) device->RealOut.ChannelName[6] = SideLeft; device->RealOut.ChannelName[7] = SideRight; break; - case DevFmtAmbi1: + case DevFmtAmbi3D: device->RealOut.ChannelName[0] = Aux0; - device->RealOut.ChannelName[1] = Aux1; - device->RealOut.ChannelName[2] = Aux2; - device->RealOut.ChannelName[3] = Aux3; - break; - case DevFmtAmbi2: - device->RealOut.ChannelName[0] = Aux0; - device->RealOut.ChannelName[1] = Aux1; - device->RealOut.ChannelName[2] = Aux2; - device->RealOut.ChannelName[3] = Aux3; - device->RealOut.ChannelName[4] = Aux4; - device->RealOut.ChannelName[5] = Aux5; - device->RealOut.ChannelName[6] = Aux6; - device->RealOut.ChannelName[7] = Aux7; - device->RealOut.ChannelName[8] = Aux8; - break; - case DevFmtAmbi3: - device->RealOut.ChannelName[0] = Aux0; - device->RealOut.ChannelName[1] = Aux1; - device->RealOut.ChannelName[2] = Aux2; - device->RealOut.ChannelName[3] = Aux3; - device->RealOut.ChannelName[4] = Aux4; - device->RealOut.ChannelName[5] = Aux5; - device->RealOut.ChannelName[6] = Aux6; - device->RealOut.ChannelName[7] = Aux7; - device->RealOut.ChannelName[8] = Aux8; - device->RealOut.ChannelName[9] = Aux9; - device->RealOut.ChannelName[10] = Aux10; - device->RealOut.ChannelName[11] = Aux11; - device->RealOut.ChannelName[12] = Aux12; - device->RealOut.ChannelName[13] = Aux13; - device->RealOut.ChannelName[14] = Aux14; - device->RealOut.ChannelName[15] = Aux15; + if(device->AmbiOrder > 0) + { + device->RealOut.ChannelName[1] = Aux1; + device->RealOut.ChannelName[2] = Aux2; + device->RealOut.ChannelName[3] = Aux3; + } + if(device->AmbiOrder > 1) + { + device->RealOut.ChannelName[4] = Aux4; + device->RealOut.ChannelName[5] = Aux5; + device->RealOut.ChannelName[6] = Aux6; + device->RealOut.ChannelName[7] = Aux7; + device->RealOut.ChannelName[8] = Aux8; + } + if(device->AmbiOrder > 2) + { + device->RealOut.ChannelName[9] = Aux9; + device->RealOut.ChannelName[10] = Aux10; + device->RealOut.ChannelName[11] = Aux11; + device->RealOut.ChannelName[12] = Aux12; + device->RealOut.ChannelName[13] = Aux13; + device->RealOut.ChannelName[14] = Aux14; + device->RealOut.ChannelName[15] = Aux15; + } break; } } @@ -1661,9 +1651,7 @@ void SetDefaultChannelOrder(ALCdevice *device) case DevFmtQuad: case DevFmtX51: case DevFmtX61: - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: SetDefaultWFXChannelOrder(device); break; } @@ -1901,16 +1889,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); + device->Frequency = freq; + device->FmtChans = schans; + device->FmtType = stype; if(schans == ALC_BFORMAT3D_SOFT) { - device->FmtChans = DevFmtAmbi1 + (aorder-1); + device->AmbiOrder = aorder; device->AmbiLayout = alayout; device->AmbiScale = ascale; } - else - device->FmtChans = schans; - device->Frequency = freq; - device->FmtType = stype; device->NumMonoSources = numMono; device->NumStereoSources = numStereo; @@ -2944,8 +2931,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para static inline ALCsizei NumAttrsForDevice(ALCdevice *device) { - if(device->Type == Loopback && device->FmtChans >= DevFmtAmbi1 && - device->FmtChans <= DevFmtAmbi3) + if(device->Type == Loopback && device->FmtChans == DevFmtAmbi3D) return 23; return 17; } @@ -3060,7 +3046,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC } else { - if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; values[i++] = device->AmbiLayout; @@ -3069,17 +3055,12 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = device->AmbiScale; values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->FmtChans-DevFmtAmbi1+1; - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = ALC_BFORMAT3D_SOFT; - } - else - { - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + values[i++] = device->AmbiOrder; } + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + values[i++] = ALC_FORMAT_TYPE_SOFT; values[i++] = device->FmtType; } @@ -3133,10 +3114,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC alcSetError(device, ALC_INVALID_DEVICE); return 0; } - if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) - values[0] = ALC_BFORMAT3D_SOFT; - else - values[0] = device->FmtChans; + values[0] = device->FmtChans; return 1; case ALC_FORMAT_TYPE_SOFT: @@ -3149,8 +3127,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_AMBISONIC_LAYOUT_SOFT: - if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && - device->FmtChans <= DevFmtAmbi3)) + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) { alcSetError(device, ALC_INVALID_DEVICE); return 0; @@ -3159,8 +3136,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_AMBISONIC_SCALING_SOFT: - if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && - device->FmtChans <= DevFmtAmbi3)) + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) { alcSetError(device, ALC_INVALID_DEVICE); return 0; @@ -3169,13 +3145,12 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_AMBISONIC_ORDER_SOFT: - if(device->Type != Loopback || !(device->FmtChans >= DevFmtAmbi1 && - device->FmtChans <= DevFmtAmbi3)) + if(device->Type != Loopback || device->FmtChans != DevFmtAmbi3D) { alcSetError(device, ALC_INVALID_DEVICE); return 0; } - values[0] = device->FmtChans - DevFmtAmbi1 + 1; + values[0] = device->AmbiOrder; return 1; case ALC_MONO_SOURCES: @@ -3280,7 +3255,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, } else { - if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->FmtChans == DevFmtAmbi3D) { values[i++] = ALC_AMBISONIC_LAYOUT_SOFT; values[i++] = device->AmbiLayout; @@ -3289,17 +3264,12 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = device->AmbiScale; values[i++] = ALC_AMBISONIC_ORDER_SOFT; - values[i++] = device->FmtChans-DevFmtAmbi1+1; - - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = ALC_BFORMAT3D_SOFT; - } - else - { - values[i++] = ALC_FORMAT_CHANNELS_SOFT; - values[i++] = device->FmtChans; + values[i++] = device->AmbiOrder; } + values[i++] = ALC_FORMAT_CHANNELS_SOFT; + values[i++] = device->FmtChans; + values[i++] = ALC_FORMAT_TYPE_SOFT; values[i++] = device->FmtType; } @@ -3825,17 +3795,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) static const struct { const char name[16]; enum DevFmtChannels chans; + ALsizei order; } chanlist[] = { - { "mono", DevFmtMono }, - { "stereo", DevFmtStereo }, - { "quad", DevFmtQuad }, - { "surround51", DevFmtX51 }, - { "surround61", DevFmtX61 }, - { "surround71", DevFmtX71 }, - { "surround51rear", DevFmtX51Rear }, - { "ambi1", DevFmtAmbi1 }, - { "ambi2", DevFmtAmbi2 }, - { "ambi3", DevFmtAmbi3 }, + { "mono", DevFmtMono, 0 }, + { "stereo", DevFmtStereo, 0 }, + { "quad", DevFmtQuad, 0 }, + { "surround51", DevFmtX51, 0 }, + { "surround61", DevFmtX61, 0 }, + { "surround71", DevFmtX71, 0 }, + { "surround51rear", DevFmtX51Rear, 0 }, + { "ambi1", DevFmtAmbi3D, 1 }, + { "ambi2", DevFmtAmbi3D, 2 }, + { "ambi3", DevFmtAmbi3D, 3 }, }; size_t i; @@ -3844,6 +3815,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(strcasecmp(chanlist[i].name, fmt) == 0) { device->FmtChans = chanlist[i].chans; + device->AmbiOrder = chanlist[i].order; device->Flags |= DEVICE_CHANNELS_REQUEST; break; } @@ -4118,6 +4090,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return NULL; } device->IsHeadphones = AL_FALSE; + device->AmbiOrder = 0; device->AmbiLayout = AmbiLayout_Default; device->AmbiScale = AmbiNorm_Default; diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 4a7b81ba..40b68779 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -755,7 +755,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } 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(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0) + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, @@ -768,14 +768,15 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) for(k = 0;k < COUNTOF(channellist);k++) { - if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0) + if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0) { device->FmtChans = channellist[k]; + device->AmbiOrder = 0; break; } } } - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) || !(device->Flags&DEVICE_FREQUENCY_REQUEST)) @@ -1039,7 +1040,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) /* set format (implicitly sets sample bits) */ CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format)); /* set channels (implicitly sets frame bits) */ - CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); + CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder))); /* set rate (implicitly constrains period/buffer parameters) */ 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) */ @@ -1063,7 +1064,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { self->ring = ll_ringbuffer_create( device->UpdateSize*device->NumUpdates + 1, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) ); if(!self->ring) { diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 435c0fae..ec926d3d 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -319,7 +319,7 @@ static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) } /* setup callback */ - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); input.inputProc = ALCcoreAudioPlayback_MixerProc; input.inputProcRefCon = self; @@ -608,9 +608,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } @@ -624,7 +622,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar // save requested format description for later use self->format = requestedFormat; - self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); // Use intermediate format for sample rate conversion (outputFormat) // Set sample rate to the same as hardware for resampling later diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 3dc297ff..f730dc95 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -244,7 +244,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) return 1; } - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); FragSize = device->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL); @@ -474,9 +474,7 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) case DevFmtMono: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: @@ -529,7 +527,7 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) retry_open: hr = S_OK; OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; - OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); + OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; OutputType.Format.nSamplesPerSec = device->Frequency; @@ -736,98 +734,94 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi break; } - //DirectSoundCapture Init code - hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL); - if(SUCCEEDED(hr)) + memset(&InputType, 0, sizeof(InputType)); + switch(device->FmtChans) { - memset(&InputType, 0, sizeof(InputType)); - - switch(device->FmtChans) - { - case DevFmtMono: - InputType.dwChannelMask = SPEAKER_FRONT_CENTER; - break; - case DevFmtStereo: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT; - break; - case DevFmtQuad: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX51: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX51Rear: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; - break; - case DevFmtX61: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_CENTER | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtX71: - InputType.dwChannelMask = SPEAKER_FRONT_LEFT | - SPEAKER_FRONT_RIGHT | - SPEAKER_FRONT_CENTER | - SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; - break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: - break; - } + case DevFmtMono: + InputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX51Rear: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX61: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtAmbi3D: + WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans)); + return ALC_INVALID_ENUM; + } - InputType.Format.wFormatTag = WAVE_FORMAT_PCM; - InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); - InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; - InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; - InputType.Format.nSamplesPerSec = device->Frequency; - InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; - InputType.Format.cbSize = 0; + InputType.Format.wFormatTag = WAVE_FORMAT_PCM; + InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; + InputType.Format.nSamplesPerSec = device->Frequency; + InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; + InputType.Format.cbSize = 0; + InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; + if(device->FmtType == DevFmtFloat) + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) - { - InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; - if(device->FmtType == DevFmtFloat) - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } + if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + { + InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + } - samples = device->UpdateSize * device->NumUpdates; - samples = maxu(samples, 100 * device->Frequency / 1000); + samples = device->UpdateSize * device->NumUpdates; + samples = maxu(samples, 100 * device->Frequency / 1000); - memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); - DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); - DSCBDescription.dwFlags = 0; - DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; - DSCBDescription.lpwfxFormat = &InputType.Format; + memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); + DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); + DSCBDescription.dwFlags = 0; + DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; + DSCBDescription.lpwfxFormat = &InputType.Format; + //DirectSoundCapture Init code + hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL); + if(SUCCEEDED(hr)) hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL); - } if(SUCCEEDED(hr)) { self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, @@ -921,7 +915,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(!device->Connected) goto done; - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); BufferBytes = self->BufferBytes; LastCursor = self->Cursor; diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index cce828e9..f43f8527 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -228,7 +228,9 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType)); + self->Ring = ll_ringbuffer_create(bufsize, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + ); if(!self->Ring) { ERR("Failed to reallocate ringbuffer\n"); @@ -423,7 +425,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; - numchans = ChannelsFromDevFmt(device->FmtChans); + numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); for(i = 0;i < numchans;i++) { char name[64]; @@ -452,7 +454,9 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) } ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType)); + self->Ring = ll_ringbuffer_create(bufsize, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + ); if(!self->Ring) { ERR("Failed to allocate ringbuffer\n"); diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index a70607e4..43d8429d 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -922,9 +922,7 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.Format.nChannels = 1; OutputType.dwChannelMask = MONO; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: @@ -1367,7 +1365,8 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) } else { - size_t framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + size_t framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, + device->AmbiOrder); ALuint len1 = minu(data[0].len, numsamples); ALuint len2 = minu(data[1].len, numsamples-len1); @@ -1636,9 +1635,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) OutputType.dwChannelMask = X7DOT1; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: return E_FAIL; } switch(device->FmtType) @@ -1767,7 +1764,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) { self->SampleConv = CreateSampleConverter( - srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans), + srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), OutputType.Format.nSamplesPerSec, device->Frequency ); if(!self->SampleConv) @@ -1800,7 +1797,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len); ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) ); if(!self->Ring) { diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 41f55120..622437b8 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -65,9 +65,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: break; } return 0; @@ -513,7 +511,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) device->FmtType = DevFmtShort; SetDefaultWFXChannelOrder(device); - self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; @@ -522,7 +520,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #ifdef SL_DATAFORMAT_PCM_EX SLDataFormat_PCM_EX format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM_EX; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); format_pcm.sampleRate = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; @@ -533,7 +531,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) #else SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans); + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); format_pcm.samplesPerSec = device->Frequency * 1000; format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; format_pcm.containerSize = format_pcm.bitsPerSample; diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 6706405d..6774a789 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -280,7 +280,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr) SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCplaybackOSS_lock(self); while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) @@ -418,7 +418,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } periods = device->NumUpdates; - numChannels = ChannelsFromDevFmt(device->FmtChans); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); ossSpeed = device->Frequency; frameSize = numChannels * BytesFromDevFmt(device->FmtType); /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */ @@ -444,7 +444,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); return ALC_FALSE; @@ -471,7 +471,9 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); self->mix_data = calloc(1, self->data_size); ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); @@ -543,7 +545,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) SetRTPriority(); althrd_setname(althrd_current(), RECORD_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); while(!ATOMIC_LOAD_SEQ(&self->killNow)) { @@ -660,7 +662,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } periods = 4; - numChannels = ChannelsFromDevFmt(device->FmtChans); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); frameSize = numChannels * BytesFromDevFmt(device->FmtType); ossSpeed = device->Frequency; log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates * @@ -690,7 +692,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) } #undef CHECKERR - if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels) { ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); close(self->fd); diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index b713f330..807e8000 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -399,7 +399,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); self->ring = ll_ringbuffer_create(samples, frame_size); if(self->ring == NULL) return ALC_INVALID_VALUE; @@ -433,7 +433,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); return ALC_INVALID_VALUE; } - self->params.channelCount = ChannelsFromDevFmt(device->FmtChans); + self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); err = Pa_OpenStream(&self->stream, &self->params, NULL, device->Frequency, paFramesPerBufferUnspecified, paNoFlag, diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 26557ea8..9e2d4f73 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1014,7 +1014,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) break; } self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans); + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); if(pa_sample_spec_valid(&self->spec) == 0) { @@ -1028,9 +1028,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) case DevFmtMono: mapname = "mono"; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: device->FmtChans = DevFmtStereo; /*fall-through*/ case DevFmtStereo: @@ -1464,6 +1462,7 @@ 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; + const char *mapname = NULL; pa_channel_map chanmap; ALuint samples; @@ -1488,9 +1487,6 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) pa_threaded_mainloop_lock(self->loop); - self->spec.rate = device->Frequency; - self->spec.channels = ChannelsFromDevFmt(device->FmtChans); - switch(device->FmtType) { case DevFmtUByte: @@ -1513,6 +1509,44 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) goto fail; } + switch(device->FmtChans) + { + 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,side-left,side-right"; + break; + case DevFmtX51Rear: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-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; + case DevFmtAmbi3D: + ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); + pa_threaded_mainloop_unlock(self->loop); + goto fail; + } + 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; + } + + self->spec.rate = device->Frequency; + self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + if(pa_sample_spec_valid(&self->spec) == 0) { ERR("Invalid sample format\n"); diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 9563a918..9da55b59 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -179,7 +179,9 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr) param.sched_priority=param.sched_curpriority+1; SchedSet(0, 0, SCHED_NOCHANGE, ¶m); - const ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + const ALint frame_size = FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); V0(device->Backend,lock)(); while(!data->killNow) @@ -361,14 +363,14 @@ static ALCboolean qsa_reset_playback(ALCdevice* device) 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.frag_size=device->UpdateSize * + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); 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.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); data->cparams.format.format=format; if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) @@ -552,7 +554,7 @@ static ALCboolean qsa_reset_playback(ALCdevice* device) SetDefaultChannelOrder(device); device->UpdateSize=data->csetup.buf.block.frag_size/ - (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType)); + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); device->NumUpdates=data->csetup.buf.block.frags; data->size=data->csetup.buf.block.frag_size; @@ -684,13 +686,13 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) data->cparams.stop_mode=SND_PCM_STOP_STOP; data->cparams.buf.block.frag_size=device->UpdateSize* - ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType); + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); 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.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); data->cparams.format.format=format; if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) @@ -749,7 +751,7 @@ 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 frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALint free_size; int rstatus; @@ -785,7 +787,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s int selectret; struct timeval timeout; int bytes_read; - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALint len=samples*frame_size; int rstatus; diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index ac2dc03f..47e05353 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -98,7 +98,7 @@ static int ALCsndioBackend_mixerProc(void *ptr) SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); while(!self->killNow && device->Connected) { @@ -245,7 +245,9 @@ static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); al_free(self->mix_data); self->mix_data = al_calloc(16, self->data_size); diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 98c00525..5b3f6136 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -116,7 +116,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCsolarisBackend_lock(self); while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) @@ -209,7 +209,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) if(device->FmtChans != DevFmtMono) device->FmtChans = DevFmtStereo; - numChannels = ChannelsFromDevFmt(device->FmtChans); + numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); info.play.channels = numChannels; switch(device->FmtType) @@ -243,9 +243,9 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) return ALC_FALSE; } - if(ChannelsFromDevFmt(device->FmtChans) != (ALsizei)info.play.channels) + if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels) { - ERR("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels); + ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels); return ALC_FALSE; } @@ -265,7 +265,9 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) SetDefaultChannelOrder(device); free(self->mix_data); - self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); self->mix_data = calloc(1, self->data_size); return ALC_TRUE; diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 36d7cbca..c72a632b 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -127,7 +127,7 @@ static int ALCwaveBackend_mixerProc(void *ptr) althrd_setname(althrd_current(), MIXER_THREAD_NAME); - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); done = 0; if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) @@ -251,7 +251,10 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) clearerr(self->mFile); if(GetConfigValueBool(NULL, "wave", "bformat", 0)) - device->FmtChans = DevFmtAmbi1; + { + device->FmtChans = DevFmtAmbi3D; + device->AmbiOrder = 1; + } switch(device->FmtType) { @@ -279,9 +282,7 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: /* .amb output requires FuMa */ device->AmbiLayout = AmbiLayout_FuMa; device->AmbiScale = AmbiNorm_FuMa; @@ -290,14 +291,14 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) break; } bits = BytesFromDevFmt(device->FmtType) * 8; - channels = ChannelsFromDevFmt(device->FmtChans); + channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); - fprintf(self->mFile, "RIFF"); + fputs("RIFF", self->mFile); fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close - fprintf(self->mFile, "WAVE"); + fputs("WAVE", self->mFile); - fprintf(self->mFile, "fmt "); + fputs("fmt ", self->mFile); fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) @@ -323,7 +324,7 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile); (void)val; - fprintf(self->mFile, "data"); + fputs("data", self->mFile); fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close if(ferror(self->mFile)) @@ -342,7 +343,9 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->mSize = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); self->mBuffer = malloc(self->mSize); if(!self->mBuffer) { diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index da0d67a1..b5b3cdb6 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -382,7 +382,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) // Create 4 Buffers BufferSize = device->UpdateSize*device->NumUpdates / 4; - BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); BufferData = calloc(4, BufferSize); for(i = 0;i < 4;i++) @@ -563,9 +563,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: return ALC_INVALID_ENUM; } @@ -586,7 +584,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) memset(&self->Format, 0, sizeof(WAVEFORMATEX)); self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); - self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans); + self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; diff --git a/Alc/converter.c b/Alc/converter.c index 38d51d47..56af8ff0 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -389,7 +389,7 @@ void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALflo if(converter->mSrcChans == converter->mDstChans) { LoadSamples(dst, src, 1, converter->mSrcType, - frames*ChannelsFromDevFmt(converter->mSrcChans)); + frames*ChannelsFromDevFmt(converter->mSrcChans, 0)); return; } diff --git a/Alc/panning.c b/Alc/panning.c index dcdcf36d..e4941720 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -620,13 +620,11 @@ static void InitPanning(ALCdevice *device) coeffcount = 16; break; - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: break; } - if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->FmtChans == DevFmtAmbi3D) { const char *devname = alstr_get_cstr(device->DeviceName); const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; @@ -635,9 +633,9 @@ static void InitPanning(ALCdevice *device) /*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale; ALfloat nfc_delay = 0.0f; - count = (device->FmtChans == DevFmtAmbi3) ? 16 : - (device->FmtChans == DevFmtAmbi2) ? 9 : - (device->FmtChans == DevFmtAmbi1) ? 4 : 1; + count = (device->AmbiOrder == 3) ? 16 : + (device->AmbiOrder == 2) ? 9 : + (device->AmbiOrder == 1) ? 4 : 1; for(i = 0;i < count;i++) { ALsizei acn = acnmap[i]; @@ -647,7 +645,7 @@ static void InitPanning(ALCdevice *device) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - if(device->FmtChans == DevFmtAmbi1) + if(device->AmbiOrder < 2) { device->FOAOut.Ambi = device->Dry.Ambi; device->FOAOut.CoeffCount = device->Dry.CoeffCount; @@ -674,10 +672,7 @@ static void InitPanning(ALCdevice *device) { nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - (device->FmtChans == DevFmtAmbi3) ? 3 : - (device->FmtChans == DevFmtAmbi2) ? 2 : 1, - true - ); + device->AmbiOrder, true); } } else @@ -861,7 +856,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz device->FOAOut.NumChannels = count; } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); avg_dist = 0.0f; for(i = 0;i < conf->NumSpeakers;i++) @@ -963,7 +958,7 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) ambiup_reset(device->AmbiUp, device); } - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); device->Hrtf->IrSize = BuildBFormatHrtf(device->HrtfHandle, device->Hrtf, device->Dry.NumChannels, @@ -992,7 +987,7 @@ static void InitUhjPanning(ALCdevice *device) device->FOAOut.CoeffCount = device->Dry.CoeffCount; device->FOAOut.NumChannels = 0; - device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans); + device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); } void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) @@ -1049,9 +1044,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ case DevFmtMono: case DevFmtStereo: - case DevFmtAmbi1: - case DevFmtAmbi2: - case DevFmtAmbi3: + case DevFmtAmbi3D: break; } if(layout) @@ -1085,7 +1078,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; - if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3) + if(device->FmtChans == DevFmtAmbi3D && device->AmbiOrder == 1) { if(!device->AmbiUp) device->AmbiUp = ambiup_alloc(); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1919a257..fc2c5e8f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -508,24 +508,20 @@ enum DevFmtChannels { DevFmtX51 = ALC_5POINT1_SOFT, DevFmtX61 = ALC_6POINT1_SOFT, DevFmtX71 = ALC_7POINT1_SOFT, + DevFmtAmbi3D = ALC_BFORMAT3D_SOFT, /* Similar to 5.1, except using rear channels instead of sides */ DevFmtX51Rear = 0x80000000, - /* Ambisonic formats should be kept together */ - DevFmtAmbi1, - DevFmtAmbi2, - DevFmtAmbi3, - DevFmtChannelsDefault = DevFmtStereo }; #define MAX_OUTPUT_CHANNELS (16) ALsizei BytesFromDevFmt(enum DevFmtType type); -ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans); -inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type) +ALsizei ChannelsFromDevFmt(enum DevFmtChannels chans, ALsizei ambiorder); +inline ALsizei FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type, ALsizei ambiorder) { - return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); + return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); } enum AmbiLayout { @@ -668,6 +664,7 @@ struct ALCdevice_struct enum DevFmtChannels FmtChans; enum DevFmtType FmtType; ALboolean IsHeadphones; + ALsizei AmbiOrder; /* For DevFmtAmbi* output only, specifies the channel order and * normalization. */ -- cgit v1.2.3 From 684823ebc4c65957d85b79f0d8ac8b2afe9160bb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Apr 2017 22:44:16 -0700 Subject: Select NEON when available before SSE --- Alc/ALu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9e2b041f..7e3eb99a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -102,14 +102,14 @@ const aluMatrixf IdentityMatrixf = {{ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) { -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixDirectHrtf_SSE; -#endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return MixDirectHrtf_Neon; #endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixDirectHrtf_SSE; +#endif return MixDirectHrtf_C; } -- cgit v1.2.3 From 24c172bb96b8a1379e9d37c8c33dbbb7c94f8e61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Apr 2017 22:45:54 -0700 Subject: Use ALsizei for the fir4 resampler fraction --- Alc/ALu.c | 2 +- OpenAL32/Include/alu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 7e3eb99a..4f41d012 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -80,7 +80,7 @@ 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 resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac); +extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei frac); extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 51c43d85..6c3f3499 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -295,7 +295,7 @@ inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) { return val1 + (val2-val1)*mu; } -inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac) +inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei frac) { return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 + sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3; -- cgit v1.2.3 From 6476f3277ae94d034f8bf21fba66473b71bcf3a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Apr 2017 11:48:43 -0700 Subject: Mark some pointers with restrict --- Alc/converter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index 56af8ff0..99069d15 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -65,7 +65,8 @@ static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\ +static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ + ALint srcstep, ALsizei samples) \ { \ ALsizei i; \ for(i = 0;i < samples;i++) \ @@ -130,7 +131,8 @@ static inline ALfloat ALfloat_Sample(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static inline void Store_##T(T *dst, const ALfloat *src, ALint dststep, ALsizei samples)\ +static inline void Store_##T(T *restrict dst, const ALfloat *restrict src, \ + ALint dststep, ALsizei samples) \ { \ ALsizei i; \ for(i = 0;i < samples;i++) \ -- cgit v1.2.3 From 9e60eea93b029f1c2d2e394e2352b86cd7c65d12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Apr 2017 15:29:30 -0700 Subject: Use atomic flags for the thunk array --- OpenAL32/alThunk.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c index d3892c97..0d90760a 100644 --- a/OpenAL32/alThunk.c +++ b/OpenAL32/alThunk.c @@ -28,8 +28,8 @@ #include "almalloc.h" -static ATOMIC(ALenum) *ThunkArray; -static ALuint ThunkArraySize; +static ATOMIC_FLAG *ThunkArray; +static ALsizei ThunkArraySize; static RWLock ThunkLock; void ThunkInit(void) @@ -49,12 +49,12 @@ void ThunkExit(void) ALenum NewThunkEntry(ALuint *index) { void *NewList; - ALuint i; + ALsizei i; ReadLock(&ThunkLock); for(i = 0;i < ThunkArraySize;i++) { - if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE, almemory_order_acq_rel) == AL_FALSE) + if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel)) { ReadUnlock(&ThunkLock); *index = i+1; @@ -69,7 +69,7 @@ ALenum NewThunkEntry(ALuint *index) */ for(;i < ThunkArraySize;i++) { - if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE, almemory_order_acq_rel) == AL_FALSE) + if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel)) { WriteUnlock(&ThunkLock); *index = i+1; @@ -89,17 +89,20 @@ ALenum NewThunkEntry(ALuint *index) ThunkArray = NewList; ThunkArraySize *= 2; - ATOMIC_STORE_SEQ(&ThunkArray[i], AL_TRUE); + ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_seq_cst); + *index = ++i; + + for(;i < ThunkArraySize;i++) + ATOMIC_FLAG_CLEAR(&ThunkArray[i], almemory_order_relaxed); WriteUnlock(&ThunkLock); - *index = i+1; return AL_NO_ERROR; } void FreeThunkEntry(ALuint index) { ReadLock(&ThunkLock); - if(index > 0 && index <= ThunkArraySize) - ATOMIC_STORE_SEQ(&ThunkArray[index-1], AL_FALSE); + if(index > 0 && (ALsizei)index <= ThunkArraySize) + ATOMIC_FLAG_CLEAR(&ThunkArray[index-1], almemory_order_release); ReadUnlock(&ThunkLock); } -- cgit v1.2.3 From f94fa5d5cfb78ab5438a53b2ad17f033660103c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Apr 2017 17:47:55 -0700 Subject: Use separate atomic macros for pointers --- Alc/ALc.c | 36 ++++++------ Alc/ALu.c | 12 ++-- Alc/backends/opensl.c | 4 +- Alc/backends/oss.c | 4 +- Alc/backends/solaris.c | 2 +- Alc/helpers.c | 4 +- OpenAL32/alAuxEffectSlot.c | 18 +++--- OpenAL32/alError.c | 4 +- OpenAL32/alListener.c | 7 +-- OpenAL32/alSource.c | 19 +++---- include/atomic.h | 133 ++++++++++++++++++++++++++++----------------- 11 files changed, 135 insertions(+), 108 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2a636c59..cc9aa5c3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1247,7 +1247,7 @@ static void alc_cleanup(void) free(alcCaptureDefaultDeviceSpecifier); alcCaptureDefaultDeviceSpecifier = NULL; - if((dev=ATOMIC_EXCHANGE_SEQ(ALCdevice*, &DeviceList, NULL)) != NULL) + if((dev=ATOMIC_EXCHANGE_PTR_SEQ(&DeviceList, NULL)) != NULL) { ALCuint num = 0; do { @@ -1678,7 +1678,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) void ALCcontext_ProcessUpdates(ALCcontext *context) { ReadLock(&context->PropLock); - if(ATOMIC_EXCHANGE_SEQ(ALenum, &context->DeferUpdates, AL_FALSE)) + if(ATOMIC_EXCHANGE_SEQ(&context->DeferUpdates, AL_FALSE)) { /* Tell the mixer to stop applying updates, then wait for any active * updating to finish, before providing updates. @@ -2225,11 +2225,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * number of auxiliary sends changed. Playing (or paused) sources * will have updates respecified in UpdateAllSourceProps. */ - props = ATOMIC_EXCHANGE_SEQ(struct ALsourceProps*, &source->Update, NULL); + props = ATOMIC_EXCHANGE_PTR_SEQ(&source->Update, NULL); al_free(props); - props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->FreeList, NULL, - almemory_order_relaxed); + props = ATOMIC_EXCHANGE_PTR(&source->FreeList, NULL, almemory_order_relaxed); while(props) { struct ALsourceProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); @@ -2489,8 +2488,7 @@ static void FreeContext(ALCcontext *context) TRACE("%p\n", context); - auxslots = ATOMIC_EXCHANGE(struct ALeffectslotArray*, &context->ActiveAuxSlots, - NULL, almemory_order_relaxed); + auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, NULL, almemory_order_relaxed); al_free(auxslots); if(context->SourceMap.size > 0) @@ -2557,13 +2555,13 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) } origctx = context; - if(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &GlobalContext, &origctx, NULL)) + if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, NULL)) ALCcontext_DecRef(context); ALCdevice_Lock(device); origctx = context; newhead = context->next; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCcontext*, &device->ContextList, &origctx, newhead)) + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) { ALCcontext *volatile*list = &origctx->next; while(*list) @@ -2750,11 +2748,11 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) if(VerifyDevice(&device)) { - errorCode = ATOMIC_EXCHANGE_SEQ(ALCenum, &device->LastError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(&device->LastError, ALC_NO_ERROR); ALCdevice_DecRef(device); } else - errorCode = ATOMIC_EXCHANGE_SEQ(ALCenum, &LastNullDeviceError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(&LastNullDeviceError, ALC_NO_ERROR); return errorCode; } @@ -3549,8 +3547,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); do { ALContext->next = head; - } while(ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCcontext*, - &device->ContextList, &head, ALContext) == 0); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&device->ContextList, &head, + ALContext) == 0); } almtx_unlock(&device->BackendLock); @@ -3628,7 +3626,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) return ALC_FALSE; } /* context's reference count is already incremented */ - context = ATOMIC_EXCHANGE_SEQ(ALCcontext*, &GlobalContext, context); + context = ATOMIC_EXCHANGE_PTR_SEQ(&GlobalContext, context); if(context) ALCcontext_DecRef(context); if((context=altss_get(LocalContext)) != NULL) @@ -3937,7 +3935,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); @@ -3968,7 +3966,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) almtx_lock(&device->BackendLock); origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCdevice*, &DeviceList, &origdev, device->next)) + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, device->next)) { ALCdevice *volatile*list = &origdev->next; while(*list) @@ -4113,7 +4111,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } TRACE("Created device %p, \"%s\"\n", device, alstr_get_cstr(device->DeviceName)); @@ -4138,7 +4136,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALCdevice*, &DeviceList, &origdev, device->next)) + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, device->next)) { ALCdevice *volatile*list = &origdev->next; while(*list) @@ -4334,7 +4332,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { device->next = head; - } while(!ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(ALCdevice*, &DeviceList, &head, device)); + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } TRACE("Created device %p\n", device); diff --git a/Alc/ALu.c b/Alc/ALu.c index 4f41d012..89689fba 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -241,7 +241,7 @@ static ALboolean CalcListenerParams(ALCcontext *Context) struct ALlistenerProps *props; aluVector vel; - props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &Listener->Update, NULL, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&Listener->Update, NULL, almemory_order_acq_rel); if(!props) return AL_FALSE; /* AT then UP */ @@ -291,7 +291,7 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) struct ALeffectslotProps *props; ALeffectState *state; - props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, NULL, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&slot->Update, NULL, almemory_order_acq_rel); if(!props) return AL_FALSE; slot->Params.Gain = props->Gain; @@ -1252,7 +1252,7 @@ static void CalcSourceParams(ALvoice *voice, ALsource *source, ALCcontext *conte const ALbufferlistitem *BufferListItem; struct ALsourceProps *props; - props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, NULL, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&source->Update, NULL, almemory_order_acq_rel); if(!props && !force) return; if(props) @@ -1607,14 +1607,14 @@ void aluHandleDisconnect(ALCdevice *device) voice_end = voice + Context->VoiceCount; while(voice != voice_end) { - ALsource *source = ATOMIC_EXCHANGE(ALsource*, &(*voice)->Source, NULL, - almemory_order_acq_rel); + ALsource *source = ATOMIC_EXCHANGE_PTR(&(*voice)->Source, NULL, + almemory_order_acq_rel); ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release); if(source) { ALenum playing = AL_PLAYING; - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &source->state, &playing, AL_STOPPED); + (void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&source->state, &playing, AL_STOPPED)); } voice++; diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 622437b8..4e295f23 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -149,7 +149,7 @@ typedef struct ALCopenslPlayback { ALsizei mFrameSize; - ATOMIC(ALboolean) mKillNow; + ATOMIC(ALenum) mKillNow; althrd_t mThread; } ALCopenslPlayback; @@ -637,7 +637,7 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) SLresult result; int res; - if(ATOMIC_EXCHANGE_SEQ(ALboolean, &self->mKillNow, AL_TRUE)) + if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) return; /* Lock the backend to ensure we don't flag the mixer to die and signal the diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 6774a789..33ea55eb 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -491,7 +491,7 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self) { int res; - if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE)) + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) return; althrd_join(self->thread, &res); @@ -745,7 +745,7 @@ static void ALCcaptureOSS_stop(ALCcaptureOSS *self) { int res; - if(ATOMIC_EXCHANGE_SEQ(ALenum, &self->killNow, AL_TRUE)) + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) return; althrd_join(self->thread, &res); diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 5b3f6136..5dfb5084 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -285,7 +285,7 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { int res; - if(ATOMIC_EXCHANGE_SEQ(int, &self->killNow, AL_TRUE)) + if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE)) return; althrd_join(self->thread, &res); diff --git a/Alc/helpers.c b/Alc/helpers.c index 5d23c3a7..8e685c75 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -564,7 +564,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) vector_al_string results = VECTOR_INIT_STATIC(); size_t i; - while(ATOMIC_EXCHANGE_SEQ(uint, &search_lock, 1) == 1) + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) althrd_yield(); /* If the path is absolute, use it directly. */ @@ -840,7 +840,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); - while(ATOMIC_EXCHANGE_SEQ(uint, &search_lock, 1) == 1) + while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1) althrd_yield(); if(subdir[0] == '/') diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 743fac14..de7de943 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -126,9 +126,8 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(curarray) memcpy(newarray->slot+n, curarray->slot, sizeof(ALeffectslot*)*curarray->count); - newarray = ATOMIC_EXCHANGE(struct ALeffectslotArray*, - &context->ActiveAuxSlots, newarray, almemory_order_acq_rel - ); + newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, + almemory_order_acq_rel); device = context->Device; while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); @@ -187,9 +186,8 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * newarray->slot[i++] = slot; } - newarray = ATOMIC_EXCHANGE(struct ALeffectslotArray*, - &context->ActiveAuxSlots, newarray, almemory_order_acq_rel - ); + newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, + almemory_order_acq_rel); device = context->Device; while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); @@ -668,9 +666,8 @@ void UpdateEffectSlotProps(ALeffectslot *slot) struct ALeffectslotProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALeffectslotProps*, - &slot->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_acquire) == 0); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&slot->FreeList, &props, next, + almemory_order_seq_cst, almemory_order_acquire) == 0); } /* Copy in current property values. */ @@ -687,8 +684,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot) props->State = slot->Effect.State; /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(struct ALeffectslotProps*, &slot->Update, props, - almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&slot->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index 19fcaa6d..6c953977 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -49,7 +49,7 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode) #endif } - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALenum, &Context->LastError, &curerr, errorCode); + (void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&Context->LastError, &curerr, errorCode)); } AL_API ALenum AL_APIENTRY alGetError(void) @@ -74,7 +74,7 @@ AL_API ALenum AL_APIENTRY alGetError(void) return AL_INVALID_OPERATION; } - errorCode = ATOMIC_EXCHANGE_SEQ(ALenum, &Context->LastError, AL_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(&Context->LastError, AL_NO_ERROR); ALCcontext_DecRef(Context); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index e3d71435..d117c0ca 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -468,9 +468,8 @@ void UpdateListenerProps(ALCcontext *context) struct ALlistenerProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALlistenerProps*, - &listener->FreeList, &props, next, almemory_order_seq_cst, - almemory_order_acquire) == 0); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&listener->FreeList, &props, next, + almemory_order_seq_cst, almemory_order_acquire) == 0); } /* Copy in current property values. */ @@ -500,7 +499,7 @@ void UpdateListenerProps(ALCcontext *context) props->DistanceModel = context->DistanceModel;; /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(struct ALlistenerProps*, &listener->Update, props, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&listener->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a8c4ce2f..040078df 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -158,7 +158,7 @@ static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) if(!voice) { ALenum state = AL_PLAYING; - if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &source->state, &state, AL_STOPPED, + if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED, almemory_order_acq_rel, almemory_order_acquire)) return AL_STOPPED; return state; @@ -747,7 +747,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->SourceType = AL_UNDETERMINED; newlist = NULL; } - oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist); + oldlist = ATOMIC_EXCHANGE_PTR_SEQ(&Source->queue, newlist); WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -2784,8 +2784,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu source->SourceType = AL_STREAMING; BufferList = NULL; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->queue, - &BufferList, BufferListStart)) + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&source->queue, &BufferList, + BufferListStart)) { /* Queue head is not NULL, append to the end of the queue */ while(BufferList->next != NULL) @@ -2854,7 +2854,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Swap it, and cut the new head from the old. */ - OldHead = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, OldTail->next); + OldHead = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, OldTail->next); if(OldTail->next) { ALCdevice *device = context->Device; @@ -3003,7 +3003,7 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) if(count > 3) WARN("Freed "SZFMT" Source property objects\n", count); - BufferList = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &source->queue, NULL); + BufferList = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, NULL); while(BufferList != NULL) { ALbufferlistitem *next = BufferList->next; @@ -3040,9 +3040,8 @@ static void UpdateSourceProps(ALsource *source, ALsizei num_sends) struct ALsourceProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(struct ALsourceProps*, - &source->FreeList, &props, next, almemory_order_acq_rel, - almemory_order_acquire) == 0); + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&source->FreeList, &props, next, + almemory_order_acq_rel, almemory_order_acquire) == 0); } /* Copy in current property values. */ @@ -3103,7 +3102,7 @@ static void UpdateSourceProps(ALsource *source, ALsizei num_sends) } /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE(struct ALsourceProps*, &source->Update, props, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&source->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the diff --git a/include/atomic.h b/include/atomic.h index 57609c33..a42cfa4a 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -34,10 +34,10 @@ extern "C" { #define ATOMIC_ADD(_val, _incr, _MO) atomic_fetch_add_explicit(_val, _incr, _MO) #define ATOMIC_SUB(_val, _decr, _MO) atomic_fetch_sub_explicit(_val, _decr, _MO) -#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) atomic_exchange_explicit(_val, _newval, _MO) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _orig, _newval, _MO1, _MO2) \ +#define ATOMIC_EXCHANGE(_val, _newval, _MO) atomic_exchange_explicit(_val, _newval, _MO) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _orig, _newval, _MO1, _MO2) \ atomic_compare_exchange_strong_explicit(_val, _orig, _newval, _MO1, _MO2) -#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _orig, _newval, _MO1, _MO2) \ +#define ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _orig, _newval, _MO1, _MO2) \ atomic_compare_exchange_weak_explicit(_val, _orig, _newval, _MO1, _MO2) #define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) atomic_flag_test_and_set_explicit(_val, _MO) @@ -77,14 +77,12 @@ enum almemory_order { #define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr)) #define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr)) -#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) __extension__({ \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ +#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ __asm__ __volatile__("" ::: "memory"); \ __sync_lock_test_and_set(&(_val)->value, (_newval)); \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - T _o = *(_oldval); \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + __typeof(*(_oldval)) _o = *(_oldval); \ *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ *(_oldval) == _o; \ }) @@ -175,20 +173,29 @@ enum almemory_order { _r; \ }) -#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) __extension__({ \ - static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - T _r; \ - if(sizeof(T) == 4) WRAP_XCHG("l", _r, &(_val)->value, (T)(_newval)); \ - else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \ +#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ + __typeof((_val)->value) _r; \ + if(sizeof((_val)->value) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ + else if(sizeof((_val)->value) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval)); \ _r; \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ - static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ - T _old = *(_oldval); \ - if(sizeof(T) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (T)(_newval)); \ - else if(sizeof(T) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (T)(_newval)); \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + __typeof(*(_oldval)) _old = *(_oldval); \ + if(sizeof((_val)->value) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ + else if(sizeof((_val)->value) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ + *(_oldval) == _old; \ +}) + +#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) __extension__({ \ + void *_r; \ + if(sizeof(void*) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ + else if(sizeof(void*) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval));\ + _r; \ +}) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + void *_old = *(_oldval); \ + if(sizeof(void*) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ + else if(sizeof(void*) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ *(_oldval) == _old; \ }) @@ -205,14 +212,13 @@ enum almemory_order { #define WIN32_LEAN_AND_MEAN #include -/* NOTE: This mess is *extremely* noisy, at least on GCC. It works by wrapping - * Windows' 32-bit and 64-bit atomic methods, which are then casted to use the - * given type based on its size (e.g. int and float use 32-bit atomics). This - * is fine for the swap and compare-and-swap methods, although the add and - * subtract methods only work properly for integer types. +/* NOTE: This mess is *extremely* touchy. It lacks quite a bit of safety + * checking due to the lack of multi-statement expressions, typeof(), and C99 + * compound literals. It is incapable of properly exchanging floats, which get + * casted to LONG/int, and could cast away potential warnings. * - * Despite how noisy it is, it's unfortunately the only way that doesn't rely - * on C99 (damn MSVC). + * Unfortunately, it's the only semi-safe way that doesn't rely on C99 (because + * MSVC). */ inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) @@ -240,6 +246,10 @@ inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval) { return InterlockedExchange64(dest, newval); } +inline void *AtomicSwapPtr(void *volatile *dest, void *newval) +{ + return InterlockedExchangePointer(dest, newval); +} inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval) { @@ -253,10 +263,16 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval = InterlockedCompareExchange64(dest, newval, *oldval); return old == *oldval; } +inline bool CompareAndSwapPtr(void *volatile *dest, void *newval, void **oldval) +{ + void *old = *oldval; + *oldval = InterlockedCompareExchangePointer(dest, newval, *oldval); + return old == *oldval; +} #define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt)) -#define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval)) -#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval)) +#define WRAP_XCHG(T, _func, _ptr, _newval) _func((T volatile*)(_ptr), (_newval)) +#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) _func((T volatile*)(_ptr), (_newval), (T*)(_oldval)) enum almemory_order { @@ -289,13 +305,20 @@ int _al_invalid_atomic_size(); /* not defined */ (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ _al_invalid_atomic_size()) -#define ATOMIC_EXCHANGE(T, _val, _newval, _MO) \ - ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \ - (sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \ - (T)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, _MO1, _MO2) \ - ((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ - (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ +#define ATOMIC_EXCHANGE(_val, _newval, _MO) \ + ((sizeof((_val)->value)==4) ? WRAP_XCHG(LONG, AtomicSwap32, &(_val)->value, (_newval)) : \ + (sizeof((_val)->value)==8) ? WRAP_XCHG(LONGLONG, AtomicSwap64, &(_val)->value, (_newval)) : \ + (LONG)_al_invalid_atomic_size()) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) \ + ((sizeof((_val)->value)==4) ? WRAP_CMPXCHG(LONG, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ + (sizeof((_val)->value)==8) ? WRAP_CMPXCHG(LONGLONG, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ + (bool)_al_invalid_atomic_size()) + +#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \ + ((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \ + (void*)_al_invalid_atomic_size()) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\ + ((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \ (bool)_al_invalid_atomic_size()) #define ATOMIC_THREAD_FENCE(order) do { \ @@ -320,21 +343,27 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_ADD(...) (0) #define ATOMIC_SUB(...) (0) -#define ATOMIC_EXCHANGE(T, ...) (0) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) (0) -#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) (0) - -#define ATOMIC_FLAG_TEST_AND_SET(...) (0) -#define ATOMIC_FLAG_CLEAR(...) ((void)0) +#define ATOMIC_EXCHANGE(...) (0) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(...) (0) #define ATOMIC_THREAD_FENCE(...) ((void)0) #endif +/* If no PTR xchg variants are provided, the normal ones can handle it. */ +#ifndef ATOMIC_EXCHANGE_PTR +#define ATOMIC_EXCHANGE_PTR ATOMIC_EXCHANGE +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG ATOMIC_COMPARE_EXCHANGE_STRONG +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK +#endif + /* If no weak cmpxchg is provided (not all systems will have one), substitute a * strong cmpxchg. */ #ifndef ATOMIC_COMPARE_EXCHANGE_WEAK #define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG #endif +#ifndef ATOMIC_COMPARE_EXCHANGE_PTR_WEAK +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG +#endif /* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange * and store ops. @@ -342,7 +371,7 @@ int _al_invalid_atomic_size(); /* not defined */ #ifndef ATOMIC_FLAG #define ATOMIC_FLAG ATOMIC(int) #define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(int, _val, 1, _MO) +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(_val, 1, _MO) #define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO) #endif @@ -353,11 +382,17 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) #define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) -#define ATOMIC_EXCHANGE_SEQ(T, _val, _newval) ATOMIC_EXCHANGE(T, _val, _newval, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(T, _val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(T, _val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_EXCHANGE_SEQ(_val, _newval) ATOMIC_EXCHANGE(_val, _newval, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) + +#define ATOMIC_EXCHANGE_PTR_SEQ(_val, _newval) ATOMIC_EXCHANGE_PTR(_val, _newval, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) typedef unsigned int uint; @@ -381,7 +416,7 @@ inline uint DecrementRef(RefCount *ptr) T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ do { \ ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ - } while(ATOMIC_COMPARE_EXCHANGE_WEAK(T, _head, &_first, _entry, \ + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_head, &_first, _entry, \ almemory_order_acq_rel, almemory_order_acquire) == 0); \ } while(0) -- cgit v1.2.3 From c5310d2e953c44eb33aa9bfa913e62adf11f20fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Apr 2017 17:55:23 -0700 Subject: Avoid unnecessary macro parameters --- include/atomic.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/include/atomic.h b/include/atomic.h index a42cfa4a..874d510d 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -24,24 +24,22 @@ extern "C" { #define ATOMIC(T) T _Atomic #define ATOMIC_FLAG atomic_flag -#define ATOMIC_INIT(_val, _newval) atomic_init((_val), (_newval)) -#define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval) +#define ATOMIC_INIT atomic_init +#define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT /*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ -#define ATOMIC_LOAD(_val, _MO) atomic_load_explicit(_val, _MO) -#define ATOMIC_STORE(_val, _newval, _MO) atomic_store_explicit(_val, _newval, _MO) +#define ATOMIC_LOAD atomic_load_explicit +#define ATOMIC_STORE atomic_store_explicit -#define ATOMIC_ADD(_val, _incr, _MO) atomic_fetch_add_explicit(_val, _incr, _MO) -#define ATOMIC_SUB(_val, _decr, _MO) atomic_fetch_sub_explicit(_val, _decr, _MO) +#define ATOMIC_ADD atomic_fetch_add_explicit +#define ATOMIC_SUB atomic_fetch_sub_explicit -#define ATOMIC_EXCHANGE(_val, _newval, _MO) atomic_exchange_explicit(_val, _newval, _MO) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _orig, _newval, _MO1, _MO2) \ - atomic_compare_exchange_strong_explicit(_val, _orig, _newval, _MO1, _MO2) -#define ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _orig, _newval, _MO1, _MO2) \ - atomic_compare_exchange_weak_explicit(_val, _orig, _newval, _MO1, _MO2) +#define ATOMIC_EXCHANGE atomic_exchange_explicit +#define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit +#define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) atomic_flag_test_and_set_explicit(_val, _MO) -#define ATOMIC_FLAG_CLEAR(_val, _MO) atomic_flag_clear_explicit(_val, _MO) +#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set_explicit +#define ATOMIC_FLAG_CLEAR atomic_flag_clear_explicit #define ATOMIC_THREAD_FENCE atomic_thread_fence -- cgit v1.2.3 From afb59e7f98f40cde77c150414a8a5bd13f40781a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Apr 2017 18:15:56 -0700 Subject: Move internal headers out of the include directory --- CMakeLists.txt | 2 +- common/align.h | 21 +++ common/almalloc.h | 21 +++ common/atomic.h | 425 ++++++++++++++++++++++++++++++++++++++++++++++++ common/bool.h | 18 ++ common/math_defs.h | 19 +++ common/rwlock.h | 31 ++++ common/static_assert.h | 21 +++ common/threads.h | 237 +++++++++++++++++++++++++++ common/uintmap.h | 46 ++++++ include/align.h | 21 --- include/almalloc.h | 21 --- include/atomic.h | 425 ------------------------------------------------ include/bool.h | 18 -- include/math_defs.h | 19 --- include/rwlock.h | 31 ---- include/static_assert.h | 21 --- include/threads.h | 237 --------------------------- include/uintmap.h | 46 ------ 19 files changed, 840 insertions(+), 840 deletions(-) create mode 100644 common/align.h create mode 100644 common/almalloc.h create mode 100644 common/atomic.h create mode 100644 common/bool.h create mode 100644 common/math_defs.h create mode 100644 common/rwlock.h create mode 100644 common/static_assert.h create mode 100644 common/threads.h create mode 100644 common/uintmap.h delete mode 100644 include/align.h delete mode 100644 include/almalloc.h delete mode 100644 include/atomic.h delete mode 100644 include/bool.h delete mode 100644 include/math_defs.h delete mode 100644 include/rwlock.h delete mode 100644 include/static_assert.h delete mode 100644 include/threads.h delete mode 100644 include/uintmap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ee1c9e57..3cb1e5f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,7 +274,7 @@ CHECK_C_SOURCE_COMPILES( HAVE_C11_ATOMIC) # Add definitions, compiler switches, etc. -INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_BINARY_DIR}") +INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_SOURCE_DIR}/common" "${OpenAL_BINARY_DIR}") IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING diff --git a/common/align.h b/common/align.h new file mode 100644 index 00000000..e2dc81df --- /dev/null +++ b/common/align.h @@ -0,0 +1,21 @@ +#ifndef AL_ALIGN_H +#define AL_ALIGN_H + +#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS) +#include +#endif + +#ifndef alignas +#if defined(IN_IDE_PARSER) +/* KDevelop has problems with our align macro, so just use nothing for parsing. */ +#define alignas(x) +#elif defined(HAVE_C11_ALIGNAS) +#define alignas _Alignas +#else +/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For + * maximum compatibility, only provide constant integer values to alignas. */ +#define alignas(_x) ALIGN(_x) +#endif +#endif + +#endif /* AL_ALIGN_H */ diff --git a/common/almalloc.h b/common/almalloc.h new file mode 100644 index 00000000..8eadb5b3 --- /dev/null +++ b/common/almalloc.h @@ -0,0 +1,21 @@ +#ifndef AL_MALLOC_H +#define AL_MALLOC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Minimum alignment required by posix_memalign. */ +#define DEF_ALIGN sizeof(void*) + +void *al_malloc(size_t alignment, size_t size); +void *al_calloc(size_t alignment, size_t size); +void al_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* AL_MALLOC_H */ diff --git a/common/atomic.h b/common/atomic.h new file mode 100644 index 00000000..874d510d --- /dev/null +++ b/common/atomic.h @@ -0,0 +1,425 @@ +#ifndef AL_ATOMIC_H +#define AL_ATOMIC_H + +#include "static_assert.h" +#include "bool.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Atomics using C11 */ +#ifdef HAVE_C11_ATOMIC + +#include + +#define almemory_order memory_order +#define almemory_order_relaxed memory_order_relaxed +#define almemory_order_consume memory_order_consume +#define almemory_order_acquire memory_order_acquire +#define almemory_order_release memory_order_release +#define almemory_order_acq_rel memory_order_acq_rel +#define almemory_order_seq_cst memory_order_seq_cst + +#define ATOMIC(T) T _Atomic +#define ATOMIC_FLAG atomic_flag + +#define ATOMIC_INIT atomic_init +#define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT +/*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ + +#define ATOMIC_LOAD atomic_load_explicit +#define ATOMIC_STORE atomic_store_explicit + +#define ATOMIC_ADD atomic_fetch_add_explicit +#define ATOMIC_SUB atomic_fetch_sub_explicit + +#define ATOMIC_EXCHANGE atomic_exchange_explicit +#define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit +#define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit + +#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set_explicit +#define ATOMIC_FLAG_CLEAR atomic_flag_clear_explicit + +#define ATOMIC_THREAD_FENCE atomic_thread_fence + +/* Atomics using GCC intrinsics */ +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) + +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; + +#define ATOMIC(T) struct { T volatile value; } +#define ATOMIC_FLAG ATOMIC(int) + +#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) +#define ATOMIC_INIT_STATIC(_newval) {(_newval)} +#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) + +#define ATOMIC_LOAD(_val, _MO) __extension__({ \ + __typeof((_val)->value) _r = (_val)->value; \ + __asm__ __volatile__("" ::: "memory"); \ + _r; \ +}) +#define ATOMIC_STORE(_val, _newval, _MO) do { \ + __asm__ __volatile__("" ::: "memory"); \ + (_val)->value = (_newval); \ +} while(0) + +#define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr)) +#define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr)) + +#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ + __asm__ __volatile__("" ::: "memory"); \ + __sync_lock_test_and_set(&(_val)->value, (_newval)); \ +}) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + __typeof(*(_oldval)) _o = *(_oldval); \ + *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ + *(_oldval) == _o; \ +}) + +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) __extension__({ \ + __asm__ __volatile__("" ::: "memory"); \ + __sync_lock_test_and_set(&(_val)->value, 1); \ +}) +#define ATOMIC_FLAG_CLEAR(_val, _MO) __extension__({ \ + __sync_lock_release(&(_val)->value); \ + __asm__ __volatile__("" ::: "memory"); \ +}) + + +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + __asm__ __volatile__("" ::: "memory"); \ +} while(0) + +/* Atomics using x86/x86-64 GCC inline assembly */ +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \ + "lock; xadd"S" %0,(%1)" \ + : "=r" (ret) \ + : "r" (dest), "0" (incr) \ + : "memory" \ +) +#define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \ + "lock; xadd"S" %0,(%1)" \ + : "=r" (ret) \ + : "r" (dest), "0" (-(decr)) \ + : "memory" \ +) + +#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \ + "lock; xchg"S" %0,(%1)" \ + : "=r" (ret) \ + : "r" (dest), "0" (newval) \ + : "memory" \ +) +#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \ + "lock; cmpxchg"S" %2,(%1)" \ + : "=a" (ret) \ + : "r" (dest), "r" (newval), "0" (oldval) \ + : "memory" \ +) + + +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; + +#define ATOMIC(T) struct { T volatile value; } + +#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) +#define ATOMIC_INIT_STATIC(_newval) {(_newval)} + +#define ATOMIC_LOAD(_val, _MO) __extension__({ \ + __typeof((_val)->value) _r = (_val)->value; \ + __asm__ __volatile__("" ::: "memory"); \ + _r; \ +}) +#define ATOMIC_STORE(_val, _newval, _MO) do { \ + __asm__ __volatile__("" ::: "memory"); \ + (_val)->value = (_newval); \ +} while(0) + +#define ATOMIC_ADD(_val, _incr, _MO) __extension__({ \ + static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ + __typeof((_val)->value) _r; \ + if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \ + else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \ + _r; \ +}) +#define ATOMIC_SUB(_val, _decr, _MO) __extension__({ \ + static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ + __typeof((_val)->value) _r; \ + if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \ + else if(sizeof((_val)->value) == 8) WRAP_SUB("q", _r, &(_val)->value, _decr); \ + _r; \ +}) + +#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ + __typeof((_val)->value) _r; \ + if(sizeof((_val)->value) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ + else if(sizeof((_val)->value) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval)); \ + _r; \ +}) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + __typeof(*(_oldval)) _old = *(_oldval); \ + if(sizeof((_val)->value) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ + else if(sizeof((_val)->value) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ + *(_oldval) == _old; \ +}) + +#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) __extension__({ \ + void *_r; \ + if(sizeof(void*) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ + else if(sizeof(void*) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval));\ + _r; \ +}) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ + void *_old = *(_oldval); \ + if(sizeof(void*) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ + else if(sizeof(void*) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ + *(_oldval) == _old; \ +}) + +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + __asm__ __volatile__("" ::: "memory"); \ +} while(0) + +/* Atomics using Windows methods */ +#elif defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include + +/* NOTE: This mess is *extremely* touchy. It lacks quite a bit of safety + * checking due to the lack of multi-statement expressions, typeof(), and C99 + * compound literals. It is incapable of properly exchanging floats, which get + * casted to LONG/int, and could cast away potential warnings. + * + * Unfortunately, it's the only semi-safe way that doesn't rely on C99 (because + * MSVC). + */ + +inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) +{ + return InterlockedExchangeAdd(dest, incr); +} +inline LONGLONG AtomicAdd64(volatile LONGLONG *dest, LONGLONG incr) +{ + return InterlockedExchangeAdd64(dest, incr); +} +inline LONG AtomicSub32(volatile LONG *dest, LONG decr) +{ + return InterlockedExchangeAdd(dest, -decr); +} +inline LONGLONG AtomicSub64(volatile LONGLONG *dest, LONGLONG decr) +{ + return InterlockedExchangeAdd64(dest, -decr); +} + +inline LONG AtomicSwap32(volatile LONG *dest, LONG newval) +{ + return InterlockedExchange(dest, newval); +} +inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval) +{ + return InterlockedExchange64(dest, newval); +} +inline void *AtomicSwapPtr(void *volatile *dest, void *newval) +{ + return InterlockedExchangePointer(dest, newval); +} + +inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval) +{ + LONG old = *oldval; + *oldval = InterlockedCompareExchange(dest, newval, *oldval); + return old == *oldval; +} +inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval) +{ + LONGLONG old = *oldval; + *oldval = InterlockedCompareExchange64(dest, newval, *oldval); + return old == *oldval; +} +inline bool CompareAndSwapPtr(void *volatile *dest, void *newval, void **oldval) +{ + void *old = *oldval; + *oldval = InterlockedCompareExchangePointer(dest, newval, *oldval); + return old == *oldval; +} + +#define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt)) +#define WRAP_XCHG(T, _func, _ptr, _newval) _func((T volatile*)(_ptr), (_newval)) +#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) _func((T volatile*)(_ptr), (_newval), (T*)(_oldval)) + + +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; + +#define ATOMIC(T) struct { T volatile value; } + +#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) +#define ATOMIC_INIT_STATIC(_newval) {(_newval)} + +#define ATOMIC_LOAD(_val, _MO) ((_val)->value) +#define ATOMIC_STORE(_val, _newval, _MO) do { \ + (_val)->value = (_newval); \ +} while(0) + +int _al_invalid_atomic_size(); /* not defined */ + +#define ATOMIC_ADD(_val, _incr, _MO) \ + ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ + (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \ + _al_invalid_atomic_size()) +#define ATOMIC_SUB(_val, _decr, _MO) \ + ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ + (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ + _al_invalid_atomic_size()) + +#define ATOMIC_EXCHANGE(_val, _newval, _MO) \ + ((sizeof((_val)->value)==4) ? WRAP_XCHG(LONG, AtomicSwap32, &(_val)->value, (_newval)) : \ + (sizeof((_val)->value)==8) ? WRAP_XCHG(LONGLONG, AtomicSwap64, &(_val)->value, (_newval)) : \ + (LONG)_al_invalid_atomic_size()) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) \ + ((sizeof((_val)->value)==4) ? WRAP_CMPXCHG(LONG, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ + (sizeof((_val)->value)==8) ? WRAP_CMPXCHG(LONGLONG, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ + (bool)_al_invalid_atomic_size()) + +#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \ + ((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \ + (void*)_al_invalid_atomic_size()) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\ + ((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \ + (bool)_al_invalid_atomic_size()) + +#define ATOMIC_THREAD_FENCE(order) do { \ + enum { must_be_constant = (order) }; \ + const int _o = must_be_constant; \ + if(_o > almemory_order_relaxed) \ + _ReadWriteBarrier(); \ +} while(0) + +#else + +#error "No atomic functions available on this platform!" + +#define ATOMIC(T) T + +#define ATOMIC_INIT(_val, _newval) ((void)0) +#define ATOMIC_INIT_STATIC(_newval) (0) + +#define ATOMIC_LOAD(...) (0) +#define ATOMIC_STORE(...) ((void)0) + +#define ATOMIC_ADD(...) (0) +#define ATOMIC_SUB(...) (0) + +#define ATOMIC_EXCHANGE(...) (0) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(...) (0) + +#define ATOMIC_THREAD_FENCE(...) ((void)0) +#endif + +/* If no PTR xchg variants are provided, the normal ones can handle it. */ +#ifndef ATOMIC_EXCHANGE_PTR +#define ATOMIC_EXCHANGE_PTR ATOMIC_EXCHANGE +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG ATOMIC_COMPARE_EXCHANGE_STRONG +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK +#endif + +/* If no weak cmpxchg is provided (not all systems will have one), substitute a + * strong cmpxchg. */ +#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK +#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG +#endif +#ifndef ATOMIC_COMPARE_EXCHANGE_PTR_WEAK +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG +#endif + +/* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange + * and store ops. + */ +#ifndef ATOMIC_FLAG +#define ATOMIC_FLAG ATOMIC(int) +#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) +#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(_val, 1, _MO) +#define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO) +#endif + + +#define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) +#define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) + +#define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) +#define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) + +#define ATOMIC_EXCHANGE_SEQ(_val, _newval) ATOMIC_EXCHANGE(_val, _newval, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) + +#define ATOMIC_EXCHANGE_PTR_SEQ(_val, _newval) ATOMIC_EXCHANGE_PTR(_val, _newval, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(_val, _oldval, _newval) \ + ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) + + +typedef unsigned int uint; +typedef ATOMIC(uint) RefCount; + +inline void InitRef(RefCount *ptr, uint value) +{ ATOMIC_INIT(ptr, value); } +inline uint ReadRef(RefCount *ptr) +{ return ATOMIC_LOAD_SEQ(ptr); } +inline uint IncrementRef(RefCount *ptr) +{ return ATOMIC_ADD_SEQ(ptr, 1)+1; } +inline uint DecrementRef(RefCount *ptr) +{ return ATOMIC_SUB_SEQ(ptr, 1)-1; } + + +/* WARNING: A livelock is theoretically possible if another thread keeps + * changing the head without giving this a chance to actually swap in the new + * one (practically impossible with this little code, but...). + */ +#define ATOMIC_REPLACE_HEAD(T, _head, _entry) do { \ + T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ + do { \ + ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_head, &_first, _entry, \ + almemory_order_acq_rel, almemory_order_acquire) == 0); \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* AL_ATOMIC_H */ diff --git a/common/bool.h b/common/bool.h new file mode 100644 index 00000000..6f714d09 --- /dev/null +++ b/common/bool.h @@ -0,0 +1,18 @@ +#ifndef AL_BOOL_H +#define AL_BOOL_H + +#ifdef HAVE_STDBOOL_H +#include +#endif + +#ifndef bool +#ifdef HAVE_C99_BOOL +#define bool _Bool +#else +#define bool int +#endif +#define false 0 +#define true 1 +#endif + +#endif /* AL_BOOL_H */ diff --git a/common/math_defs.h b/common/math_defs.h new file mode 100644 index 00000000..149cf80b --- /dev/null +++ b/common/math_defs.h @@ -0,0 +1,19 @@ +#ifndef AL_MATH_DEFS_H +#define AL_MATH_DEFS_H + +#ifdef HAVE_FLOAT_H +#include +#endif + +#define F_PI (3.14159265358979323846f) +#define F_PI_2 (1.57079632679489661923f) +#define F_TAU (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)) + +#endif /* AL_MATH_DEFS_H */ diff --git a/common/rwlock.h b/common/rwlock.h new file mode 100644 index 00000000..8e36fa1a --- /dev/null +++ b/common/rwlock.h @@ -0,0 +1,31 @@ +#ifndef AL_RWLOCK_H +#define AL_RWLOCK_H + +#include "bool.h" +#include "atomic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + RefCount read_count; + RefCount write_count; + ATOMIC_FLAG read_lock; + ATOMIC_FLAG read_entry_lock; + ATOMIC_FLAG write_lock; +} RWLock; +#define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ + ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT } + +void RWLockInit(RWLock *lock); +void ReadLock(RWLock *lock); +void ReadUnlock(RWLock *lock); +void WriteLock(RWLock *lock); +void WriteUnlock(RWLock *lock); + +#ifdef __cplusplus +} +#endif + +#endif /* AL_RWLOCK_H */ diff --git a/common/static_assert.h b/common/static_assert.h new file mode 100644 index 00000000..bf0ce065 --- /dev/null +++ b/common/static_assert.h @@ -0,0 +1,21 @@ +#ifndef AL_STATIC_ASSERT_H +#define AL_STATIC_ASSERT_H + +#include + + +#ifndef static_assert +#ifdef HAVE_C11_STATIC_ASSERT +#define static_assert _Static_assert +#else +#define CTASTR2(_pre,_post) _pre##_post +#define CTASTR(_pre,_post) CTASTR2(_pre,_post) +#if defined(__COUNTER__) +#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__) +#else +#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } +#endif +#endif +#endif + +#endif /* AL_STATIC_ASSERT_H */ diff --git a/common/threads.h b/common/threads.h new file mode 100644 index 00000000..c2848ee7 --- /dev/null +++ b/common/threads.h @@ -0,0 +1,237 @@ +#ifndef AL_THREADS_H +#define AL_THREADS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + althrd_success = 0, + althrd_error, + althrd_nomem, + althrd_timedout, + althrd_busy +}; + +enum { + almtx_plain = 0, + almtx_recursive = 1, + almtx_timed = 2 +}; + +typedef int (*althrd_start_t)(void*); +typedef void (*altss_dtor_t)(void*); + + +#define AL_TIME_UTC 1 + + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + + +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif + +typedef DWORD althrd_t; +typedef CRITICAL_SECTION almtx_t; +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +typedef CONDITION_VARIABLE alcnd_t; +#else +typedef struct { void *Ptr; } alcnd_t; +#endif +typedef DWORD altss_t; +typedef LONG alonce_flag; + +#define AL_ONCE_FLAG_INIT 0 + +int althrd_sleep(const struct timespec *ts, struct timespec *rem); +void alcall_once(alonce_flag *once, void (*callback)(void)); + + +inline althrd_t althrd_current(void) +{ + return GetCurrentThreadId(); +} + +inline int althrd_equal(althrd_t thr0, althrd_t thr1) +{ + return thr0 == thr1; +} + +inline void althrd_exit(int res) +{ + ExitThread(res); +} + +inline void althrd_yield(void) +{ + SwitchToThread(); +} + + +inline int almtx_lock(almtx_t *mtx) +{ + if(!mtx) return althrd_error; + EnterCriticalSection(mtx); + return althrd_success; +} + +inline int almtx_unlock(almtx_t *mtx) +{ + if(!mtx) return althrd_error; + LeaveCriticalSection(mtx); + return althrd_success; +} + +inline int almtx_trylock(almtx_t *mtx) +{ + if(!mtx) return althrd_error; + if(!TryEnterCriticalSection(mtx)) + return althrd_busy; + return althrd_success; +} + + +inline void *altss_get(altss_t tss_id) +{ + return TlsGetValue(tss_id); +} + +inline int altss_set(altss_t tss_id, void *val) +{ + if(TlsSetValue(tss_id, val) == 0) + return althrd_error; + return althrd_success; +} + +#else + +#include +#include +#include + + +typedef pthread_t althrd_t; +typedef pthread_mutex_t almtx_t; +typedef pthread_cond_t alcnd_t; +typedef pthread_key_t altss_t; +typedef pthread_once_t alonce_flag; + +#define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT + + +inline althrd_t althrd_current(void) +{ + return pthread_self(); +} + +inline int althrd_equal(althrd_t thr0, althrd_t thr1) +{ + return pthread_equal(thr0, thr1); +} + +inline void althrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +inline void althrd_yield(void) +{ + sched_yield(); +} + +inline int althrd_sleep(const struct timespec *ts, struct timespec *rem) +{ + int ret = nanosleep(ts, rem); + if(ret != 0) + { + ret = ((errno==EINTR) ? -1 : -2); + errno = 0; + } + return ret; +} + + +inline int almtx_lock(almtx_t *mtx) +{ + if(pthread_mutex_lock(mtx) != 0) + return althrd_error; + return althrd_success; +} + +inline int almtx_unlock(almtx_t *mtx) +{ + if(pthread_mutex_unlock(mtx) != 0) + return althrd_error; + return althrd_success; +} + +inline int almtx_trylock(almtx_t *mtx) +{ + int ret = pthread_mutex_trylock(mtx); + switch(ret) + { + case 0: return althrd_success; + case EBUSY: return althrd_busy; + } + return althrd_error; +} + + +inline void *altss_get(altss_t tss_id) +{ + return pthread_getspecific(tss_id); +} + +inline int altss_set(altss_t tss_id, void *val) +{ + if(pthread_setspecific(tss_id, val) != 0) + return althrd_error; + return althrd_success; +} + + +inline void alcall_once(alonce_flag *once, void (*callback)(void)) +{ + pthread_once(once, callback); +} + +#endif + + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); +int althrd_detach(althrd_t thr); +int althrd_join(althrd_t thr, int *res); +void althrd_setname(althrd_t thr, const char *name); + +int almtx_init(almtx_t *mtx, int type); +void almtx_destroy(almtx_t *mtx); +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts); + +int alcnd_init(alcnd_t *cond); +int alcnd_signal(alcnd_t *cond); +int alcnd_broadcast(alcnd_t *cond); +int alcnd_wait(alcnd_t *cond, almtx_t *mtx); +int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point); +void alcnd_destroy(alcnd_t *cond); + +int altss_create(altss_t *tss_id, altss_dtor_t callback); +void altss_delete(altss_t tss_id); + +int altimespec_get(struct timespec *ts, int base); + +void al_nssleep(unsigned long nsec); + +#ifdef __cplusplus +} +#endif + +#endif /* AL_THREADS_H */ diff --git a/common/uintmap.h b/common/uintmap.h new file mode 100644 index 00000000..f70d99fd --- /dev/null +++ b/common/uintmap.h @@ -0,0 +1,46 @@ +#ifndef AL_UINTMAP_H +#define AL_UINTMAP_H + +#include "AL/al.h" +#include "rwlock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UIntMap { + ALuint *keys; + /* Shares memory with keys. */ + ALvoid **values; + + ALsizei size; + ALsizei capacity; + ALsizei limit; + RWLock lock; +} UIntMap; +#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } +#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(~0) + +void InitUIntMap(UIntMap *map, ALsizei limit); +void ResetUIntMap(UIntMap *map); +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); +ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); +ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); +ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key); +ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); +ALvoid *LookupUIntMapKeyNoLock(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); } + +#ifdef __cplusplus +} +#endif + +#endif /* AL_UINTMAP_H */ diff --git a/include/align.h b/include/align.h deleted file mode 100644 index e2dc81df..00000000 --- a/include/align.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AL_ALIGN_H -#define AL_ALIGN_H - -#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS) -#include -#endif - -#ifndef alignas -#if defined(IN_IDE_PARSER) -/* KDevelop has problems with our align macro, so just use nothing for parsing. */ -#define alignas(x) -#elif defined(HAVE_C11_ALIGNAS) -#define alignas _Alignas -#else -/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For - * maximum compatibility, only provide constant integer values to alignas. */ -#define alignas(_x) ALIGN(_x) -#endif -#endif - -#endif /* AL_ALIGN_H */ diff --git a/include/almalloc.h b/include/almalloc.h deleted file mode 100644 index 8eadb5b3..00000000 --- a/include/almalloc.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AL_MALLOC_H -#define AL_MALLOC_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Minimum alignment required by posix_memalign. */ -#define DEF_ALIGN sizeof(void*) - -void *al_malloc(size_t alignment, size_t size); -void *al_calloc(size_t alignment, size_t size); -void al_free(void *ptr); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_MALLOC_H */ diff --git a/include/atomic.h b/include/atomic.h deleted file mode 100644 index 874d510d..00000000 --- a/include/atomic.h +++ /dev/null @@ -1,425 +0,0 @@ -#ifndef AL_ATOMIC_H -#define AL_ATOMIC_H - -#include "static_assert.h" -#include "bool.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Atomics using C11 */ -#ifdef HAVE_C11_ATOMIC - -#include - -#define almemory_order memory_order -#define almemory_order_relaxed memory_order_relaxed -#define almemory_order_consume memory_order_consume -#define almemory_order_acquire memory_order_acquire -#define almemory_order_release memory_order_release -#define almemory_order_acq_rel memory_order_acq_rel -#define almemory_order_seq_cst memory_order_seq_cst - -#define ATOMIC(T) T _Atomic -#define ATOMIC_FLAG atomic_flag - -#define ATOMIC_INIT atomic_init -#define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT -/*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/ - -#define ATOMIC_LOAD atomic_load_explicit -#define ATOMIC_STORE atomic_store_explicit - -#define ATOMIC_ADD atomic_fetch_add_explicit -#define ATOMIC_SUB atomic_fetch_sub_explicit - -#define ATOMIC_EXCHANGE atomic_exchange_explicit -#define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit -#define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit - -#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set_explicit -#define ATOMIC_FLAG_CLEAR atomic_flag_clear_explicit - -#define ATOMIC_THREAD_FENCE atomic_thread_fence - -/* Atomics using GCC intrinsics */ -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } -#define ATOMIC_FLAG ATOMIC(int) - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) - -#define ATOMIC_LOAD(_val, _MO) __extension__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr)) -#define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr)) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ - __asm__ __volatile__("" ::: "memory"); \ - __sync_lock_test_and_set(&(_val)->value, (_newval)); \ -}) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - __typeof(*(_oldval)) _o = *(_oldval); \ - *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ - *(_oldval) == _o; \ -}) - -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) __extension__({ \ - __asm__ __volatile__("" ::: "memory"); \ - __sync_lock_test_and_set(&(_val)->value, 1); \ -}) -#define ATOMIC_FLAG_CLEAR(_val, _MO) __extension__({ \ - __sync_lock_release(&(_val)->value); \ - __asm__ __volatile__("" ::: "memory"); \ -}) - - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - __asm__ __volatile__("" ::: "memory"); \ -} while(0) - -/* Atomics using x86/x86-64 GCC inline assembly */ -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \ - "lock; xadd"S" %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (incr) \ - : "memory" \ -) -#define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \ - "lock; xadd"S" %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (-(decr)) \ - : "memory" \ -) - -#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \ - "lock; xchg"S" %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (newval) \ - : "memory" \ -) -#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \ - "lock; cmpxchg"S" %2,(%1)" \ - : "=a" (ret) \ - : "r" (dest), "r" (newval), "0" (oldval) \ - : "memory" \ -) - - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} - -#define ATOMIC_LOAD(_val, _MO) __extension__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#define ATOMIC_ADD(_val, _incr, _MO) __extension__({ \ - static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \ - else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \ - _r; \ -}) -#define ATOMIC_SUB(_val, _decr, _MO) __extension__({ \ - static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \ - else if(sizeof((_val)->value) == 8) WRAP_SUB("q", _r, &(_val)->value, _decr); \ - _r; \ -}) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \ - __typeof((_val)->value) _r; \ - if(sizeof((_val)->value) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ - else if(sizeof((_val)->value) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval)); \ - _r; \ -}) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - __typeof(*(_oldval)) _old = *(_oldval); \ - if(sizeof((_val)->value) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ - else if(sizeof((_val)->value) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ - *(_oldval) == _old; \ -}) - -#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) __extension__({ \ - void *_r; \ - if(sizeof(void*) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \ - else if(sizeof(void*) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval));\ - _r; \ -}) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \ - void *_old = *(_oldval); \ - if(sizeof(void*) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \ - else if(sizeof(void*) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \ - *(_oldval) == _old; \ -}) - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - __asm__ __volatile__("" ::: "memory"); \ -} while(0) - -/* Atomics using Windows methods */ -#elif defined(_WIN32) - -#define WIN32_LEAN_AND_MEAN -#include - -/* NOTE: This mess is *extremely* touchy. It lacks quite a bit of safety - * checking due to the lack of multi-statement expressions, typeof(), and C99 - * compound literals. It is incapable of properly exchanging floats, which get - * casted to LONG/int, and could cast away potential warnings. - * - * Unfortunately, it's the only semi-safe way that doesn't rely on C99 (because - * MSVC). - */ - -inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) -{ - return InterlockedExchangeAdd(dest, incr); -} -inline LONGLONG AtomicAdd64(volatile LONGLONG *dest, LONGLONG incr) -{ - return InterlockedExchangeAdd64(dest, incr); -} -inline LONG AtomicSub32(volatile LONG *dest, LONG decr) -{ - return InterlockedExchangeAdd(dest, -decr); -} -inline LONGLONG AtomicSub64(volatile LONGLONG *dest, LONGLONG decr) -{ - return InterlockedExchangeAdd64(dest, -decr); -} - -inline LONG AtomicSwap32(volatile LONG *dest, LONG newval) -{ - return InterlockedExchange(dest, newval); -} -inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval) -{ - return InterlockedExchange64(dest, newval); -} -inline void *AtomicSwapPtr(void *volatile *dest, void *newval) -{ - return InterlockedExchangePointer(dest, newval); -} - -inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval) -{ - LONG old = *oldval; - *oldval = InterlockedCompareExchange(dest, newval, *oldval); - return old == *oldval; -} -inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval) -{ - LONGLONG old = *oldval; - *oldval = InterlockedCompareExchange64(dest, newval, *oldval); - return old == *oldval; -} -inline bool CompareAndSwapPtr(void *volatile *dest, void *newval, void **oldval) -{ - void *old = *oldval; - *oldval = InterlockedCompareExchangePointer(dest, newval, *oldval); - return old == *oldval; -} - -#define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt)) -#define WRAP_XCHG(T, _func, _ptr, _newval) _func((T volatile*)(_ptr), (_newval)) -#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) _func((T volatile*)(_ptr), (_newval), (T*)(_oldval)) - - -enum almemory_order { - almemory_order_relaxed, - almemory_order_consume, - almemory_order_acquire, - almemory_order_release, - almemory_order_acq_rel, - almemory_order_seq_cst -}; - -#define ATOMIC(T) struct { T volatile value; } - -#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) -#define ATOMIC_INIT_STATIC(_newval) {(_newval)} - -#define ATOMIC_LOAD(_val, _MO) ((_val)->value) -#define ATOMIC_STORE(_val, _newval, _MO) do { \ - (_val)->value = (_newval); \ -} while(0) - -int _al_invalid_atomic_size(); /* not defined */ - -#define ATOMIC_ADD(_val, _incr, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ - (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \ - _al_invalid_atomic_size()) -#define ATOMIC_SUB(_val, _decr, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \ - (sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \ - _al_invalid_atomic_size()) - -#define ATOMIC_EXCHANGE(_val, _newval, _MO) \ - ((sizeof((_val)->value)==4) ? WRAP_XCHG(LONG, AtomicSwap32, &(_val)->value, (_newval)) : \ - (sizeof((_val)->value)==8) ? WRAP_XCHG(LONGLONG, AtomicSwap64, &(_val)->value, (_newval)) : \ - (LONG)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) \ - ((sizeof((_val)->value)==4) ? WRAP_CMPXCHG(LONG, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ - (sizeof((_val)->value)==8) ? WRAP_CMPXCHG(LONGLONG, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ - (bool)_al_invalid_atomic_size()) - -#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \ - ((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \ - (void*)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\ - ((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \ - (bool)_al_invalid_atomic_size()) - -#define ATOMIC_THREAD_FENCE(order) do { \ - enum { must_be_constant = (order) }; \ - const int _o = must_be_constant; \ - if(_o > almemory_order_relaxed) \ - _ReadWriteBarrier(); \ -} while(0) - -#else - -#error "No atomic functions available on this platform!" - -#define ATOMIC(T) T - -#define ATOMIC_INIT(_val, _newval) ((void)0) -#define ATOMIC_INIT_STATIC(_newval) (0) - -#define ATOMIC_LOAD(...) (0) -#define ATOMIC_STORE(...) ((void)0) - -#define ATOMIC_ADD(...) (0) -#define ATOMIC_SUB(...) (0) - -#define ATOMIC_EXCHANGE(...) (0) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(...) (0) - -#define ATOMIC_THREAD_FENCE(...) ((void)0) -#endif - -/* If no PTR xchg variants are provided, the normal ones can handle it. */ -#ifndef ATOMIC_EXCHANGE_PTR -#define ATOMIC_EXCHANGE_PTR ATOMIC_EXCHANGE -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG ATOMIC_COMPARE_EXCHANGE_STRONG -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK -#endif - -/* If no weak cmpxchg is provided (not all systems will have one), substitute a - * strong cmpxchg. */ -#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK -#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG -#endif -#ifndef ATOMIC_COMPARE_EXCHANGE_PTR_WEAK -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG -#endif - -/* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange - * and store ops. - */ -#ifndef ATOMIC_FLAG -#define ATOMIC_FLAG ATOMIC(int) -#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0) -#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(_val, 1, _MO) -#define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO) -#endif - - -#define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst) -#define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst) - -#define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst) -#define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst) - -#define ATOMIC_EXCHANGE_SEQ(_val, _newval) ATOMIC_EXCHANGE(_val, _newval, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) - -#define ATOMIC_EXCHANGE_PTR_SEQ(_val, _newval) ATOMIC_EXCHANGE_PTR(_val, _newval, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) -#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(_val, _oldval, _newval) \ - ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst) - - -typedef unsigned int uint; -typedef ATOMIC(uint) RefCount; - -inline void InitRef(RefCount *ptr, uint value) -{ ATOMIC_INIT(ptr, value); } -inline uint ReadRef(RefCount *ptr) -{ return ATOMIC_LOAD_SEQ(ptr); } -inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD_SEQ(ptr, 1)+1; } -inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB_SEQ(ptr, 1)-1; } - - -/* WARNING: A livelock is theoretically possible if another thread keeps - * changing the head without giving this a chance to actually swap in the new - * one (practically impossible with this little code, but...). - */ -#define ATOMIC_REPLACE_HEAD(T, _head, _entry) do { \ - T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \ - do { \ - ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \ - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_head, &_first, _entry, \ - almemory_order_acq_rel, almemory_order_acquire) == 0); \ -} while(0) - -#ifdef __cplusplus -} -#endif - -#endif /* AL_ATOMIC_H */ diff --git a/include/bool.h b/include/bool.h deleted file mode 100644 index 6f714d09..00000000 --- a/include/bool.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef AL_BOOL_H -#define AL_BOOL_H - -#ifdef HAVE_STDBOOL_H -#include -#endif - -#ifndef bool -#ifdef HAVE_C99_BOOL -#define bool _Bool -#else -#define bool int -#endif -#define false 0 -#define true 1 -#endif - -#endif /* AL_BOOL_H */ diff --git a/include/math_defs.h b/include/math_defs.h deleted file mode 100644 index 149cf80b..00000000 --- a/include/math_defs.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef AL_MATH_DEFS_H -#define AL_MATH_DEFS_H - -#ifdef HAVE_FLOAT_H -#include -#endif - -#define F_PI (3.14159265358979323846f) -#define F_PI_2 (1.57079632679489661923f) -#define F_TAU (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)) - -#endif /* AL_MATH_DEFS_H */ diff --git a/include/rwlock.h b/include/rwlock.h deleted file mode 100644 index 8e36fa1a..00000000 --- a/include/rwlock.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef AL_RWLOCK_H -#define AL_RWLOCK_H - -#include "bool.h" -#include "atomic.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - RefCount read_count; - RefCount write_count; - ATOMIC_FLAG read_lock; - ATOMIC_FLAG read_entry_lock; - ATOMIC_FLAG write_lock; -} RWLock; -#define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \ - ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT } - -void RWLockInit(RWLock *lock); -void ReadLock(RWLock *lock); -void ReadUnlock(RWLock *lock); -void WriteLock(RWLock *lock); -void WriteUnlock(RWLock *lock); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_RWLOCK_H */ diff --git a/include/static_assert.h b/include/static_assert.h deleted file mode 100644 index bf0ce065..00000000 --- a/include/static_assert.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef AL_STATIC_ASSERT_H -#define AL_STATIC_ASSERT_H - -#include - - -#ifndef static_assert -#ifdef HAVE_C11_STATIC_ASSERT -#define static_assert _Static_assert -#else -#define CTASTR2(_pre,_post) _pre##_post -#define CTASTR(_pre,_post) CTASTR2(_pre,_post) -#if defined(__COUNTER__) -#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__) -#else -#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } -#endif -#endif -#endif - -#endif /* AL_STATIC_ASSERT_H */ diff --git a/include/threads.h b/include/threads.h deleted file mode 100644 index c2848ee7..00000000 --- a/include/threads.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef AL_THREADS_H -#define AL_THREADS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - althrd_success = 0, - althrd_error, - althrd_nomem, - althrd_timedout, - althrd_busy -}; - -enum { - almtx_plain = 0, - almtx_recursive = 1, - almtx_timed = 2 -}; - -typedef int (*althrd_start_t)(void*); -typedef void (*altss_dtor_t)(void*); - - -#define AL_TIME_UTC 1 - - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - - -#ifndef HAVE_STRUCT_TIMESPEC -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif - -typedef DWORD althrd_t; -typedef CRITICAL_SECTION almtx_t; -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 -typedef CONDITION_VARIABLE alcnd_t; -#else -typedef struct { void *Ptr; } alcnd_t; -#endif -typedef DWORD altss_t; -typedef LONG alonce_flag; - -#define AL_ONCE_FLAG_INIT 0 - -int althrd_sleep(const struct timespec *ts, struct timespec *rem); -void alcall_once(alonce_flag *once, void (*callback)(void)); - - -inline althrd_t althrd_current(void) -{ - return GetCurrentThreadId(); -} - -inline int althrd_equal(althrd_t thr0, althrd_t thr1) -{ - return thr0 == thr1; -} - -inline void althrd_exit(int res) -{ - ExitThread(res); -} - -inline void althrd_yield(void) -{ - SwitchToThread(); -} - - -inline int almtx_lock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - EnterCriticalSection(mtx); - return althrd_success; -} - -inline int almtx_unlock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - LeaveCriticalSection(mtx); - return althrd_success; -} - -inline int almtx_trylock(almtx_t *mtx) -{ - if(!mtx) return althrd_error; - if(!TryEnterCriticalSection(mtx)) - return althrd_busy; - return althrd_success; -} - - -inline void *altss_get(altss_t tss_id) -{ - return TlsGetValue(tss_id); -} - -inline int altss_set(altss_t tss_id, void *val) -{ - if(TlsSetValue(tss_id, val) == 0) - return althrd_error; - return althrd_success; -} - -#else - -#include -#include -#include - - -typedef pthread_t althrd_t; -typedef pthread_mutex_t almtx_t; -typedef pthread_cond_t alcnd_t; -typedef pthread_key_t altss_t; -typedef pthread_once_t alonce_flag; - -#define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT - - -inline althrd_t althrd_current(void) -{ - return pthread_self(); -} - -inline int althrd_equal(althrd_t thr0, althrd_t thr1) -{ - return pthread_equal(thr0, thr1); -} - -inline void althrd_exit(int res) -{ - pthread_exit((void*)(intptr_t)res); -} - -inline void althrd_yield(void) -{ - sched_yield(); -} - -inline int althrd_sleep(const struct timespec *ts, struct timespec *rem) -{ - int ret = nanosleep(ts, rem); - if(ret != 0) - { - ret = ((errno==EINTR) ? -1 : -2); - errno = 0; - } - return ret; -} - - -inline int almtx_lock(almtx_t *mtx) -{ - if(pthread_mutex_lock(mtx) != 0) - return althrd_error; - return althrd_success; -} - -inline int almtx_unlock(almtx_t *mtx) -{ - if(pthread_mutex_unlock(mtx) != 0) - return althrd_error; - return althrd_success; -} - -inline int almtx_trylock(almtx_t *mtx) -{ - int ret = pthread_mutex_trylock(mtx); - switch(ret) - { - case 0: return althrd_success; - case EBUSY: return althrd_busy; - } - return althrd_error; -} - - -inline void *altss_get(altss_t tss_id) -{ - return pthread_getspecific(tss_id); -} - -inline int altss_set(altss_t tss_id, void *val) -{ - if(pthread_setspecific(tss_id, val) != 0) - return althrd_error; - return althrd_success; -} - - -inline void alcall_once(alonce_flag *once, void (*callback)(void)) -{ - pthread_once(once, callback); -} - -#endif - - -int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); -int althrd_detach(althrd_t thr); -int althrd_join(althrd_t thr, int *res); -void althrd_setname(althrd_t thr, const char *name); - -int almtx_init(almtx_t *mtx, int type); -void almtx_destroy(almtx_t *mtx); -int almtx_timedlock(almtx_t *mtx, const struct timespec *ts); - -int alcnd_init(alcnd_t *cond); -int alcnd_signal(alcnd_t *cond); -int alcnd_broadcast(alcnd_t *cond); -int alcnd_wait(alcnd_t *cond, almtx_t *mtx); -int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point); -void alcnd_destroy(alcnd_t *cond); - -int altss_create(altss_t *tss_id, altss_dtor_t callback); -void altss_delete(altss_t tss_id); - -int altimespec_get(struct timespec *ts, int base); - -void al_nssleep(unsigned long nsec); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_THREADS_H */ diff --git a/include/uintmap.h b/include/uintmap.h deleted file mode 100644 index f70d99fd..00000000 --- a/include/uintmap.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef AL_UINTMAP_H -#define AL_UINTMAP_H - -#include "AL/al.h" -#include "rwlock.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct UIntMap { - ALuint *keys; - /* Shares memory with keys. */ - ALvoid **values; - - ALsizei size; - ALsizei capacity; - ALsizei limit; - RWLock lock; -} UIntMap; -#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } -#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(~0) - -void InitUIntMap(UIntMap *map, ALsizei limit); -void ResetUIntMap(UIntMap *map); -ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); -ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); -ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); -ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key); -ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); -ALvoid *LookupUIntMapKeyNoLock(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); } - -#ifdef __cplusplus -} -#endif - -#endif /* AL_UINTMAP_H */ -- cgit v1.2.3 From d9bf4f7620c1e13846a53ee9df5c8c9eb2fcfe7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Apr 2017 22:56:54 -0700 Subject: Allow increasing the maximum source limit If the requested number of mono and stereo sources exceeds 256, the source limit will be expanded. Any config file setting overrides this. If the device is reset to have fewer sources than are currently allocated, excess sources will remain and be usable as normal, but no more can be generated until enough are delated to go back below the limit. --- Alc/ALc.c | 74 ++++++++++++++++++++++++++++++++++++---------- OpenAL32/alAuxEffectSlot.c | 2 +- common/uintmap.c | 9 ++++-- common/uintmap.h | 3 +- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index cc9aa5c3..2d0d64f5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1834,13 +1834,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_VALUE; } + if(attrList[attrIdx] == ALC_MONO_SOURCES) + { + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + } + if(attrList[attrIdx] == ALC_STEREO_SOURCES) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - - numStereo = clampi(numStereo, 0, device->SourcesMax); - numMono = device->SourcesMax - numStereo; + numStereo = maxi(numStereo, 0); } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) @@ -1898,6 +1903,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->AmbiLayout = alayout; device->AmbiScale = ascale; } + + if(numMono > INT_MAX-numStereo) + numMono = INT_MAX-numStereo; + numMono += numStereo; + if(ConfigValueInt(NULL, NULL, "sources", &numMono)) + { + if(numMono <= 0) + numMono = 256; + } + else + numMono = maxi(numMono, 256); + numStereo = mini(numStereo, numMono); + numMono -= numStereo; + device->SourcesMax = numMono + numStereo; + device->NumMonoSources = numMono; device->NumStereoSources = numStereo; @@ -1935,13 +1955,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->Flags |= DEVICE_FREQUENCY_REQUEST; } + if(attrList[attrIdx] == ALC_MONO_SOURCES) + { + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + } + if(attrList[attrIdx] == ALC_STEREO_SOURCES) { numStereo = attrList[attrIdx + 1]; TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - - numStereo = clampi(numStereo, 0, device->SourcesMax); - numMono = device->SourcesMax - numStereo; + numStereo = maxi(numStereo, 0); } if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) @@ -1982,6 +2007,21 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->UpdateSize = (device->UpdateSize+3)&~3; device->Frequency = freq; + + if(numMono > INT_MAX-numStereo) + numMono = INT_MAX-numStereo; + numMono += numStereo; + if(ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "sources", &numMono)) + { + if(numMono <= 0) + numMono = 256; + } + else + numMono = maxi(numMono, 256); + numStereo = mini(numStereo, numMono); + numMono -= numStereo; + device->SourcesMax = numMono + numStereo; + device->NumMonoSources = numMono; device->NumStereoSources = numStereo; @@ -2150,6 +2190,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) * allocated with the appropriate size. */ device->NumAuxSends = new_sends; + TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", + device->SourcesMax, device->NumMonoSources, device->NumStereoSources, + device->AuxiliaryEffectSlotMax, device->NumAuxSends); update_failed = AL_FALSE; SetMixerFPUMode(&oldMode); if(device->DefaultSlot) @@ -2187,6 +2230,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UnlockUIntMapRead(&context->EffectSlotMap); LockUIntMapRead(&context->SourceMap); + RelimitUIntMapNoLock(&context->SourceMap, device->SourcesMax); for(pos = 0;pos < context->SourceMap.size;pos++) { ALsource *source = context->SourceMap.values[pos]; @@ -3751,9 +3795,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - InitUIntMap(&device->BufferMap, ~0); - InitUIntMap(&device->EffectMap, ~0); - InitUIntMap(&device->FilterMap, ~0); + InitUIntMap(&device->BufferMap, INT_MAX); + InitUIntMap(&device->EffectMap, INT_MAX); + InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -4051,9 +4095,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - InitUIntMap(&device->BufferMap, ~0); - InitUIntMap(&device->EffectMap, ~0); - InitUIntMap(&device->FilterMap, ~0); + InitUIntMap(&device->BufferMap, INT_MAX); + InitUIntMap(&device->EffectMap, INT_MAX); + InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -4279,9 +4323,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - InitUIntMap(&device->BufferMap, ~0); - InitUIntMap(&device->EffectMap, ~0); - InitUIntMap(&device->FilterMap, ~0); + InitUIntMap(&device->BufferMap, INT_MAX); + InitUIntMap(&device->EffectMap, INT_MAX); + InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index de7de943..3ec857ca 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -479,7 +479,7 @@ done: void InitEffectFactoryMap(void) { - InitUIntMap(&EffectStateFactoryMap, ~0); + InitUIntMap(&EffectStateFactoryMap, INT_MAX); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_NULL, ALnullStateFactory_getFactory); InsertUIntMapEntry(&EffectStateFactoryMap, AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory); diff --git a/common/uintmap.c b/common/uintmap.c index 21a921b2..98ed3191 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -36,6 +36,11 @@ void ResetUIntMap(UIntMap *map) WriteUnlock(&map->lock); } +void RelimitUIntMapNoLock(UIntMap *map, ALsizei limit) +{ + map->limit = limit; +} + ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) { ALsizei pos = 0; @@ -59,7 +64,7 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) if(pos == map->size || map->keys[pos] != key) { - if(map->size == map->limit) + if(map->size >= map->limit) { WriteUnlock(&map->lock); return AL_OUT_OF_MEMORY; @@ -141,7 +146,7 @@ ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value) if(pos == map->size || map->keys[pos] != key) { - if(map->size == map->limit) + if(map->size >= map->limit) return AL_OUT_OF_MEMORY; if(map->size == map->capacity) diff --git a/common/uintmap.h b/common/uintmap.h index f70d99fd..47bd0d42 100644 --- a/common/uintmap.h +++ b/common/uintmap.h @@ -19,10 +19,11 @@ typedef struct UIntMap { RWLock lock; } UIntMap; #define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE } -#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(~0) +#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(INT_MAX) void InitUIntMap(UIntMap *map, ALsizei limit); void ResetUIntMap(UIntMap *map); +void RelimitUIntMapNoLock(UIntMap *map, ALsizei limit); ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); -- cgit v1.2.3 From fca83263f46c8934b58d17997362eeecd6a79905 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Apr 2017 18:08:52 -0700 Subject: Implement capture support in the OpenSL backend --- Alc/backends/opensl.c | 380 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 379 insertions(+), 1 deletion(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 4e295f23..aa1ff991 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -700,6 +700,376 @@ static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) } +typedef struct ALCopenslCapture { + DERIVE_FROM_TYPE(ALCbackend); + + /* engine interfaces */ + SLObjectItf mEngineObj; + SLEngineItf mEngine; + + /* recording interfaces */ + SLObjectItf mRecordObj; + + ll_ringbuffer_t *mRing; + ALCuint mSplOffset; + + ALsizei mFrameSize; +} ALCopenslCapture; + +static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context); + +static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); +static void ALCopenslCapture_Destruct(ALCopenslCapture *self); +static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); +static void ALCopenslCapture_close(ALCopenslCapture *self); +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); +static void ALCopenslCapture_stop(ALCopenslCapture *self); +static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self); +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture) +DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture); + + +static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context) +{ + ALCopenslCapture *self = context; + /* A new chunk has been written into the ring buffer, advance it. */ + ll_ringbuffer_write_advance(self->mRing, 1); +} + + +static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCopenslCapture, ALCbackend, self); + + self->mEngineObj = NULL; + self->mEngine = NULL; + + self->mRecordObj = NULL; + + self->mRing = NULL; + self->mSplOffset = 0; + + self->mFrameSize = 0; +} + +static void ALCopenslCapture_Destruct(ALCopenslCapture *self) +{ + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + +static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + SLDataLocator_AndroidSimpleBufferQueue loc_bq; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLDataLocator_IODevice loc_dev; + SLDataSource audioSrc; + SLDataSink audioSnk; + SLresult result; + + if(!name) + name = opensl_device; + else if(strcmp(name, opensl_device) != 0) + return ALC_INVALID_VALUE; + + result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL); + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + /* Ensure the total length is at least 100ms */ + ALsizei length = maxi(device->NumUpdates * device->UpdateSize, + device->Frequency / 10); + /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */ + ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3, + device->Frequency / 100, + device->Frequency / 100 * 5); + + device->UpdateSize = update_len; + device->NumUpdates = (length+update_len-1) / update_len; + + self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + } + loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; + loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; + loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; + loc_dev.device = NULL; + + audioSrc.pLocator = &loc_dev; + audioSrc.pFormat = NULL; + + loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bq.numBuffers = device->NumUpdates; + +#ifdef SL_DATAFORMAT_PCM_EX + SLDataFormat_PCM_EX format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM_EX; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.sampleRate = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + format_pcm.representation = GetTypeRepresentation(device->FmtType); +#else + SLDataFormat_PCM format_pcm; + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + format_pcm.samplesPerSec = device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; +#endif + + audioSnk.pLocator = &loc_bq; + audioSnk.pFormat = &format_pcm; + + if(SL_RESULT_SUCCESS == result) + { + const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; + const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; + + result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj, + &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs + ); + PRINTERR(result, "engine->CreateAudioRecorder"); + } + if(SL_RESULT_SUCCESS == result) + { + /* Set the record preset to "generic", if possible. */ + SLAndroidConfigurationItf config; + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config); + PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION"); + if(SL_RESULT_SUCCESS == result) + { + SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC; + result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, + &preset, sizeof(preset) + ); + PRINTERR(result, "config->SetConfiguration"); + } + + /* Clear any error since this was optional. */ + result = SL_RESULT_SUCCESS; + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE); + PRINTERR(result, "recordObj->Realize"); + } + + if(SL_RESULT_SUCCESS == result) + { + self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, + device->UpdateSize * self->mFrameSize); + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + ll_ringbuffer_data_t data[2]; + size_t i; + + ll_ringbuffer_get_write_vector(self->mRing, data); + for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + } + + if(SL_RESULT_SUCCESS != result) + { + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + + return ALC_INVALID_VALUE; + } + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static void ALCopenslCapture_close(ALCopenslCapture *self) +{ + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; +} + +static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) +{ + SLRecordItf record; + SLresult result; + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING); + PRINTERR(result, "record->SetRecordState"); + } + + if(SL_RESULT_SUCCESS != result) + { + ALCopenslCapture_lock(self); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice); + ALCopenslCapture_unlock(self); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ALCopenslCapture_stop(ALCopenslCapture *self) +{ + SLRecordItf record; + SLresult result; + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record); + PRINTERR(result, "recordObj->GetInterface"); + + if(SL_RESULT_SUCCESS == result) + { + result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED); + PRINTERR(result, "record->SetRecordState"); + } +} + +static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei chunk_size = device->UpdateSize * self->mFrameSize; + SLAndroidSimpleBufferQueueItf bufferQueue; + ll_ringbuffer_data_t data[2]; + SLresult result; + size_t advance; + ALCuint i; + + /* Read the desired samples from the ring buffer then advance its read + * pointer. + */ + ll_ringbuffer_get_read_vector(self->mRing, data); + advance = 0; + for(i = 0;i < samples;) + { + ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); + memcpy((ALCbyte*)buffer + i*self->mFrameSize, + data[0].buf + self->mSplOffset*self->mFrameSize, + rem * self->mFrameSize); + + self->mSplOffset += rem; + if(self->mSplOffset == device->UpdateSize) + { + /* Finished a chunk, reset the offset and advance the read pointer. */ + self->mSplOffset = 0; + advance++; + + data[0].len--; + if(!data[0].len) + data[0] = data[1]; + else + data[0].buf += chunk_size; + } + + i += rem; + } + ll_ringbuffer_read_advance(self->mRing, advance); + + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + + /* Enqueue any newly-writable chunks in the ring buffer. */ + ll_ringbuffer_get_write_vector(self->mRing, data); + for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) + { + result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + } + + if(SL_RESULT_SUCCESS != result) + { + ALCopenslCapture_lock(self); + aluHandleDisconnect(device); + ALCopenslCapture_unlock(self); + return ALC_INVALID_DEVICE; + } + + return ALC_NO_ERROR; +} + +static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize; +} + + typedef struct ALCopenslBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCopenslBackendFactory; @@ -716,7 +1086,7 @@ static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self) static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type) { - if(type == ALCbackend_Playback) + if(type == ALCbackend_Playback || type == ALCbackend_Capture) return ALC_TRUE; return ALC_FALSE; } @@ -730,6 +1100,7 @@ static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), break; case CAPTURE_DEVICE_PROBE: + AppendAllDevicesList(opensl_device); break; } } @@ -743,6 +1114,13 @@ static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory if(!backend) return NULL; return STATIC_CAST(ALCbackend, backend); } + if(type == ALCbackend_Capture) + { + ALCopenslCapture *backend; + NEW_OBJ(backend, ALCopenslCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } return NULL; } -- cgit v1.2.3 From 8f1a968d7934117fa5ff499e3989ea2ae8e17b52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Apr 2017 20:10:32 -0700 Subject: Correctly handle the attribute array size for alcGetInteger64vSOFT --- Alc/ALc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2d0d64f5..e11a2a4e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3274,11 +3274,11 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, switch(pname) { case ALC_ATTRIBUTES_SIZE: - *values = NumAttrsForDevice(device)+2; + *values = NumAttrsForDevice(device)+4; break; case ALC_ALL_ATTRIBUTES: - if(size < NumAttrsForDevice(device)+2) + if(size < NumAttrsForDevice(device)+4) alcSetError(device, ALC_INVALID_VALUE); else { -- cgit v1.2.3 From 064176d03d33d93c107a087fe178261cfc637719 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Apr 2017 15:05:57 -0700 Subject: Remove some unnecessary parenthesis --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fc2c5e8f..a08fbbbe 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -256,7 +256,7 @@ static const union { } EndianTest = { 1 }; #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) -#define COUNTOF(x) (sizeof((x))/sizeof((x)[0])) +#define COUNTOF(x) (sizeof(x) / sizeof(0[x])) #define DERIVE_FROM_TYPE(t) t t##_parent -- cgit v1.2.3 From 6d3973f9657133cf6ccc62c47e16783fe4e95921 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Apr 2017 16:21:11 -0700 Subject: Trace unhandled device reset attributes --- Alc/ALc.c | 220 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e11a2a4e..7c6956ad 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1786,91 +1786,87 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) #define TRACE_ATTR(a, v) TRACE("Loopback %s = %d\n", #a, v) while(attrList[attrIdx]) { - if(attrList[attrIdx] == ALC_FORMAT_CHANNELS_SOFT) + switch(attrList[attrIdx]) { - schans = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); - if(!IsValidALCChannels(schans)) - return ALC_INVALID_VALUE; - } + case ALC_FORMAT_CHANNELS_SOFT: + schans = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_CHANNELS_SOFT, schans); + if(!IsValidALCChannels(schans)) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_FORMAT_TYPE_SOFT) - { - stype = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); - if(!IsValidALCType(stype)) - return ALC_INVALID_VALUE; - } + case ALC_FORMAT_TYPE_SOFT: + stype = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FORMAT_TYPE_SOFT, stype); + if(!IsValidALCType(stype)) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_FREQUENCY) - { - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - if(freq < MIN_OUTPUT_RATE) - return ALC_INVALID_VALUE; - } + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + if(freq < MIN_OUTPUT_RATE) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_AMBISONIC_LAYOUT_SOFT) - { - alayout = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); - if(!IsValidAmbiLayout(alayout)) - return ALC_INVALID_VALUE; - } + case ALC_AMBISONIC_LAYOUT_SOFT: + alayout = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_LAYOUT_SOFT, alayout); + if(!IsValidAmbiLayout(alayout)) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_AMBISONIC_SCALING_SOFT) - { - ascale = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); - if(!IsValidAmbiScaling(ascale)) - return ALC_INVALID_VALUE; - } + case ALC_AMBISONIC_SCALING_SOFT: + ascale = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_SCALING_SOFT, ascale); + if(!IsValidAmbiScaling(ascale)) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_AMBISONIC_ORDER_SOFT) - { - aorder = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); - if(aorder < 1 || aorder > MAX_AMBI_ORDER) - return ALC_INVALID_VALUE; - } + case ALC_AMBISONIC_ORDER_SOFT: + aorder = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_AMBISONIC_ORDER_SOFT, aorder); + if(aorder < 1 || aorder > MAX_AMBI_ORDER) + return ALC_INVALID_VALUE; + break; - if(attrList[attrIdx] == ALC_MONO_SOURCES) - { - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - } + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + break; - if(attrList[attrIdx] == ALC_STEREO_SOURCES) - { - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - } + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + numStereo = maxi(numStereo, 0); + break; - if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) - { - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - } + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; - if(attrList[attrIdx] == ALC_HRTF_SOFT) - { - ALCint val = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_SOFT, val); - if(val == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(val == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - } + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; - if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) - { - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; + + default: + TRACE("Loopback 0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; } attrIdx += 2; @@ -1948,49 +1944,51 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) #define TRACE_ATTR(a, v) TRACE("%s = %d\n", #a, v) while(attrList[attrIdx]) { - if(attrList[attrIdx] == ALC_FREQUENCY) + switch(attrList[attrIdx]) { - freq = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_FREQUENCY, freq); - device->Flags |= DEVICE_FREQUENCY_REQUEST; - } + case ALC_FREQUENCY: + freq = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_FREQUENCY, freq); + device->Flags |= DEVICE_FREQUENCY_REQUEST; + break; - if(attrList[attrIdx] == ALC_MONO_SOURCES) - { - numMono = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MONO_SOURCES, numMono); - numMono = maxi(numMono, 0); - } + case ALC_MONO_SOURCES: + numMono = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MONO_SOURCES, numMono); + numMono = maxi(numMono, 0); + break; - if(attrList[attrIdx] == ALC_STEREO_SOURCES) - { - numStereo = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); - numStereo = maxi(numStereo, 0); - } + case ALC_STEREO_SOURCES: + numStereo = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_STEREO_SOURCES, numStereo); + numStereo = maxi(numStereo, 0); + break; - if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS) - { - numSends = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); - numSends = clampi(numSends, 0, MAX_SENDS); - } + case ALC_MAX_AUXILIARY_SENDS: + numSends = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_MAX_AUXILIARY_SENDS, numSends); + numSends = clampi(numSends, 0, MAX_SENDS); + break; - if(attrList[attrIdx] == ALC_HRTF_SOFT) - { - TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); - if(attrList[attrIdx + 1] == ALC_FALSE) - hrtf_appreq = Hrtf_Disable; - else if(attrList[attrIdx + 1] == ALC_TRUE) - hrtf_appreq = Hrtf_Enable; - else - hrtf_appreq = Hrtf_Default; - } + case ALC_HRTF_SOFT: + TRACE_ATTR(ALC_HRTF_SOFT, attrList[attrIdx + 1]); + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; + else + hrtf_appreq = Hrtf_Default; + break; - if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) - { - hrtf_id = attrList[attrIdx + 1]; - TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + case ALC_HRTF_ID_SOFT: + hrtf_id = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); + break; + + default: + TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], + attrList[attrIdx + 1], attrList[attrIdx + 1]); + break; } attrIdx += 2; -- cgit v1.2.3 From 660971d0b73dc1abfc21827bd9b5e120a63944a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Apr 2017 23:22:30 -0700 Subject: Close some gaps in enum values --- OpenAL32/Include/alMain.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a08fbbbe..191bb658 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -42,9 +42,9 @@ #define ALC_FUMA_SOFT 0x1601 /* Ambisonic scalings (normalization) */ -#define ALC_N3D_SOFT 0x1700 -#define ALC_SN3D_SOFT 0x1701 /*#define ALC_FUMA_SOFT*/ +#define ALC_SN3D_SOFT 0x1602 +#define ALC_N3D_SOFT 0x1603 typedef ALCboolean (ALC_APIENTRY*LPALCISAMBISONICFORMATSUPPORTEDSOFT)(ALCdevice *device, ALCenum layout, ALCenum scaling, ALsizei order); #ifdef AL_ALEXT_PROTOTYPES -- cgit v1.2.3 From 14bc7baeb79f537cde9574934bee290908c43fb8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Apr 2017 21:16:01 -0700 Subject: Store the source prop updates with the mixer voice Also move its declaration and rename it for consistency. --- Alc/ALc.c | 57 +++++++++++++++++++++++-------------- Alc/ALu.c | 43 ++++++++++++++++++++++------ OpenAL32/Include/alSource.h | 57 ------------------------------------- OpenAL32/Include/alu.h | 61 ++++++++++++++++++++++++++++++++++++++-- OpenAL32/alSource.c | 68 +++++++++++++++++---------------------------- 5 files changed, 154 insertions(+), 132 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7c6956ad..a352cacd 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2232,7 +2232,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) for(pos = 0;pos < context->SourceMap.size;pos++) { ALsource *source = context->SourceMap.values[pos]; - struct ALsourceProps *props; if(old_sends != device->NumAuxSends) { @@ -2262,26 +2261,28 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } ATOMIC_FLAG_CLEAR(&source->PropsClean, almemory_order_release); + } + AllocateVoices(context, context->MaxVoices, old_sends); + for(pos = 0;pos < context->VoiceCount;pos++) + { + ALvoice *voice = context->Voices[pos]; + struct ALvoiceProps *props; - /* Clear any pre-existing source property structs, in case the - * number of auxiliary sends changed. Playing (or paused) sources - * will have updates respecified in UpdateAllSourceProps. + /* Clear any pre-existing voice property structs, in case the + * number of auxiliary sends changed. Active sources will have + * updates respecified in UpdateAllSourceProps. */ - props = ATOMIC_EXCHANGE_PTR_SEQ(&source->Update, NULL); + props = ATOMIC_EXCHANGE_PTR(&voice->Update, NULL, almemory_order_relaxed); al_free(props); - props = ATOMIC_EXCHANGE_PTR(&source->FreeList, NULL, almemory_order_relaxed); + props = ATOMIC_EXCHANGE_PTR(&voice->FreeList, NULL, almemory_order_relaxed); while(props) { - struct ALsourceProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + struct ALvoiceProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); al_free(props); props = next; } - } - AllocateVoices(context, context->MaxVoices, old_sends); - for(pos = 0;pos < context->VoiceCount;pos++) - { - ALvoice *voice = context->Voices[pos]; + if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == NULL) continue; @@ -2527,6 +2528,7 @@ static void FreeContext(ALCcontext *context) struct ALeffectslotArray *auxslots; struct ALlistenerProps *lprops; size_t count; + ALsizei i; TRACE("%p\n", context); @@ -2549,6 +2551,8 @@ static void FreeContext(ALCcontext *context) } ResetUIntMap(&context->EffectSlotMap); + for(i = 0;i < context->VoiceCount;i++) + DeinitVoice(context->Voices[i]); al_free(context->Voices); context->Voices = NULL; context->VoiceCount = 0; @@ -2706,7 +2710,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) { ALCdevice *device = context->Device; ALsizei num_sends = device->NumAuxSends; - struct ALsourceProps *props; + struct ALvoiceProps *props; size_t sizeof_props; size_t sizeof_voice; ALvoice **voices; @@ -2721,7 +2725,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - sizeof_props = RoundUp(offsetof(struct ALsourceProps, Send[num_sends]), 16); + sizeof_props = RoundUp(offsetof(struct ALvoiceProps, Send[num_sends]), 16); sizeof_voice = RoundUp(offsetof(ALvoice, Send[num_sends]), 16); size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; @@ -2730,7 +2734,7 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * paired together. */ voice = (ALvoice*)((char*)voices + RoundUp(num_voices*sizeof(ALvoice*), 16)); - props = (struct ALsourceProps*)((char*)voice + sizeof_voice); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); if(context->Voices) { @@ -2738,17 +2742,18 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) for(;v < v_count;v++) { ALsizei s_count = mini(old_sends, num_sends); + ALvoice *old_voice = context->Voices[v]; ALsizei i; /* Copy the old voice data and source property set to the new * storage. */ - *voice = *(context->Voices[v]); + *voice = *old_voice; for(i = 0;i < s_count;i++) - voice->Send[i] = context->Voices[v]->Send[i]; - *props = *(context->Voices[v]->Props); + voice->Send[i] = old_voice->Send[i]; + *props = *(old_voice->Props); for(i = 0;i < s_count;i++) - props->Send[i] = context->Voices[v]->Props->Send[i]; + props->Send[i] = old_voice->Props->Send[i]; /* Set this voice's property set pointer and voice reference. */ voice->Props = props; @@ -2756,17 +2761,27 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) /* Increment pointers to the next storage space. */ voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALsourceProps*)((char*)voice + sizeof_voice); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); } + /* Deinit any left over voices that weren't copied over to the new + * array. NOTE: If this does anything, v equals num_voices and + * num_voices is less than VoiceCount, so the following loop won't do + * anything. + */ + for(;v < context->VoiceCount;v++) + DeinitVoice(context->Voices[v]); } /* Finish setting the voices' property set pointers and references. */ for(;v < num_voices;v++) { + ATOMIC_INIT(&voice->Update, NULL); + ATOMIC_INIT(&voice->FreeList, NULL); + voice->Props = props; voices[v] = voice; voice = (ALvoice*)((char*)props + sizeof_props); - props = (struct ALsourceProps*)((char*)voice + sizeof_voice); + props = (struct ALvoiceProps*)((char*)voice + sizeof_voice); } al_free(context->Voices); diff --git a/Alc/ALu.c b/Alc/ALu.c index 89689fba..4a4709b0 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -100,6 +100,31 @@ const aluMatrixf IdentityMatrixf = {{ }}; +void DeinitVoice(ALvoice *voice) +{ + struct ALvoiceProps *props; + size_t count = 0; + + props = ATOMIC_EXCHANGE_PTR_SEQ(&voice->Update, NULL); + if(props) al_free(props); + + props = ATOMIC_EXCHANGE_PTR(&voice->FreeList, NULL, almemory_order_relaxed); + while(props) + { + struct ALvoiceProps *next; + next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); + al_free(props); + props = next; + ++count; + } + /* This is excessively spammy if it traces every voice destruction, so just + * warn if it was unexpectedly large. + */ + if(count > 3) + WARN("Freed "SZFMT" voice property objects\n", count); +} + + static inline HrtfDirectMixerFunc SelectHrtfMixer(void) { #ifdef HAVE_NEON @@ -324,7 +349,7 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) } -static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } @@ -749,7 +774,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALsourceProps * } } -static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; @@ -1247,24 +1272,24 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALsourceProps *pro } } -static void CalcSourceParams(ALvoice *voice, ALsource *source, ALCcontext *context, ALboolean force) +static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean force) { const ALbufferlistitem *BufferListItem; - struct ALsourceProps *props; + struct ALvoiceProps *props; - props = ATOMIC_EXCHANGE_PTR(&source->Update, NULL, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&voice->Update, NULL, almemory_order_acq_rel); if(!props && !force) return; if(props) { memcpy(voice->Props, props, - offsetof(struct ALsourceProps, Send[context->Device->NumAuxSends]) + offsetof(struct ALvoiceProps, Send[context->Device->NumAuxSends]) ); - ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props); + ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props); } - BufferListItem = ATOMIC_LOAD(&source->queue, almemory_order_relaxed); + BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); while(BufferListItem != NULL) { const ALbuffer *buffer; @@ -1299,7 +1324,7 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray for(;voice != voice_end;++voice) { source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire); - if(source) CalcSourceParams(*voice, source, ctx, force); + if(source) CalcSourceParams(*voice, ctx, force); } } IncrementRef(&ctx->UpdateCount); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 5b1e2547..265a8f47 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -15,7 +15,6 @@ extern "C" { struct ALbuffer; struct ALsource; -struct ALsourceProps; typedef struct ALbufferlistitem { @@ -24,59 +23,6 @@ typedef struct ALbufferlistitem { } ALbufferlistitem; -struct ALsourceProps { - ATOMIC(struct ALsourceProps*) next; - - ALfloat Pitch; - ALfloat Gain; - ALfloat OuterGain; - ALfloat MinGain; - ALfloat MaxGain; - ALfloat InnerAngle; - ALfloat OuterAngle; - ALfloat RefDistance; - ALfloat MaxDistance; - ALfloat RollOffFactor; - ALfloat Position[3]; - ALfloat Velocity[3]; - ALfloat Direction[3]; - ALfloat Orientation[2][3]; - ALboolean HeadRelative; - enum DistanceModel DistanceModel; - ALboolean DirectChannels; - - ALboolean DryGainHFAuto; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat OuterGainHF; - - ALfloat AirAbsorptionFactor; - ALfloat RoomRolloffFactor; - ALfloat DopplerFactor; - - ALfloat StereoPan[2]; - - ALfloat Radius; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct { - struct ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[]; -}; - - typedef struct ALsource { /** Source properties. */ ALfloat Pitch; @@ -151,9 +97,6 @@ typedef struct ALsource { ATOMIC_FLAG PropsClean; - ATOMIC(struct ALsourceProps*) Update; - ATOMIC(struct ALsourceProps*) FreeList; - /** Self ID */ ALuint id; } ALsource; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6c3f3499..a2ba4fae 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -35,7 +35,6 @@ extern "C" { #endif struct ALsource; -struct ALsourceProps; struct ALbufferlistitem; struct ALvoice; struct ALeffectslot; @@ -153,13 +152,69 @@ typedef struct SendParams { } Gains; } SendParams; + +struct ALvoiceProps { + ATOMIC(struct ALvoiceProps*) next; + + ALfloat Pitch; + ALfloat Gain; + ALfloat OuterGain; + ALfloat MinGain; + ALfloat MaxGain; + ALfloat InnerAngle; + ALfloat OuterAngle; + ALfloat RefDistance; + ALfloat MaxDistance; + ALfloat RollOffFactor; + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Direction[3]; + ALfloat Orientation[2][3]; + ALboolean HeadRelative; + enum DistanceModel DistanceModel; + ALboolean DirectChannels; + + ALboolean DryGainHFAuto; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + ALfloat OuterGainHF; + + ALfloat AirAbsorptionFactor; + ALfloat RoomRolloffFactor; + ALfloat DopplerFactor; + + ALfloat StereoPan[2]; + + ALfloat Radius; + + /** Direct filter and auxiliary send info. */ + struct { + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Direct; + struct { + struct ALeffectslot *Slot; + ALfloat Gain; + ALfloat GainHF; + ALfloat HFReference; + ALfloat GainLF; + ALfloat LFReference; + } Send[]; +}; + /* If not 'moving', gain targets are used directly without fading. */ #define VOICE_IS_MOVING (1<<0) #define VOICE_IS_HRTF (1<<1) #define VOICE_HAS_NFC (1<<2) typedef struct ALvoice { - struct ALsourceProps *Props; + struct ALvoiceProps *Props; + + ATOMIC(struct ALvoiceProps*) Update; + ATOMIC(struct ALvoiceProps*) FreeList; ATOMIC(struct ALsource*) Source; ATOMIC(bool) Playing; @@ -209,6 +264,8 @@ typedef struct ALvoice { } Send[]; } ALvoice; +void DeinitVoice(ALvoice *voice); + typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 040078df..dcf9821e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -49,7 +49,7 @@ extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); -static void UpdateSourceProps(ALsource *source, ALsizei num_sends); +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends); static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); @@ -430,8 +430,10 @@ static ALint Int64ValsByProp(ALenum prop) } while(0) #define DO_UPDATEPROPS() do { \ - if(SourceShouldUpdate(Source, Context)) \ - UpdateSourceProps(Source, device->NumAuxSends); \ + ALvoice *voice; \ + if(SourceShouldUpdate(Source, Context) && \ + (voice=GetSourceVoice(Source, Context)) != NULL) \ + UpdateSourceProps(Source, voice, device->NumAuxSends); \ else \ ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); \ } while(0) @@ -896,16 +898,20 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { + ALvoice *voice; /* Add refcount on the new slot, and release the previous slot */ if(slot) IncrementRef(&slot->ref); if(Source->Send[values[1]].Slot) DecrementRef(&Source->Send[values[1]].Slot->ref); Source->Send[values[1]].Slot = slot; - /* We must force an update if the auxiliary slot changed on a - * playing source, in case the slot is about to be deleted. + /* We must force an update if the auxiliary slot changed on an + * active source, in case the slot is about to be deleted. */ - UpdateSourceProps(Source, device->NumAuxSends); + if((voice=GetSourceVoice(Source, Context)) != NULL) + UpdateSourceProps(Source, voice, device->NumAuxSends); + else + ATOMIC_FLAG_CLEAR(&Source->PropsClean, almemory_order_release); } else { @@ -2450,9 +2456,6 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) break; } - ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire); - UpdateSourceProps(source, device->NumAuxSends); - /* Make sure this source isn't already active, and if not, look for an * unused voice to put it in. */ @@ -2468,7 +2471,9 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(voice == NULL) voice = context->Voices[context->VoiceCount++]; ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - ATOMIC_THREAD_FENCE(almemory_order_acquire); + + ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire); + UpdateSourceProps(source, voice, device->NumAuxSends); /* A source that's not playing or paused has any offset applied when it * starts playing. @@ -2973,36 +2978,13 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) * ignore the test. */ ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed); - - ATOMIC_INIT(&Source->Update, NULL); - ATOMIC_INIT(&Source->FreeList, NULL); } static void DeinitSource(ALsource *source, ALsizei num_sends) { ALbufferlistitem *BufferList; - struct ALsourceProps *props; - size_t count = 0; ALsizei i; - props = ATOMIC_LOAD_SEQ(&source->Update); - if(props) al_free(props); - - props = ATOMIC_LOAD(&source->FreeList, almemory_order_relaxed); - while(props) - { - struct ALsourceProps *next; - next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - al_free(props); - props = next; - ++count; - } - /* This is excessively spammy if it traces every source destruction, so - * just warn if it was unexpectedly large. - */ - if(count > 3) - WARN("Freed "SZFMT" Source property objects\n", count); - BufferList = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, NULL); while(BufferList != NULL) { @@ -3026,21 +3008,21 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) } } -static void UpdateSourceProps(ALsource *source, ALsizei num_sends) +static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends) { - struct ALsourceProps *props; + struct ALvoiceProps *props; ALsizei i; /* Get an unused property container, or allocate a new one as needed. */ - props = ATOMIC_LOAD(&source->FreeList, almemory_order_acquire); + props = ATOMIC_LOAD(&voice->FreeList, almemory_order_acquire); if(!props) - props = al_calloc(16, offsetof(struct ALsourceProps, Send[num_sends])); + props = al_calloc(16, offsetof(struct ALvoiceProps, Send[num_sends])); else { - struct ALsourceProps *next; + struct ALvoiceProps *next; do { next = ATOMIC_LOAD(&props->next, almemory_order_relaxed); - } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&source->FreeList, &props, next, + } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&voice->FreeList, &props, next, almemory_order_acq_rel, almemory_order_acquire) == 0); } @@ -3102,13 +3084,13 @@ static void UpdateSourceProps(ALsource *source, ALsizei num_sends) } /* Set the new container for updating internal parameters. */ - props = ATOMIC_EXCHANGE_PTR(&source->Update, props, almemory_order_acq_rel); + props = ATOMIC_EXCHANGE_PTR(&voice->Update, props, almemory_order_acq_rel); if(props) { /* If there was an unused update container, put it back in the * freelist. */ - ATOMIC_REPLACE_HEAD(struct ALsourceProps*, &source->FreeList, props); + ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props); } } @@ -3121,8 +3103,8 @@ void UpdateAllSourceProps(ALCcontext *context) { ALvoice *voice = context->Voices[pos]; ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire); - if(source != NULL && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) - UpdateSourceProps(source, num_sends); + if(source && !ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acq_rel)) + UpdateSourceProps(source, voice, num_sends); } } -- cgit v1.2.3 From 45d52f7124312c91ec0259fbb0c72346ee36e03b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Apr 2017 21:31:20 -0700 Subject: Remove unnecessary functions in the JACK backend --- Alc/backends/jack.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index f43f8527..85d5d9c5 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -163,8 +163,8 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self); static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples) static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self); -static void ALCjackPlayback_lock(ALCjackPlayback *self); -static void ALCjackPlayback_unlock(ALCjackPlayback *self); +static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback) DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback); @@ -248,7 +248,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) ll_ringbuffer_data_t data[2]; jack_nframes_t total = 0; jack_nframes_t todo; - ALuint i, c, numchans; + ALsizei i, c, numchans; ll_ringbuffer_get_read_vector(self->Ring, data); @@ -260,7 +260,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) for(c = 0;c < numchans;c++) { const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c; - for(i = 0;i < todo;i++) + for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; } @@ -272,7 +272,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) for(c = 0;c < numchans;c++) { const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c; - for(i = 0;i < todo;i++) + for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = in[i*numchans]; out[c] += todo; } @@ -287,7 +287,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) todo = numframes-total; for(c = 0;c < numchans;c++) { - for(i = 0;i < todo;i++) + for(i = 0;(jack_nframes_t)i < todo;i++) out[c][i] = 0.0f; } } @@ -397,7 +397,7 @@ static void ALCjackPlayback_close(ALCjackPlayback *self) static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALuint numchans, i; + ALsizei numchans, i; ALuint bufsize; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -471,7 +471,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) { const char **ports; - ALuint i; + ALsizei i; if(jack_activate(self->Client)) { @@ -544,17 +544,6 @@ static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self) } -static void ALCjackPlayback_lock(ALCjackPlayback *self) -{ - almtx_lock(&STATIC_CAST(ALCbackend,self)->mMutex); -} - -static void ALCjackPlayback_unlock(ALCjackPlayback *self) -{ - almtx_unlock(&STATIC_CAST(ALCbackend,self)->mMutex); -} - - static void jack_msg_handler(const char *message) { WARN("%s\n", message); -- cgit v1.2.3 From de62ab97e912525f20272153f6a4c896e833839d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Apr 2017 00:58:33 -0700 Subject: Store the source queue head in the voice to signify looping This removes the need to access a couple more source fields in the mixer, and also makes the looping and queue fields non-atomic. --- Alc/mixer.c | 21 ++-- OpenAL32/Include/alSource.h | 5 +- OpenAL32/Include/alu.h | 11 +- OpenAL32/alSource.c | 279 +++++++++++++++++++++----------------------- 4 files changed, 153 insertions(+), 163 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 90f3e05e..8996499d 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -268,6 +268,7 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { ALbufferlistitem *BufferListItem; + ALbufferlistitem *BufferLoopItem; ALsizei NumChannels, SampleSize; ResamplerFunc Resample; ALsizei DataPosInt; @@ -278,16 +279,15 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei OutPos; ALsizei IrSize; bool isplaying; - bool islooping; ALsizei chan; ALsizei send; /* Get source info */ isplaying = true; /* Will only be called while playing. */ - islooping = ATOMIC_LOAD(&Source->looping, almemory_order_acquire); - DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); + DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); NumChannels = voice->NumChannels; SampleSize = voice->SampleSize; increment = voice->Step; @@ -345,9 +345,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Data += chan*SampleSize; /* If current pos is beyond the loop range, do not loop */ - if(!islooping || DataPosInt >= ALBuffer->LoopEnd) + if(!BufferLoopItem || DataPosInt >= ALBuffer->LoopEnd) { - islooping = false; + BufferLoopItem = NULL; /* Load what's left to play from the source buffer, and * clear the rest of the temp buffer */ @@ -415,8 +415,8 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } } tmpiter = tmpiter->next; - if(!tmpiter && islooping) - tmpiter = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); + if(!tmpiter && BufferLoopItem) + tmpiter = BufferLoopItem; else if(!tmpiter) { SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); @@ -602,7 +602,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei break; } - if(islooping && Source->SourceType == AL_STATIC) + if(BufferLoopItem && Source->SourceType == AL_STATIC) { assert(LoopEnd > LoopStart); DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; @@ -614,12 +614,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if(!(BufferListItem=BufferListItem->next)) { - if(islooping) - BufferListItem = ATOMIC_LOAD(&Source->queue, almemory_order_acquire); - else + if(!(BufferListItem=BufferLoopItem)) { isplaying = false; - BufferListItem = NULL; DataPosInt = 0; DataPosFrac = 0; break; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 265a8f47..795ddf24 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -40,6 +40,7 @@ typedef struct ALsource { ALfloat Direction[3]; ALfloat Orientation[2][3]; ALboolean HeadRelative; + ALboolean Looping; enum DistanceModel DistanceModel; ALboolean DirectChannels; @@ -91,9 +92,7 @@ typedef struct ALsource { /** Source Buffer Queue head. */ RWLock queue_lock; - ATOMIC(ALbufferlistitem*) queue; - - ATOMIC(ALboolean) looping; + ALbufferlistitem *queue; ATOMIC_FLAG PropsClean; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a2ba4fae..96c7d4c4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -219,9 +219,6 @@ typedef struct ALvoice { ATOMIC(struct ALsource*) Source; ATOMIC(bool) Playing; - /* Current buffer queue item being played. */ - ATOMIC(struct ALbufferlistitem*) current_buffer; - /** * Source offset in samples, relative to the currently playing buffer, NOT * the whole queue, and the fractional (fixed-point) offset to the next @@ -230,6 +227,14 @@ typedef struct ALvoice { ATOMIC(ALuint) position; ATOMIC(ALsizei) position_fraction; + /* Current buffer queue item being played. */ + ATOMIC(struct ALbufferlistitem*) current_buffer; + + /* Buffer queue item to loop to at end of queue (will be NULL for non- + * looping voices). + */ + ATOMIC(struct ALbufferlistitem*) loop_buffer; + /** * Number of channels and bytes-per-sample for the attached source's * buffer(s). diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index dcf9821e..236188cf 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -674,7 +674,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALfilter *filter = NULL; ALeffectslot *slot = NULL; ALbufferlistitem *oldlist; - ALbufferlistitem *newlist; ALfloat fvals[6]; switch(prop) @@ -700,15 +699,24 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); WriteLock(&Source->queue_lock); - ATOMIC_STORE_SEQ(&Source->looping, *values); - if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) == AL_PLAYING) + Source->Looping = (ALboolean)*values; + if(IsPlayingOrPaused(Source)) { - /* If the source is playing, wait for the current mix to finish - * to ensure it isn't currently looping back or reaching the - * end. - */ - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); + ALvoice *voice = GetSourceVoice(Source, Context); + if(voice) + { + if(Source->Looping) + ATOMIC_STORE(&voice->loop_buffer, Source->queue, almemory_order_release); + else + ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_release); + + /* If the source is playing, wait for the current mix to finish + * to ensure it isn't currently looping back or reaching the + * end. + */ + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + } } WriteUnlock(&Source->queue_lock); return AL_TRUE; @@ -732,24 +740,25 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } } + oldlist = Source->queue; if(buffer != NULL) { /* Add the selected buffer to a one-item queue */ - newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); + ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); newlist->buffer = buffer; newlist->next = NULL; IncrementRef(&buffer->ref); /* Source is now Static */ Source->SourceType = AL_STATIC; + Source->queue = newlist; } else { /* Source is now Undetermined */ Source->SourceType = AL_UNDETERMINED; - newlist = NULL; + Source->queue = NULL; } - oldlist = ATOMIC_EXCHANGE_PTR_SEQ(&Source->queue, newlist); WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -1153,7 +1162,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) + if(!(BufferList=Source->queue)) *values = 0; else { @@ -1270,13 +1279,12 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_LOOPING: - *values = ATOMIC_LOAD_SEQ(&Source->looping); + *values = Source->Looping; return AL_TRUE; case AL_BUFFER: ReadLock(&Source->queue_lock); - BufferList = (Source->SourceType == AL_STATIC) ? - ATOMIC_LOAD_SEQ(&Source->queue) : NULL; + BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL; *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0; ReadUnlock(&Source->queue_lock); return AL_TRUE; @@ -1287,7 +1295,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BYTE_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) + if(!(BufferList=Source->queue)) *values = 0; else { @@ -1326,7 +1334,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_LENGTH_SOFT: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) + if(!(BufferList=Source->queue)) *values = 0; else { @@ -1342,7 +1350,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFERS_QUEUED: ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD_SEQ(&Source->queue))) + if(!(BufferList=Source->queue)) *values = 0; else { @@ -1357,7 +1365,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFERS_PROCESSED: ReadLock(&Source->queue_lock); - if(ATOMIC_LOAD_SEQ(&Source->looping) || Source->SourceType != AL_STREAMING) + if(Source->Looping || Source->SourceType != AL_STREAMING) { /* Buffers on a looping source are in a perpetual state of * PENDING, so don't report any as PROCESSED */ @@ -1365,7 +1373,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } else { - const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue); + const ALbufferlistitem *BufferList = Source->queue; const ALbufferlistitem *Current = NULL; ALsizei played = 0; ALvoice *voice; @@ -2409,7 +2417,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* Check that there is a queue containing at least one valid, non zero * length Buffer. */ - BufferList = ATOMIC_LOAD_SEQ(&source->queue); + BufferList = source->queue; while(BufferList) { if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) @@ -2478,6 +2486,10 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* A source that's not playing or paused has any offset applied when it * starts playing. */ + if(source->Looping) + ATOMIC_STORE(&voice->loop_buffer, source->queue, almemory_order_relaxed); + else + ATOMIC_STORE(&voice->loop_buffer, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); @@ -2705,7 +2717,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu } /* Check for a valid Buffer, for its frequency and format */ - BufferList = ATOMIC_LOAD_SEQ(&source->queue); + BufferList = source->queue; while(BufferList) { if(BufferList->buffer) @@ -2788,11 +2800,10 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu /* Source is now streaming */ source->SourceType = AL_STREAMING; - BufferList = NULL; - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&source->queue, &BufferList, - BufferListStart)) + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else { - /* Queue head is not NULL, append to the end of the queue */ while(BufferList->next != NULL) BufferList = BufferList->next; BufferList->next = BufferListStart; @@ -2828,7 +2839,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if(nb == 0) goto done; WriteLock(&source->queue_lock); - if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING) + if(source->Looping || source->SourceType != AL_STREAMING) { WriteUnlock(&source->queue_lock); /* Trying to unqueue buffers on a looping or non-streaming source. */ @@ -2836,7 +2847,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Find the new buffer queue head */ - OldTail = ATOMIC_LOAD_SEQ(&source->queue); + OldTail = source->queue; Current = NULL; if((voice=GetSourceVoice(source, context)) != NULL) Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); @@ -2859,23 +2870,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } /* Swap it, and cut the new head from the old. */ - OldHead = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, OldTail->next); - if(OldTail->next) - { - ALCdevice *device = context->Device; - uint count; - - /* Once the active mix (if any) is done, it's safe to cut the old tail - * from the new head. - */ - if(((count=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) - { - while(count == ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)) - althrd_yield(); - } - ATOMIC_THREAD_FENCE(almemory_order_acq_rel); - OldTail->next = NULL; - } + OldHead = source->queue; + source->queue = OldTail->next; + OldTail->next = NULL; WriteUnlock(&source->queue_lock); while(OldHead != NULL) @@ -2940,6 +2937,9 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->AirAbsorptionFactor = 0.0f; Source->RoomRolloffFactor = 0.0f; Source->DopplerFactor = 1.0f; + Source->HeadRelative = AL_FALSE; + Source->Looping = AL_FALSE; + Source->DistanceModel = DefaultDistanceModel; Source->DirectChannels = AL_FALSE; Source->StereoPan[0] = DEG2RAD( 30.0f); @@ -2947,8 +2947,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->Radius = 0.0f; - Source->DistanceModel = DefaultDistanceModel; - Source->Direct.Gain = 1.0f; Source->Direct.GainHF = 1.0f; Source->Direct.HFReference = LOWPASSFREQREF; @@ -2970,9 +2968,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->SourceType = AL_UNDETERMINED; ATOMIC_INIT(&Source->state, AL_INITIAL); - ATOMIC_INIT(&Source->queue, NULL); - - ATOMIC_INIT(&Source->looping, AL_FALSE); + Source->queue = NULL; /* No way to do an 'init' here, so just test+set with relaxed ordering and * ignore the test. @@ -2985,7 +2981,7 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) ALbufferlistitem *BufferList; ALsizei i; - BufferList = ATOMIC_EXCHANGE_PTR_SEQ(&source->queue, NULL); + BufferList = source->queue; while(BufferList != NULL) { ALbufferlistitem *next = BufferList->next; @@ -2994,6 +2990,7 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) al_free(BufferList); BufferList = next; } + source->queue = NULL; if(source->Send) { @@ -3118,14 +3115,12 @@ void UpdateAllSourceProps(ALCcontext *context) static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { ALCdevice *device = context->Device; - const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; ALvoice *voice; ReadLock(&Source->queue_lock); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { Current = NULL; readPos = 0; @@ -3147,6 +3142,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui if(voice) { + const ALbufferlistitem *BufferList = Source->queue; while(BufferList && BufferList != Current) { if(BufferList->buffer) @@ -3168,7 +3164,6 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { ALCdevice *device = context->Device; - const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; @@ -3176,7 +3171,6 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint ALvoice *voice; ReadLock(&Source->queue_lock); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { Current = NULL; readPos = 0; @@ -3199,27 +3193,28 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint offset = 0.0; if(voice) { - const ALbuffer *Buffer = NULL; + const ALbufferlistitem *BufferList = Source->queue; + const ALbuffer *BufferFmt = NULL; while(BufferList && BufferList != Current) { const ALbuffer *buffer = BufferList->buffer; if(buffer != NULL) { - if(!Buffer) Buffer = buffer; + if(!BufferFmt) BufferFmt = buffer; readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; } BufferList = BufferList->next; } - while(BufferList && !Buffer) + while(BufferList && !BufferFmt) { - Buffer = BufferList->buffer; + BufferFmt = BufferList->buffer; BufferList = BufferList->next; } - assert(Buffer != NULL); + assert(BufferFmt != NULL); offset = (ALdouble)readPos / (ALdouble)FRACTIONONE / - (ALdouble)Buffer->Frequency; + (ALdouble)BufferFmt->Frequency; } ReadUnlock(&Source->queue_lock); @@ -3235,21 +3230,14 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { ALCdevice *device = context->Device; - const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; - const ALbuffer *Buffer = NULL; - ALboolean readFin = AL_FALSE; ALuint readPos; ALsizei readPosFrac; - ALuint totalBufferLen; - ALboolean looping; ALuint refcount; ALdouble offset; ALvoice *voice; ReadLock(&Source->queue_lock); - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); do { Current = NULL; readPos = readPosFrac = 0; @@ -3266,72 +3254,75 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(!voice) + offset = 0.0; + if(voice) { - ReadUnlock(&Source->queue_lock); - return 0.0; - } + const ALbufferlistitem *BufferList = Source->queue; + const ALbuffer *BufferFmt = NULL; + ALboolean readFin = AL_FALSE; + ALuint totalBufferLen = 0; - totalBufferLen = 0; - while(BufferList != NULL) - { - const ALbuffer *buffer; - readFin = readFin || (BufferList == Current); - if((buffer=BufferList->buffer) != NULL) + while(BufferList != NULL) { - if(!Buffer) Buffer = buffer; - totalBufferLen += buffer->SampleLen; - if(!readFin) readPos += buffer->SampleLen; + const ALbuffer *buffer; + readFin = readFin || (BufferList == Current); + if((buffer=BufferList->buffer) != NULL) + { + if(!BufferFmt) BufferFmt = buffer; + totalBufferLen += buffer->SampleLen; + if(!readFin) readPos += buffer->SampleLen; + } + BufferList = BufferList->next; } - BufferList = BufferList->next; - } - assert(Buffer != NULL); + assert(BufferFmt != NULL); - if(looping) - readPos %= totalBufferLen; - else - { - /* Wrap back to 0 */ - if(readPos >= totalBufferLen) - readPos = readPosFrac = 0; - } + if(Source->Looping) + readPos %= totalBufferLen; + else + { + /* Wrap back to 0 */ + if(readPos >= totalBufferLen) + readPos = readPosFrac = 0; + } - offset = 0.0; - switch(name) - { - case AL_SEC_OFFSET: - offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency; - break; + offset = 0.0; + switch(name) + { + case AL_SEC_OFFSET: + offset = (readPos + (ALdouble)readPosFrac/FRACTIONONE) / BufferFmt->Frequency; + break; - case AL_SAMPLE_OFFSET: - offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; - break; + case AL_SAMPLE_OFFSET: + offset = readPos + (ALdouble)readPosFrac/FRACTIONONE; + break; - case AL_BYTE_OFFSET: - if(Buffer->OriginalType == UserFmtIMA4) - { - ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels); - ALuint FrameBlockSize = Buffer->OriginalAlign; + case AL_BYTE_OFFSET: + if(BufferFmt->OriginalType == UserFmtIMA4) + { + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else if(Buffer->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (Buffer->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels); - ALuint FrameBlockSize = Buffer->OriginalAlign; + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else if(BufferFmt->OriginalType == UserFmtMSADPCM) + { + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + ALuint BlockSize = align * ChannelsFromFmt(BufferFmt->FmtChannels); + ALuint FrameBlockSize = BufferFmt->OriginalAlign; - /* Round down to nearest ADPCM block */ - offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); - } - else - { - ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); - offset = (ALdouble)(readPos * FrameSize); - } - break; + /* Round down to nearest ADPCM block */ + offset = (ALdouble)(readPos / FrameBlockSize * BlockSize); + } + else + { + ALuint FrameSize = FrameSizeFromUserFmt(BufferFmt->OriginalChannels, + BufferFmt->OriginalType); + offset = (ALdouble)(readPos * FrameSize); + } + break; + } } ReadUnlock(&Source->queue_lock); @@ -3357,7 +3348,7 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) return AL_FALSE; totalBufferLen = 0; - BufferList = ATOMIC_LOAD_SEQ(&Source->queue); + BufferList = Source->queue; while(BufferList && totalBufferLen <= offset) { Buffer = BufferList->buffer; @@ -3366,9 +3357,9 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) if(bufferLen > offset-totalBufferLen) { /* Offset is in this buffer */ - ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release); + ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release); return AL_TRUE; } @@ -3390,22 +3381,19 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) */ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac) { - const ALbuffer *Buffer = NULL; + const ALbuffer *BufferFmt = NULL; const ALbufferlistitem *BufferList; ALdouble dbloff, dblfrac; /* Find the first valid Buffer in the Queue */ - BufferList = ATOMIC_LOAD_SEQ(&Source->queue); + BufferList = Source->queue; while(BufferList) { - if(BufferList->buffer) - { - Buffer = BufferList->buffer; + if((BufferFmt=BufferList->buffer) != NULL) break; - } BufferList = BufferList->next; } - if(!Buffer) + if(!BufferFmt) { Source->OffsetType = AL_NONE; Source->Offset = 0.0; @@ -3417,20 +3405,21 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac case AL_BYTE_OFFSET: /* Determine the ByteOffset (and ensure it is block aligned) */ *offset = (ALuint)Source->Offset; - if(Buffer->OriginalType == UserFmtIMA4) + if(BufferFmt->OriginalType == UserFmtIMA4) { - ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); - *offset *= Buffer->OriginalAlign; + ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; + *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels); + *offset *= BufferFmt->OriginalAlign; } - else if(Buffer->OriginalType == UserFmtMSADPCM) + else if(BufferFmt->OriginalType == UserFmtMSADPCM) { - ALsizei align = (Buffer->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); - *offset *= Buffer->OriginalAlign; + ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; + *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels); + *offset *= BufferFmt->OriginalAlign; } else - *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); + *offset /= FrameSizeFromUserFmt(BufferFmt->OriginalChannels, + BufferFmt->OriginalType); *frac = 0; break; @@ -3441,7 +3430,7 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac break; case AL_SEC_OFFSET: - dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff); + dblfrac = modf(Source->Offset*BufferFmt->Frequency, &dbloff); *offset = (ALuint)mind(dbloff, UINT_MAX); *frac = (ALsizei)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; -- cgit v1.2.3 From 55011d4bfd46c920580d1aa6663bcfdb1e996d3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Apr 2017 14:11:15 -0700 Subject: Use a different way to get the size of structs with flexible array members --- Alc/ALc.c | 6 +++--- Alc/ALu.c | 2 +- Alc/converter.c | 2 +- Alc/hrtf.c | 4 ++-- Alc/panning.c | 4 +--- OpenAL32/Include/alMain.h | 6 ++++++ OpenAL32/alAuxEffectSlot.c | 8 ++------ OpenAL32/alSource.c | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a352cacd..ecd8fd0d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2501,7 +2501,7 @@ static ALvoid InitContext(ALCcontext *Context) InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); - auxslots = al_calloc(DEF_ALIGN, offsetof(struct ALeffectslotArray, slot[0])); + auxslots = al_calloc(DEF_ALIGN, sizeof(struct ALeffectslotArray)); auxslots->count = 0; ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots); @@ -2725,8 +2725,8 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - sizeof_props = RoundUp(offsetof(struct ALvoiceProps, Send[num_sends]), 16); - sizeof_voice = RoundUp(offsetof(ALvoice, Send[num_sends]), 16); + sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); + sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16); size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; voices = al_calloc(16, RoundUp(size*num_voices, 16)); diff --git a/Alc/ALu.c b/Alc/ALu.c index 4a4709b0..da3ae9d5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1283,7 +1283,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc if(props) { memcpy(voice->Props, props, - offsetof(struct ALvoiceProps, Send[context->Device->NumAuxSends]) + FAM_SIZE(struct ALvoiceProps, Send, context->Device->NumAuxSends) ); ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props); diff --git a/Alc/converter.c b/Alc/converter.c index 99069d15..f1a3a96b 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -13,7 +13,7 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType if(numchans <= 0 || srcRate <= 0 || dstRate <= 0) return NULL; - converter = al_calloc(16, offsetof(SampleConverter, Chan[numchans])); + converter = al_calloc(16, FAM_SIZE(SampleConverter, Chan, numchans)); converter->mSrcType = srcType; converter->mDstType = dstType; converter->mNumChannels = numchans; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 23817d66..3047915b 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -688,7 +688,7 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct HrtfEntry, filename[alstr_length(filename)+1]) + FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1) ); loaded_entry->next = LoadedHrtfs; loaded_entry->handle = NULL; @@ -769,7 +769,7 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename)); loaded_entry = al_calloc(DEF_ALIGN, - offsetof(struct HrtfEntry, filename[namelen]) + FAM_SIZE(struct HrtfEntry, filename, namelen) ); loaded_entry->next = LoadedHrtfs; loaded_entry->handle = hrtf; diff --git a/Alc/panning.c b/Alc/panning.c index e4941720..5ce93b9b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -922,13 +922,11 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) }; const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA; ALsizei count = hoa_mode ? 9 : 4; - size_t sizeof_hrtfstate; ALsizei i; static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); - sizeof_hrtfstate = offsetof(DirectHrtfState, Chan[count]); - device->Hrtf = al_calloc(16, sizeof_hrtfstate); + device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count)); for(i = 0;i < count;i++) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 191bb658..3a8aabde 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -225,6 +225,12 @@ typedef ALuint64SOFT ALuint64; #define DECL_FORMAT(x, y, z) #endif +/* Calculates the size of a struct with N elements of a flexible array member. + * GCC and Clang allow offsetof(Type, fam[N]) for this, but MSVC seems to have + * trouble, so a bit more verbose workaround is needed. + */ +#define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) + #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 diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 3ec857ca..5d110500 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -118,9 +118,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo ALsizei newcount = curarray->count + n; ALCdevice *device; - newarray = al_calloc(DEF_ALIGN, - offsetof(struct ALeffectslotArray, slot[newcount]) - ); + newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); newarray->count = newcount; memcpy(newarray->slot, tmpslots, sizeof(ALeffectslot*)*n); if(curarray) @@ -170,9 +168,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * ALsizei j, k; assert(newcount >= 0); - newarray = al_calloc(DEF_ALIGN, - offsetof(struct ALeffectslotArray, slot[newcount]) - ); + newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); newarray->count = newcount; for(i = j = 0;i < newarray->count;) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 236188cf..9fc22205 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -3013,7 +3013,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send /* Get an unused property container, or allocate a new one as needed. */ props = ATOMIC_LOAD(&voice->FreeList, almemory_order_acquire); if(!props) - props = al_calloc(16, offsetof(struct ALvoiceProps, Send[num_sends])); + props = al_calloc(16, FAM_SIZE(struct ALvoiceProps, Send, num_sends)); else { struct ALvoiceProps *next; -- cgit v1.2.3 From f1be335486efacc7f1e99fd9e1974b59c5e8c160 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Apr 2017 17:39:10 -0700 Subject: Check for the upsampler to determine if HRTF uses HOA --- Alc/panning.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 5ce93b9b..993346be 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -870,7 +870,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz InitDistanceComp(device, conf, speakermap); } -static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) +static void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ static const ALfloat AmbiPoints[][2] = { @@ -920,8 +920,9 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, { { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, }; - const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA; - ALsizei count = hoa_mode ? 9 : 4; + const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = device->AmbiUp ? AmbiMatrixHOA : + AmbiMatrixFOA; + ALsizei count = device->AmbiUp ? 9 : 4; ALsizei i; static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); @@ -936,13 +937,7 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; - if(!hoa_mode) - { - device->FOAOut.Ambi = device->Dry.Ambi; - device->FOAOut.CoeffCount = device->Dry.CoeffCount; - device->FOAOut.NumChannels = 0; - } - else + if(device->AmbiUp) { memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); for(i = 0;i < 4;i++) @@ -955,6 +950,12 @@ static void InitHrtfPanning(ALCdevice *device, bool hoa_mode) ambiup_reset(device->AmbiUp, device); } + else + { + device->FOAOut.Ambi = device->Dry.Ambi; + device->FOAOut.CoeffCount = device->Dry.CoeffCount; + device->FOAOut.NumChannels = 0; + } device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); @@ -1172,8 +1173,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(device->HrtfHandle) { - bool hoa_mode; - if(old_hrtf) Hrtf_DecRef(old_hrtf); old_hrtf = NULL; @@ -1196,20 +1195,18 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf */ ambiup_free(device->AmbiUp); device->AmbiUp = NULL; - hoa_mode = false; } else { if(!device->AmbiUp) device->AmbiUp = ambiup_alloc(); - hoa_mode = true; } TRACE("%s HRTF rendering enabled, using \"%s\"\n", ((device->Render_Mode == HrtfRender) ? "Full" : "Basic"), alstr_get_cstr(device->HrtfName) ); - InitHrtfPanning(device, hoa_mode); + InitHrtfPanning(device); return; } device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; -- cgit v1.2.3 From 0407285c534392a9b1d96d4f57de26ff2be9671c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Apr 2017 12:34:45 -0700 Subject: Allocate a new context's voices after updating the device params --- Alc/ALc.c | 41 +++++++++++++++-------------------------- OpenAL32/Include/alMain.h | 1 + 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ecd8fd0d..0a36fcc3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2725,8 +2725,8 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) * property set (including the dynamically-sized Send[] array) in one * chunk. */ - sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); sizeof_voice = RoundUp(FAM_SIZE(ALvoice, Send, num_sends), 16); + sizeof_props = RoundUp(FAM_SIZE(struct ALvoiceProps, Send, num_sends), 16); size = sizeof(ALvoice*) + sizeof_voice + sizeof_props; voices = al_calloc(16, RoundUp(size*num_voices, 16)); @@ -2738,10 +2738,11 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends) if(context->Voices) { - ALsizei v_count = mini(context->VoiceCount, num_voices); + const ALsizei v_count = mini(context->VoiceCount, num_voices); + const ALsizei s_count = mini(old_sends, num_sends); + for(;v < v_count;v++) { - ALsizei s_count = mini(old_sends, num_sends); ALvoice *old_voice = context->Voices[v]; ALsizei i; @@ -3530,37 +3531,24 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)); - if(ALContext) - { - InitRef(&ALContext->ref, 1); - ALContext->Listener = (ALlistener*)ALContext->_listener_mem; - - ALContext->Device = device; - ATOMIC_INIT(&ALContext->ActiveAuxSlots, NULL); - - ALContext->Voices = NULL; - ALContext->MaxVoices = 0; - ALContext->VoiceCount = 0; - AllocateVoices(ALContext, 256, device->NumAuxSends); - } - if(!ALContext || !ALContext->Voices) + if(!ALContext) { almtx_unlock(&device->BackendLock); - if(ALContext) - { - al_free(ALContext->Voices); - ALContext->Voices = NULL; - - al_free(ALContext); - ALContext = NULL; - } - alcSetError(device, ALC_OUT_OF_MEMORY); ALCdevice_DecRef(device); return NULL; } + InitRef(&ALContext->ref, 1); + ALContext->Listener = (ALlistener*)ALContext->_listener_mem; + + ALContext->Voices = NULL; + ALContext->VoiceCount = 0; + ALContext->MaxVoices = 0; + ATOMIC_INIT(&ALContext->ActiveAuxSlots, NULL); + ALContext->Device = device; + if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { almtx_unlock(&device->BackendLock); @@ -3581,6 +3569,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCdevice_DecRef(device); return NULL; } + AllocateVoices(ALContext, 256, device->NumAuxSends); ALCdevice_IncRef(ALContext->Device); InitContext(ALContext); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3a8aabde..34635773 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From fbb5295f13711f978a1ad5a8abfc6c6d3970df0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Apr 2017 15:17:55 -0700 Subject: Fix a mixed-sign-comparison warning on MSVC --- Alc/hrtf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3047915b..d791113d 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -356,7 +356,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * if(failed) return NULL; - if(datalen < evCount*2) + if(datalen < evCount*2u) { ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen); return NULL; -- cgit v1.2.3 From 5dcbb8db38bb9aa88d3be45cf84f2e7d993acdd0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Apr 2017 19:54:17 -0700 Subject: Make the buffer list next pointer atomic --- Alc/ALu.c | 2 +- Alc/mixer.c | 8 +++--- OpenAL32/Include/alSource.h | 3 ++- OpenAL32/alSource.c | 59 ++++++++++++++++++++++++--------------------- 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index da3ae9d5..065371d1 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1301,7 +1301,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc CalcNonAttnSourceParams(voice, voice->Props, buffer, context); break; } - BufferListItem = BufferListItem->next; + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); } } diff --git a/Alc/mixer.c b/Alc/mixer.c index 8996499d..a2a56dbc 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -414,7 +414,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SrcDataSize += DataSize; } } - tmpiter = tmpiter->next; + tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); if(!tmpiter && BufferLoopItem) tmpiter = BufferLoopItem; else if(!tmpiter) @@ -612,9 +612,11 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if(DataSize > DataPosInt) break; - if(!(BufferListItem=BufferListItem->next)) + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); + if(!BufferListItem) { - if(!(BufferListItem=BufferLoopItem)) + BufferListItem = BufferLoopItem; + if(!BufferListItem) { isplaying = false; DataPosInt = 0; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 795ddf24..d069abcd 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -5,6 +5,7 @@ #include "alMain.h" #include "alu.h" #include "hrtf.h" +#include "atomic.h" #define MAX_SENDS 16 #define DEFAULT_SENDS 2 @@ -19,7 +20,7 @@ struct ALsource; typedef struct ALbufferlistitem { struct ALbuffer *buffer; - struct ALbufferlistitem *volatile next; + ATOMIC(struct ALbufferlistitem*) next; } ALbufferlistitem; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 9fc22205..0da513aa 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -746,7 +746,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p /* Add the selected buffer to a one-item queue */ ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); newlist->buffer = buffer; - newlist->next = NULL; + ATOMIC_INIT(&newlist->next, NULL); IncrementRef(&buffer->ref); /* Source is now Static */ @@ -766,7 +766,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p while(oldlist != NULL) { ALbufferlistitem *temp = oldlist; - oldlist = temp->next; + oldlist = ATOMIC_LOAD(&temp->next, almemory_order_relaxed); if(temp->buffer) DecrementRef(&temp->buffer->ref); @@ -1175,7 +1175,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p freq = buffer->Frequency; length += buffer->SampleLen; } - } while((BufferList=BufferList->next) != NULL); + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } while(BufferList != NULL); *values = (ALdouble)length / (ALdouble)freq; } ReadUnlock(&Source->queue_lock); @@ -1326,7 +1327,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p length += buffer->SampleLen / sample_align * byte_align; } - } while((BufferList=BufferList->next) != NULL); + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } while(BufferList != NULL); *values = length; } ReadUnlock(&Source->queue_lock); @@ -1342,7 +1344,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p do { ALbuffer *buffer = BufferList->buffer; if(buffer) length += buffer->SampleLen; - } while((BufferList=BufferList->next) != NULL); + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } while(BufferList != NULL); *values = length; } ReadUnlock(&Source->queue_lock); @@ -1357,7 +1360,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALsizei count = 0; do { ++count; - } while((BufferList=BufferList->next) != NULL); + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } while(BufferList != NULL); *values = count; } ReadUnlock(&Source->queue_lock); @@ -1386,7 +1390,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p while(BufferList && BufferList != Current) { played++; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } *values = played; } @@ -2422,7 +2426,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) break; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } /* If there's nothing to play, go right to stopped. */ @@ -2725,7 +2729,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferFmt = BufferList->buffer; break; } - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } LockBuffersRead(device); @@ -2747,11 +2751,12 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu } else { - BufferList->next = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); - BufferList = BufferList->next; + ALbufferlistitem *item = al_calloc(DEF_ALIGN, sizeof(ALbufferlistitem)); + ATOMIC_STORE(&BufferList->next, item, almemory_order_relaxed); + BufferList = item; } BufferList->buffer = buffer; - BufferList->next = NULL; + ATOMIC_INIT(&BufferList->next, NULL); if(!buffer) continue; /* Hold a read lock on each buffer being queued while checking all @@ -2774,7 +2779,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu * each buffer we had. */ while(BufferListStart) { - ALbufferlistitem *next = BufferListStart->next; + ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, + almemory_order_relaxed); if((buffer=BufferListStart->buffer) != NULL) { DecrementRef(&buffer->ref); @@ -2793,7 +2799,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu { ALbuffer *buffer = BufferList->buffer; if(buffer) ReadUnlock(&buffer->lock); - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } UnlockBuffersRead(device); @@ -2805,8 +2811,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu else { while(BufferList->next != NULL) - BufferList = BufferList->next; - BufferList->next = BufferListStart; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); } WriteUnlock(&source->queue_lock); @@ -2857,7 +2863,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint { for(i = 1;i < nb;i++) { - ALbufferlistitem *next = OldTail->next; + ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed); if(!next || next == Current) break; OldTail = next; } @@ -2871,13 +2877,12 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint /* Swap it, and cut the new head from the old. */ OldHead = source->queue; - source->queue = OldTail->next; - OldTail->next = NULL; + source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel); WriteUnlock(&source->queue_lock); while(OldHead != NULL) { - ALbufferlistitem *next = OldHead->next; + ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed); ALbuffer *buffer = OldHead->buffer; if(!buffer) @@ -2984,7 +2989,7 @@ static void DeinitSource(ALsource *source, ALsizei num_sends) BufferList = source->queue; while(BufferList != NULL) { - ALbufferlistitem *next = BufferList->next; + ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); if(BufferList->buffer != NULL) DecrementRef(&BufferList->buffer->ref); al_free(BufferList); @@ -3147,7 +3152,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui { if(BufferList->buffer) readPos += (ALuint64)BufferList->buffer->SampleLen << 32; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } readPos = minu64(readPos, U64(0x7fffffffffffffff)); } @@ -3203,13 +3208,13 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint if(!BufferFmt) BufferFmt = buffer; readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; } - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } while(BufferList && !BufferFmt) { BufferFmt = BufferList->buffer; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } assert(BufferFmt != NULL); @@ -3272,7 +3277,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte totalBufferLen += buffer->SampleLen; if(!readFin) readPos += buffer->SampleLen; } - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } assert(BufferFmt != NULL); @@ -3365,7 +3370,7 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) totalBufferLen += bufferLen; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } /* Offset is out of range of the queue */ @@ -3391,7 +3396,7 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac { if((BufferFmt=BufferList->buffer) != NULL) break; - BufferList = BufferList->next; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } if(!BufferFmt) { -- cgit v1.2.3 From 63baa3b1c712317e7826de6f28ecc865d1fb9b58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Apr 2017 03:14:49 -0700 Subject: Missed a raw atomic variable access --- OpenAL32/alSource.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 0da513aa..757c96db 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2810,8 +2810,9 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu source->queue = BufferListStart; else { - while(BufferList->next != NULL) - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + ALbufferlistitem *next; + while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + BufferList = next; ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); } WriteUnlock(&source->queue_lock); -- cgit v1.2.3 From 7776ebcedc780409058b953a932ba854d33ef084 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Apr 2017 20:58:32 -0700 Subject: Try NEON mixers before SSE --- Alc/mixer.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index a2a56dbc..f326fdfe 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -55,27 +55,26 @@ static ResamplerFunc ResampleSamples = Resample_point32_C; MixerFunc SelectMixer(void) { -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; -#endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return Mix_Neon; #endif - +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_SSE; +#endif return Mix_C; } RowMixerFunc SelectRowMixer(void) { -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_SSE; -#endif #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) return MixRow_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_SSE; #endif return MixRow_C; } -- cgit v1.2.3 From 1e8ea59564d4082e164f2a7707df90b00f48a35b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Apr 2017 23:21:46 -0700 Subject: Make the default resampler a variable --- Alc/mixer.c | 17 +++++++++-------- OpenAL32/Include/alu.h | 3 +-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index f326fdfe..b1d014a7 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -49,6 +49,8 @@ static_assert(MAX_PRE_SAMPLES >= 11, "MAX_PRE_SAMPLES must be at least 11!"); static_assert(MAX_POST_SAMPLES >= 12, "MAX_POST_SAMPLES must be at least 12!"); +enum Resampler ResamplerDefault = LinearResampler; + static MixerFunc MixSamples = Mix_C; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; static ResamplerFunc ResampleSamples = Resample_point32_C; @@ -145,30 +147,29 @@ ResamplerFunc SelectResampler(enum Resampler resampler) void aluInitMixer(void) { - enum Resampler resampler = ResamplerDefault; const char *str; if(ConfigValueStr(NULL, NULL, "resampler", &str)) { if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) - resampler = PointResampler; + ResamplerDefault = PointResampler; else if(strcasecmp(str, "linear") == 0) - resampler = LinearResampler; + ResamplerDefault = LinearResampler; else if(strcasecmp(str, "sinc4") == 0) - resampler = FIR4Resampler; + ResamplerDefault = FIR4Resampler; else if(strcasecmp(str, "bsinc") == 0) - resampler = BSincResampler; + ResamplerDefault = BSincResampler; else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 0) { WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str); - resampler = FIR4Resampler; + ResamplerDefault = FIR4Resampler; } else { char *end; long n = strtol(str, &end, 0); if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - resampler = n; + ResamplerDefault = n; else WARN("Invalid resampler: %s\n", str); } @@ -176,7 +177,7 @@ void aluInitMixer(void) MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); - ResampleSamples = SelectResampler(resampler); + ResampleSamples = SelectResampler(ResamplerDefault); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 96c7d4c4..9b267d15 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -369,9 +369,8 @@ enum Resampler { LinearResampler, FIR4Resampler, BSincResampler, - - ResamplerDefault = LinearResampler }; +extern enum Resampler ResamplerDefault; enum HrtfRequestMode { Hrtf_Default = 0, -- cgit v1.2.3 From 26b49c54afb9868115e495098ce69f2d2487c932 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 00:06:40 -0700 Subject: Store the resampler as part of the source --- Alc/ALu.c | 2 ++ Alc/mixer.c | 4 +--- OpenAL32/Include/alSource.h | 1 + OpenAL32/Include/alu.h | 30 ++++++++++++++++-------------- OpenAL32/alSource.c | 2 ++ 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 065371d1..baa94148 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -455,6 +455,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p else voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); BsincPrepare(voice->Step, &voice->ResampleState.bsinc); + voice->Resampler = SelectResampler(props->Resampler); /* Calculate gains */ DryGain = clampf(SourceVolume, MinVolume, MaxVolume); @@ -1095,6 +1096,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop else voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); BsincPrepare(voice->Step, &voice->ResampleState.bsinc); + voice->Resampler = SelectResampler(props->Resampler); voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC); if(Device->Render_Mode == HrtfRender) diff --git a/Alc/mixer.c b/Alc/mixer.c index b1d014a7..2070f859 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -53,7 +53,6 @@ enum Resampler ResamplerDefault = LinearResampler; static MixerFunc MixSamples = Mix_C; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; -static ResamplerFunc ResampleSamples = Resample_point32_C; MixerFunc SelectMixer(void) { @@ -177,7 +176,6 @@ void aluInitMixer(void) MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); - ResampleSamples = SelectResampler(ResamplerDefault); } @@ -295,7 +293,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_copy32_C : ResampleSamples); + Resample_copy32_C : voice->Resampler); Counter = (voice->Flags&VOICE_IS_MOVING) ? SamplesToDo : 0; OutPos = 0; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index d069abcd..f9cbc55b 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -43,6 +43,7 @@ typedef struct ALsource { ALboolean HeadRelative; ALboolean Looping; enum DistanceModel DistanceModel; + enum Resampler Resampler; ALboolean DirectChannels; ALboolean DryGainHFAuto; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 9b267d15..071ef3d2 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -40,6 +40,14 @@ struct ALvoice; struct ALeffectslot; +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + BSincResampler, +}; +extern enum Resampler ResamplerDefault; + /* The number of distinct scale and phase intervals within the filter table. */ #define BSINC_SCALE_BITS 4 #define BSINC_SCALE_COUNT (1<HeadRelative = AL_FALSE; Source->Looping = AL_FALSE; Source->DistanceModel = DefaultDistanceModel; + Source->Resampler = ResamplerDefault; Source->DirectChannels = AL_FALSE; Source->StereoPan[0] = DEG2RAD( 30.0f); @@ -3054,6 +3055,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send } props->HeadRelative = source->HeadRelative; props->DistanceModel = source->DistanceModel; + props->Resampler = source->Resampler; props->DirectChannels = source->DirectChannels; props->DryGainHFAuto = source->DryGainHFAuto; -- cgit v1.2.3 From b59359f80f45512210f37b8a8cd4c250d78dd37d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 04:15:08 -0700 Subject: Add a method to enumerate resamplers --- Alc/ALc.c | 7 ++++ OpenAL32/Include/alMain.h | 13 +++++++ OpenAL32/Include/alu.h | 2 ++ OpenAL32/alState.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0a36fcc3..175cb139 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -287,6 +287,8 @@ static const struct { DECL(alBufferSamplesSOFT), DECL(alGetBufferSamplesSOFT), DECL(alIsBufferFormatSupportedSOFT), + + DECL(alGetStringiSOFT), }; #undef DECL @@ -692,6 +694,11 @@ static const struct { DECL(AL_EQUALIZER_HIGH_CUTOFF), DECL(AL_DEDICATED_GAIN), + + DECL(AL_NUM_RESAMPLERS_SOFT), + DECL(AL_DEFAULT_RESAMPLER_SOFT), + DECL(AL_SOURCE_RESAMPLER_SOFT), + DECL(AL_RESAMPLER_NAME_SOFT), }; #undef DECL diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 34635773..7f5c0aa8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -139,6 +139,19 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif #endif +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x7fff0000 +#define AL_DEFAULT_RESAMPLER_SOFT 0x7fff0001 +#define AL_SOURCE_RESAMPLER_SOFT 0x7fff0003 +#define AL_RESAMPLER_NAME_SOFT 0x7fff0004 + +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 071ef3d2..c6706bad 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -45,6 +45,8 @@ enum Resampler { LinearResampler, FIR4Resampler, BSincResampler, + + ResamplerMax = BSincResampler }; extern enum Resampler ResamplerDefault; diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index eddd2999..231e2192 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -47,6 +47,12 @@ static const ALchar alErrInvalidValue[] = "Invalid Value"; static const ALchar alErrInvalidOp[] = "Invalid Operation"; static const ALchar alErrOutOfMemory[] = "Out of Memory"; +/* Resampler strings */ +static const ALchar alPointResampler[] = "Zero-Order Hold (Point)"; +static const ALchar alLinearResampler[] = "Linear"; +static const ALchar alSinc4Resampler[] = "4-Point Sinc"; +static const ALchar alBSincResampler[] = "Band-limited Sinc (12/24)"; + AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) { ALCcontext *context; @@ -161,6 +167,15 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) value = AL_TRUE; break; + case AL_NUM_RESAMPLERS_SOFT: + /* Always non-0. */ + value = AL_TRUE; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault ? AL_TRUE : AL_FALSE; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -206,6 +221,14 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) value = (ALdouble)GAIN_MIX_MAX/context->GainBoost; break; + case AL_NUM_RESAMPLERS_SOFT: + value = (ALdouble)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALdouble)ResamplerDefault; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -251,6 +274,14 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) value = GAIN_MIX_MAX/context->GainBoost; break; + case AL_NUM_RESAMPLERS_SOFT: + value = (ALfloat)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALfloat)ResamplerDefault; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -296,6 +327,14 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) value = (ALint)(GAIN_MIX_MAX/context->GainBoost); break; + case AL_NUM_RESAMPLERS_SOFT: + value = ResamplerMax + 1; + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = ResamplerDefault; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -341,6 +380,14 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) value = (ALint64SOFT)(GAIN_MIX_MAX/context->GainBoost); break; + case AL_NUM_RESAMPLERS_SOFT: + value = (ALint64SOFT)(ResamplerMax + 1); + break; + + case AL_DEFAULT_RESAMPLER_SOFT: + value = (ALint64SOFT)ResamplerDefault; + break; + default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -365,6 +412,8 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: values[0] = alGetBoolean(pname); return; } @@ -399,6 +448,8 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: values[0] = alGetDouble(pname); return; } @@ -433,6 +484,8 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: values[0] = alGetFloat(pname); return; } @@ -467,6 +520,8 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: values[0] = alGetInteger(pname); return; } @@ -499,6 +554,8 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: values[0] = alGetInteger64SOFT(pname); return; } @@ -687,3 +744,36 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) ALCcontext_DecRef(context); } + + +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) +{ + const char *ResamplerNames[] = { + alPointResampler, alLinearResampler, + alSinc4Resampler, alBSincResampler, + }; + const ALchar *value = NULL; + ALCcontext *context; + + static_assert(COUNTOF(ResamplerNames) == ResamplerMax+1, "Incorrect ResamplerNames list"); + + context = GetContextRef(); + if(!context) return NULL; + + switch(pname) + { + case AL_RESAMPLER_NAME_SOFT: + if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + value = ResamplerNames[index]; + break; + + default: + SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + } + +done: + ALCcontext_DecRef(context); + + return value; +} -- cgit v1.2.3 From 44f026220fba39a3211b82d5c1fa5ad071ea461e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 13:26:29 -0700 Subject: Correctly enable the ambisonic upsampler for HOA output --- Alc/panning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 993346be..4dcd607b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1077,7 +1077,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf { bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; - if(device->FmtChans == DevFmtAmbi3D && device->AmbiOrder == 1) + if(device->FmtChans == DevFmtAmbi3D && device->AmbiOrder > 1) { if(!device->AmbiUp) device->AmbiUp = ambiup_alloc(); -- cgit v1.2.3 From d2d5f1d7bd8afa6b1c483c106bec88eec1d3923c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 15:48:39 -0700 Subject: Add the ability to change the source resampler --- Alc/ALc.c | 3 ++- OpenAL32/alSource.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 175cb139..808580f3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -732,7 +732,8 @@ static const ALchar alExtList[] = "AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES " "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " - "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length"; + "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length " + "AL_SOFTX_source_resampler"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1caea5ef..23b4fb5a 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -116,6 +116,9 @@ typedef enum SourceProp { /* AL_EXT_BFORMAT */ srcOrientation = AL_ORIENTATION, + + /* AL_SOFT_source_resampler */ + srcResampler = AL_SOURCE_RESAMPLER_SOFT, } SourceProp; static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); @@ -214,6 +217,7 @@ static ALint FloatValsByProp(ALenum prop) case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: return 1; case AL_STEREO_ANGLES: @@ -277,6 +281,7 @@ static ALint DoubleValsByProp(ALenum prop) case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: return 1; case AL_SEC_OFFSET_LATENCY_SOFT: @@ -341,6 +346,7 @@ static ALint IntValsByProp(ALenum prop) case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: return 1; case AL_POSITION: @@ -401,6 +407,7 @@ static ALint Int64ValsByProp(ALenum prop) case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: + case AL_SOURCE_RESAMPLER_SOFT: return 1; case AL_SAMPLE_OFFSET_LATENCY_SOFT: @@ -648,6 +655,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: + case AL_SOURCE_RESAMPLER_SOFT: ival = (ALint)values[0]; return SetSourceiv(Source, Context, prop, &ival); @@ -873,6 +881,13 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p DO_UPDATEPROPS(); return AL_TRUE; + case AL_SOURCE_RESAMPLER_SOFT: + CHECKVAL(*values >= 0 && *values <= ResamplerMax); + + Source->Resampler = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + case AL_AUXILIARY_SEND_FILTER: LockEffectSlotsRead(Context); @@ -1013,6 +1028,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); ivals[0] = (ALint)*values; @@ -1252,6 +1268,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BYTE_LENGTH_SOFT: case AL_SAMPLE_LENGTH_SOFT: case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) *values = (ALdouble)ivals[0]; return err; @@ -1421,6 +1438,10 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values = Source->DistanceModel; return AL_TRUE; + case AL_SOURCE_RESAMPLER_SOFT: + *values = Source->Resampler; + return AL_TRUE; + /* 1x float/double */ case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: @@ -1579,6 +1600,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: case AL_DISTANCE_MODEL: + case AL_SOURCE_RESAMPLER_SOFT: if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) *values = ivals[0]; return err; -- cgit v1.2.3 From d85177cd3e687f19e080fde68642d1f7e080f129 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 16:26:22 -0700 Subject: Use more sensible values for the source resampler enums --- OpenAL32/Include/alMain.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7f5c0aa8..b604c547 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -141,10 +141,10 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #ifndef AL_SOFT_source_resampler #define AL_SOFT_source_resampler -#define AL_NUM_RESAMPLERS_SOFT 0x7fff0000 -#define AL_DEFAULT_RESAMPLER_SOFT 0x7fff0001 -#define AL_SOURCE_RESAMPLER_SOFT 0x7fff0003 -#define AL_RESAMPLER_NAME_SOFT 0x7fff0004 +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); #ifdef AL_ALEXT_PROTOTYPES -- cgit v1.2.3 From a0a41921fc28a1ff76a5850936cb32e912887735 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Apr 2017 16:58:55 -0700 Subject: Remove const from _Atomic vars to make Clang happy Clang does not allow using C11's atomic_load on const _Atomic variables. Previously it just disabled use of C11 atomics if atomic_load didn't work on a const _Atomic variable, but I think I'd prefer to have Clang use C11 atomics for the added features (more explicit memory ordering) even if it means a few instances of breaking const. --- Alc/ALu.c | 2 +- Alc/alcRing.c | 20 ++++++++++++-------- CMakeLists.txt | 7 +++---- OpenAL32/Include/alMain.h | 14 ++++++++++++++ OpenAL32/alSource.c | 18 ++++++++++++------ 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index baa94148..587952b2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1276,7 +1276,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean force) { - const ALbufferlistitem *BufferListItem; + ALbufferlistitem *BufferListItem; struct ALvoiceProps *props; props = ATOMIC_EXCHANGE_PTR(&voice->Update, NULL, almemory_order_acq_rel); diff --git a/Alc/alcRing.c b/Alc/alcRing.c index 2cb001bf..d72b34f1 100644 --- a/Alc/alcRing.c +++ b/Alc/alcRing.c @@ -103,16 +103,16 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) * elements in front of the read pointer and behind the write pointer. */ size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); return (w-r) & rb->size_mask; } /* Return the number of elements available for writing. This is the number of * elements in front of the write pointer and behind the read pointer. */ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { - size_t w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - size_t r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); return (r-w-1) & rb->size_mask; } @@ -256,8 +256,10 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data size_t cnt2; size_t w, r; - w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; free_cnt = (w-r) & rb->size_mask; cnt2 = r + free_cnt; @@ -289,8 +291,10 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat size_t cnt2; size_t w, r; - w = ATOMIC_LOAD(&rb->write_ptr, almemory_order_acquire) & rb->size_mask; - r = ATOMIC_LOAD(&rb->read_ptr, almemory_order_acquire) & rb->size_mask; + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; free_cnt = (r-w-1) & rb->size_mask; cnt2 = w + free_cnt; diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cb1e5f5..ac1133d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,12 +264,11 @@ HAVE_C11_ALIGNAS) # Check if we have C11 _Atomic CHECK_C_SOURCE_COMPILES( "#include - const int _Atomic foo = ATOMIC_VAR_INIT(~0); - int _Atomic bar = ATOMIC_VAR_INIT(0); + int _Atomic foo = ATOMIC_VAR_INIT(0); int main() { - atomic_fetch_add(&bar, 2); - return atomic_load(&foo); + atomic_fetch_add(&foo, 2); + return 0; }" HAVE_C11_ATOMIC) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b604c547..174210fa 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -204,6 +204,20 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #endif +#ifdef __GNUC__ +/* This helps cast away the const-ness of a pointer without accidentally + * changing the pointer type. This is necessary due to Clang's inability to use + * atomic_load on a const _Atomic variable. + */ +#define CONST_CAST(T, V) __extension__({ \ + const T _tmp = (V); \ + (T)_tmp; \ +}) +#else +#define CONST_CAST(T, V) ((T)(V)) +#endif + + typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 23b4fb5a..f2c4908f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1407,7 +1407,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p while(BufferList && BufferList != Current) { played++; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } *values = played; } @@ -3177,7 +3178,8 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui { if(BufferList->buffer) readPos += (ALuint64)BufferList->buffer->SampleLen << 32; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } readPos = minu64(readPos, U64(0x7fffffffffffffff)); } @@ -3233,13 +3235,15 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint if(!BufferFmt) BufferFmt = buffer; readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; } - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } while(BufferList && !BufferFmt) { BufferFmt = BufferList->buffer; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } assert(BufferFmt != NULL); @@ -3302,7 +3306,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte totalBufferLen += buffer->SampleLen; if(!readFin) readPos += buffer->SampleLen; } - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } assert(BufferFmt != NULL); @@ -3421,7 +3426,8 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac { if((BufferFmt=BufferList->buffer) != NULL) break; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, + almemory_order_relaxed); } if(!BufferFmt) { -- cgit v1.2.3 From ad782c00007ae7a39352bb649a3cfb957fa2135d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Apr 2017 22:10:27 -0700 Subject: Skip mixing the fade out step when starting silent Unfortunately it can't skip mixing the fade in when going to silence because the history needs to be up to date. --- Alc/mixer.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 2070f859..39def41f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -507,25 +507,32 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } else { - HrtfState backupstate = parms->Hrtf.State; ALfloat gain; /* The old coefficients need to fade to silence * completely since they'll be replaced after the mix. * So it needs to fade out over DstBufferSize instead * of Counter. + * + * Don't bother with the fade out when starting from + * silence. */ - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); - hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = -hrtfparams.Gain / - (ALfloat)DstBufferSize; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &backupstate, DstBufferSize - ); + if(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) + { + HrtfState backupstate = parms->Hrtf.State; + + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = -hrtfparams.Gain / + (ALfloat)DstBufferSize; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &backupstate, DstBufferSize + ); + } /* The new coefficients need to fade in completely * since they're replacing the old ones. To keep the -- cgit v1.2.3 From 12fb0404c18ec280d13a68237212f57a8242af8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2017 02:07:51 -0700 Subject: Reverb code update This update modifies the reverb in numerous ways. The 3-series, 4-parallel all-pass is replaced with a Gerzon vector all-pass. The vector all-pass is also applied to the early reflections, to help with the initial diffusion in the late reverb. The late reverb filter and feedback attenuation has been replaced with a dual first-order equalization filter, which controls the low and high frequencies with individual low-pass/high-shelf and high-pass/low-shelf filters with gain control. Additionally, delay lines now have the ability to blend the output between two offsets, to help smooth out the transition for when the delay changes (without such, it could result in undesirable clicks and pops). --- Alc/effects/reverb.c | 2037 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 1213 insertions(+), 824 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index afae2943..e5cf11b0 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1,6 +1,6 @@ /** - * Reverb for the OpenAL cross platform audio library - * Copyright (C) 2008-2009 by Christopher Fitzgerald. + * Ambisonic reverb engine for the OpenAL cross platform audio library + * Copyright (C) 2008-2017 by Chris Robinson and Christopher Fitzgerald. * 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 @@ -32,100 +32,16 @@ #include "alError.h" #include "mixer_defs.h" - -static const int PrimeTable[1024] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, - 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, - 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, - 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, - 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, - 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, - 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, - 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, - 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, - 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, - 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, - 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, - 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, - 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, - 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, - 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, - 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, - 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, - 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, - 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, - 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, - 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, - 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, - 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, - 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, - 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, - 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, - 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, - 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, - 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, - 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, - 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, - 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, - 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, - 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, - 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, - 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, - 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, - 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, - 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, - 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, - 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, - 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, - 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, - 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, - 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, - 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, - 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, - 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, - 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, - 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, - 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, - 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, - 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, - 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, - 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, - 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, - 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, - 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, - 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, - 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, - 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, - 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, - 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, - 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, - 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, - 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, - 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, - 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, - 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, - 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, - 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, - 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, - 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, - 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, - 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, - 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, - 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, - 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, - 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, - 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, - 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, - 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, - 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - 8117, 8123, 8147, 8161 -}; - /* This is the maximum number of samples processed for each inner loop * iteration. */ #define MAX_UPDATE_SAMPLES 256 +/* The number of samples used for cross-faded delay lines. This can be used + * to balance the compensation for abrupt line changes and attenuation due to + * minimally lengthed recursive lines. Try to keep this below the device + * update size. + */ +#define FADE_SAMPLES 128 static MixerFunc MixSamples = Mix_C; static RowMixerFunc MixRowSamples = MixRow_C; @@ -137,128 +53,122 @@ static void init_mixfunc(void) MixRowSamples = SelectRowMixer(); } - typedef struct DelayLine { - // The delay lines use sample lengths that are powers of 2 to allow the - // use of bit-masking instead of a modulus for wrapping. + /* The delay lines use sample lengths that are powers of 2 to allow the + * use of bit-masking instead of a modulus for wrapping. + */ ALsizei Mask; ALfloat *Line; } DelayLine; +typedef struct Allpass { + DelayLine Delay; + ALsizei Offset[2]; +} Allpass; + 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; + /* All delay lines are allocated as a single buffer to reduce memory + * fragmentation and management code. + */ + ALfloat *SampleBuffer; + ALuint TotalSamples; - // Master effect filters + /* Master effect filters */ struct { ALfilterState Lp; - ALfilterState Hp; // EAX only + ALfilterState Hp; /* EAX only */ } Filter[4]; struct { - // Modulator delay line. + /* Modulator delay lines. */ DelayLine Delay[4]; - // The vibrato time is tracked with an index over a modulus-wrapped - // range (in samples). + /* The vibrato time is tracked with an index over a modulus-wrapped + * range (in samples). + */ ALuint Index; ALuint Range; - // The depth of frequency change (also in samples) and its filter. + /* The depth of frequency change (also in samples) and its filter. */ ALfloat Depth; ALfloat Coeff; ALfloat Filter; - } Mod; // EAX only + } Mod; /* EAX only */ /* Core delay line (early reflections and late reverb tap from this). */ DelayLine Delay; - /* The tap points for the initial delay. First set go to early - * reflections, second to late reverb. - */ - ALsizei EarlyDelayTap[4]; - ALsizei LateDelayTap[4]; + + /* Tap points for early reflection delay. */ + ALsizei EarlyDelayTap[4][2]; + ALfloat EarlyDelayCoeff[4]; + + /* Tap points for late reverb feed and delay. */ + ALsizei LateFeedTap; + ALsizei LateDelayTap[4][2]; + + /* The feed-back and feed-forward all-pass coefficient. */ + ALfloat ApFeedCoeff; + + /* Coefficients for the all-pass and line scattering matrices. */ + ALfloat MixX; + ALfloat MixY; struct { - // Early reflections are done with 4 delay lines. + /* A Gerzon vector all-pass filter is used to simulate initial + * diffusion. The spread from this filter also helps smooth out the + * reverb tail. + */ + Allpass Ap[4]; + + /* Echo lines are used to complete the second half of the early + * reflections. + */ DelayLine Delay[4]; - ALsizei Offset[4]; + ALsizei Offset[4][2]; + ALfloat Coeff[4]; - // The gain for each output channel based on 3D panning. + /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Early; struct { - // Attenuation to compensate for the modal density and decay rate of - // the late lines. + /* Attenuation to compensate for the modal density and decay rate of + * the late lines. + */ ALfloat DensityGain; - // In addition to 4 delay lines. - ALfloat Coeff[4]; + /* Recursive delay lines are used fill in the reverb tail. */ DelayLine Delay[4]; - ALsizei Offset[4]; - - // The delay lines are 1-pole low-pass filtered. - struct { - ALfloat Sample; - ALfloat Coeff; - } Lp[4]; + ALsizei Offset[4][2]; - /* Late reverb has 3 all-pass filters in series on each of the 4 lines. - */ + /* T60 decay filters are used to simulate absorption. */ struct { - ALsizei Offsets[3]; - - /* One delay line is used for all 3 all-pass filters. */ - DelayLine Delay; - } Ap[4]; - - // The feed-back and feed-forward all-pass coefficient. - ALfloat ApFeedCoeff; - - // Mixing matrix coefficient. - ALfloat MixCoeff; - - // Output gain for late reverb. - ALfloat Gain; - - // The gain for each output channel based on 3D panning. + ALfloat LFCoeffs[3]; + ALfloat HFCoeffs[3]; + ALfloat MidCoeff; + /* The LF and HF filters keep a state of the last input and last + * output sample. + */ + ALfloat States[2][2]; + } Filters[4]; + + /* A Gerzon vector all-pass filter is used to simulate diffusion. */ + Allpass Ap[4]; + + /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Late; - struct { - // Attenuation to compensate for the modal density and decay rate of - // the echo line. - ALfloat DensityGain; + /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ + ALsizei FadeCount; - // Echo delay and all-pass lines. - struct { - DelayLine Feedback; - DelayLine Ap; - } Delay[4]; - - ALfloat Coeff; - ALfloat ApFeedCoeff; - - ALsizei Offset; - ALsizei ApOffset; - - // The echo line is 1-pole low-pass filtered. - ALfloat LpCoeff; - ALfloat LpSample[4]; - - // Echo mixing coefficient. - ALfloat MixCoeff; - } Echo; // EAX only - - // The current read offset for all delay lines. + /* The current write offset for all delay lines. */ ALsizei Offset; /* Temporary storage used when processing. */ @@ -275,10 +185,9 @@ DECLARE_DEFAULT_ALLOCATORS(ALreverbState) DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); - static void ALreverbState_Construct(ALreverbState *state) { - ALuint index, l; + ALsizei i, j; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALreverbState, ALeffectState, state); @@ -288,13 +197,13 @@ static void ALreverbState_Construct(ALreverbState *state) state->TotalSamples = 0; state->SampleBuffer = NULL; - for(index = 0;index < 4;index++) + for(i = 0;i < 4;i++) { - ALfilterState_clear(&state->Filter[index].Lp); - ALfilterState_clear(&state->Filter[index].Hp); + ALfilterState_clear(&state->Filter[i].Lp); + ALfilterState_clear(&state->Filter[i].Hp); - state->Mod.Delay[index].Mask = 0; - state->Mod.Delay[index].Line = NULL; + state->Mod.Delay[i].Mask = 0; + state->Mod.Delay[i].Line = NULL; } state->Mod.Index = 0; @@ -305,67 +214,78 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Mask = 0; state->Delay.Line = NULL; - for(index = 0;index < 4;index++) - state->EarlyDelayTap[index] = 0; - for(index = 0;index < 4;index++) - state->LateDelayTap[index] = 0; - for(index = 0;index < 4;index++) + for(i = 0;i < 4;i++) { - state->Early.Delay[index].Mask = 0; - state->Early.Delay[index].Line = NULL; - state->Early.Offset[index] = 0; + state->EarlyDelayTap[i][0] = 0; + state->EarlyDelayTap[i][1] = 0; + state->EarlyDelayCoeff[i] = 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->LateFeedTap = 0; + + for(i = 0;i < 4;i++) + { + state->LateDelayTap[i][0] = 0; + state->LateDelayTap[i][1] = 0; + } + + state->ApFeedCoeff = 0.0f; + state->MixX = 0.0f; + state->MixY = 0.0f; + + for(i = 0;i < 4;i++) { - ALuint k; - for(k = 0;k < 3;k++) - state->Late.Ap[index].Offsets[k] = 0; - state->Late.Ap[index].Delay.Mask = 0; - state->Late.Ap[index].Delay.Line = NULL; - - 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.Lp[index].Sample = 0.0f; - state->Late.Lp[index].Coeff = 0.0f; + state->Early.Ap[i].Delay.Mask = 0; + state->Early.Ap[i].Delay.Line = NULL; + state->Early.Ap[i].Offset[0] = 0; + state->Early.Ap[i].Offset[1] = 0; + state->Early.Delay[i].Mask = 0; + state->Early.Delay[i].Line = NULL; + state->Early.Offset[i][0] = 0; + state->Early.Offset[i][1] = 0; + state->Early.Coeff[i] = 0.0f; } - for(l = 0;l < 4;l++) + state->Late.DensityGain = 0.0f; + + for(i = 0;i < 4;i++) { - for(index = 0;index < MAX_OUTPUT_CHANNELS;index++) + state->Late.Ap[i].Delay.Mask = 0; + state->Late.Ap[i].Delay.Line = NULL; + state->Late.Ap[i].Offset[0] = 0; + state->Late.Ap[i].Offset[1] = 0; + + state->Late.Delay[i].Mask = 0; + state->Late.Delay[i].Line = NULL; + state->Late.Offset[i][0] = 0; + state->Late.Offset[i][1] = 0; + + for(j = 0;j < 3;j++) { - state->Early.CurrentGain[l][index] = 0.0f; - state->Early.PanGain[l][index] = 0.0f; - state->Late.CurrentGain[l][index] = 0.0f; - state->Late.PanGain[l][index] = 0.0f; + state->Late.Filters[i].LFCoeffs[j] = 0.0f; + state->Late.Filters[i].HFCoeffs[j] = 0.0f; } + state->Late.Filters[i].MidCoeff = 0.0f; + + state->Late.Filters[i].States[0][0] = 0.0f; + state->Late.Filters[i].States[0][1] = 0.0f; + state->Late.Filters[i].States[1][0] = 0.0f; + state->Late.Filters[i].States[1][1] = 0.0f; } - state->Echo.DensityGain = 0.0f; - for(l = 0;l < 4;l++) + for(i = 0;i < 4;i++) { - state->Echo.Delay[l].Feedback.Mask = 0; - state->Echo.Delay[l].Feedback.Line = NULL; - state->Echo.Delay[l].Ap.Mask = 0; - state->Echo.Delay[l].Ap.Line = NULL; + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + { + state->Early.CurrentGain[i][j] = 0.0f; + state->Early.PanGain[i][j] = 0.0f; + state->Late.CurrentGain[i][j] = 0.0f; + state->Late.PanGain[i][j] = 0.0f; + } } - state->Echo.Coeff = 0.0f; - state->Echo.ApFeedCoeff = 0.0f; - state->Echo.Offset = 0; - state->Echo.ApOffset = 0; - state->Echo.LpCoeff = 0.0f; - for(l = 0;l < 4;l++) - state->Echo.LpSample[l] = 0.0f; - state->Echo.MixCoeff = 0.0f; + state->FadeCount = 0; state->Offset = 0; } @@ -388,12 +308,12 @@ ALfloat ReverbBoost = 1.0f; ALboolean EmulateEAXReverb = AL_FALSE; /* This coefficient is used to define the maximum frequency range controlled - * by the modulation depth. The current value of 0.1 will allow it to swing - * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the - * sampler to stall on the downswing, and above 1 it will cause it to sample - * backwards. + * by the modulation depth. The current value of 0.025 will allow it to + * swing from 0.975x to 1.025x. This value must be below 1. At 1 it will + * cause the sampler to stall on the downswing, and above 1 it will cause it + * to sample backwards. */ -static const ALfloat MODULATION_DEPTH_COEFF = 0.1f; +static const ALfloat MODULATION_DEPTH_COEFF = 0.025f; /* A filter is used to avoid the terrible distortion caused by changing * modulation time and/or depth. To be consistent across different sample @@ -403,41 +323,137 @@ static const ALfloat MODULATION_DEPTH_COEFF = 0.1f; static const ALfloat MODULATION_FILTER_COEFF = 0.048f; static const ALfloat MODULATION_FILTER_CONST = 100000.0f; -// When diffusion is above 0, an all-pass filter is used to take the edge off -// the echo effect. It uses the following line length (in seconds). -static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; - -/* Input into the early reflections and late reverb are decorrelated between - * four channels. Their timings are dependent on a fraction and multiplier. See - * the UpdateDelayLine() routine for the calculations involved. +/* The all-pass and delay lines have a variable length dependent on the + * effect's density parameter. The resulting density multiplier is: + * + * multiplier = 1 + (density * LINE_MULTIPLIER) + * + * Thus the line multiplier below will result in a maximum density multiplier + * of 10. */ -static const ALfloat DECO_FRACTION = 0.15f; -static const ALfloat DECO_MULTIPLIER = 2.0f; +static const ALfloat LINE_MULTIPLIER = 9.0f; -// All delay line lengths are specified in seconds. +/* All delay line lengths are specified in seconds. + * + * To approximate early reflections, we break them up into primary (those + * arriving from the same direction as the source) and secondary (those + * arriving from the opposite direction). + * + * The early taps decorrelate the 4-channel signal to approximate an average + * room response for the primary reflections after the initial early delay. + * + * Given an average room dimension (d_a) and the speed of sound (c) we can + * calculate the average reflection delay (r_a) regardless of listener and + * source positions as: + * + * r_a = d_a / c + * c = 343.3 + * + * This can extended to finding the average difference (r_d) between the + * maximum (r_1) and minimum (r_0) reflection delays: + * + * r_0 = 2 / 3 r_a + * = r_a - r_d / 2 + * = r_d + * r_1 = 4 / 3 r_a + * = r_a + r_d / 2 + * = 2 r_d + * r_d = 2 / 3 r_a + * = r_1 - r_0 + * + * As can be determined by integrating the 1D model with a source (s) and + * listener (l) positioned across the dimension of length (d_a): + * + * r_d = int_(l=0)^d_a (int_(s=0)^d_a |2 d_a - 2 (l + s)| ds) dl / c + * + * The initial taps (T_(i=0)^N) are then specified by taking a power series + * that ranges between r_0 and half of r_1 less r_0: + * + * R_i = 2^(i / (2 N - 1)) r_d + * = r_0 + (2^(i / (2 N - 1)) - 1) r_d + * = r_0 + T_i + * T_i = R_i - r_0 + * = (2^(i / (2 N - 1)) - 1) r_d + * + * Assuming an average of 5m (up to 50m with the density multiplier), we get + * the following taps: + */ +static const ALfloat EARLY_TAP_LENGTHS[4] = +{ + 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f +}; -// The lengths of the early delay lines. -static const ALfloat EARLY_LINE_LENGTH[4] = +/* The early all-pass filter lengths are based on the early tap lengths: + * + * A_i = R_i / a + * + * Where a is the approximate maximum all-pass cycle limit (20). + */ +static const ALfloat EARLY_ALLPASS_LENGTHS[4] = { - 0.0015f, 0.0045f, 0.0135f, 0.0405f + 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f }; -/* The lengths of the late delay lines. */ -static const ALfloat LATE_LINE_LENGTH[4] = +/* The early delay lines are used to transform the primary reflections into + * the secondary reflections. The A-format is arranged in such a way that + * the channels/lines are spatially opposite: + * + * C_i is opposite C_(N-i-1) + * + * The delays of the two opposing reflections (R_i and O_i) from a source + * anywhere along a particular dimension always sum to twice its full delay: + * + * 2 r_a = R_i + O_i + * + * With that in mind we can determine the delay between the two reflections + * and thus specify our early line lengths (L_(i=0)^N) using: + * + * O_i = 2 r_a - R_(N-i-1) + * L_i = O_i - R_(N-i-1) + * = 2 (r_a - R_(N-i-1)) + * = 2 (r_a - T_(N-i-1) - r_0) + * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) + * + * Using an average dimension of 5m, we get: + */ +static const ALfloat EARLY_LINE_LENGTHS[4] = { - 0.0211f, 0.0311f, 0.0461f, 0.0680f + 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f }; -/* The late delay lines have a variable length dependent on the effect's - * density parameter (inverted for some reason) and this multiplier. +/* The late all-pass filter lengths are based on the late line lengths: + * + * A_i = (5 / 3) L_i / r_1 */ -static const ALfloat LATE_LINE_MULTIPLIER = 3.0f; +static const ALfloat LATE_ALLPASS_LENGTHS[4] = +{ + 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f +}; +/* The late lines are used to approximate the decaying cycle of recursive + * late reflections. + * + * Splitting the lines in half, we start with the shortest reflection paths + * (L_(i=0)^(N/2)): + * + * L_i = 2^(i / (N - 1)) r_d + * + * Then for the opposite (longest) reflection paths (L_(i=N/2)^N): + * + * L_i = 2 r_a - L_(i-N/2) + * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d + * + * For our 5m average room, we get: + */ +static const ALfloat LATE_LINE_LENGTHS[4] = +{ + 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f +}; -#if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM) /* HACK: Workaround for a modff bug in 32-bit Windows, which attempts to write * a 64-bit double to the 32-bit float parameter. */ +#if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM) static inline float hack_modff(float x, float *y) { double di; @@ -448,118 +464,50 @@ static inline float hack_modff(float x, float *y) #define modff hack_modff #endif - /************************************** * Device Update * **************************************/ -// Given the allocated sample buffer, this function updates each delay line -// offset. +/* Given the allocated sample buffer, this function updates each delay line + * offset. + */ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) { Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line]; } -// Calculate the length of a delay line and store its mask and offset. -static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, ALuint extra, DelayLine *Delay) +/* Calculate the length of a delay line and store its mask and offset. */ +static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, + const ALuint extra, DelayLine *Delay) { ALuint samples; - // All line lengths are powers of 2, calculated from their lengths, with - // an additional sample in case of rounding errors. + /* All line lengths are powers of 2, calculated from their lengths, with + * an additional sample in case of rounding errors. + */ samples = fastf2u(length*frequency) + extra; samples = NextPowerOf2(samples + 1); - // All lines share a single sample buffer. + + /* All lines share a single sample buffer. */ Delay->Mask = samples - 1; Delay->Line = (ALfloat*)offset; - // Return the sample count for accumulation. - return samples; -} - - -static int FindClosestPrime(int desired, ALboolean *used) -{ - ALsizei curidx = 0; - ALsizei count = COUNTOF(PrimeTable)-1; - /* First, a binary search to find the closest prime that's not less than - * the desired value (lower_bound). - */ - while(count > 0) - { - ALsizei step = count>>1; - ALsizei i = curidx+step; - if(!(PrimeTable[i] < desired)) - count = step; - else - { - curidx = i+1; - count -= step+1; - } - } - /* If the next lesser prime is closer to the desired value, use it. */ - if(curidx > 0 && abs(PrimeTable[curidx-1]-desired) < abs(PrimeTable[curidx]-desired)) - curidx--; - -#define GET_BIT(arr, b) (!!(arr[(b)>>4]&(1<<((b)&7)))) -#define SET_BIT(arr, b) ((void)(arr[(b)>>4] |= (1<<((b)&7)))) - if(GET_BIT(used, curidx)) - { - ALsizei off1=0, off2=0; - /* If this prime is already used, find the next unused larger and next - * unused smaller one. - */ - while(off1 < curidx && GET_BIT(used, curidx-off1)) - off1++; - while(off2 < 1024-curidx && GET_BIT(used, curidx+off2)) - off2++; - - /* Select the closest unused prime to the desired value. */ - if(GET_BIT(used, curidx-off1)) - curidx += off2; - else if(GET_BIT(used, curidx+off2)) - curidx -= off1; - else - curidx = (abs(PrimeTable[curidx-off1]-desired) < - abs(PrimeTable[curidx+off2]-desired)) ? (curidx-off1) : (curidx+off2); - } - /* Mark this prime as used. */ - SET_BIT(used, curidx); -#undef SET_BIT -#undef GET_BIT - return PrimeTable[curidx]; -} - -/* The lengths of the late reverb all-pass filter series are roughly calculated - * as: 15ms / (3**idx), where idx is the filter index of the series. On top of - * that, the filter lengths (in samples) should be prime numbers so they don't - * share any common factors. - * - * To accomplish this, a lookup table is used to search among the first 1024 - * primes, along with a packed bit table to mark used primes, which should be - * enough to handle any reasonable sample rate. - * - * NOTE: The returned length is in *samples*, not seconds! - */ -static ALfloat CalcAllpassLength(ALuint idx, ALuint frequency, ALboolean *used) -{ - ALfloat samples = frequency*0.015f / powf(3.0f, (ALfloat)idx); - - return FindClosestPrime((int)floorf(samples + 0.5f), used); + /* Return the sample count for accumulation. */ + return samples; } /* Calculates the delay line metrics and allocates the shared sample buffer * for all lines given the sample rate (frequency). If an allocation failure * occurs, it returns AL_FALSE. */ -static ALboolean AllocLines(ALuint frequency, ALreverbState *State) +static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) { - ALboolean used_primes[COUNTOF(PrimeTable)>>4] = { 0 }; - ALuint totalSamples, index; - ALfloat length; + ALuint totalSamples, i; + ALfloat multiplier, length; - // All delay line lengths are calculated to accomodate the full range of - // lengths given their respective paramters. + /* All delay line lengths are calculated to accomodate the full range of + * lengths given their respective paramters. + */ totalSamples = 0; /* The modulator's line length is calculated from the maximum modulation @@ -568,61 +516,58 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) * modulation. */ length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); - for(index = 0;index < 4;index++) + for(i = 0;i < 4;i++) totalSamples += CalcLineLength(length, totalSamples, frequency, 1, - &State->Mod.Delay[index]); + &State->Mod.Delay[i]); - /* The initial delay is the sum of the reflections and late reverb delays. - * The decorrelator length is calculated from the lowest reverb density (a - * parameter value of 1). This must include space for storing a loop - * update. + /* The main delay length includes the maximum early reflection delay, the + * largest early tap width, the maximum late reverb delay, and the + * largest late tap width. Finally, it must also be extended by the + * update size (MAX_UPDATE_SAMPLES*4) for block processing. */ + multiplier = 1.0f + LINE_MULTIPLIER; length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY; - length += (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * - LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); + EARLY_TAP_LENGTHS[3]*multiplier + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + + (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; /* Multiply length by 4, since we're storing 4 interleaved channels in the * main delay line. */ totalSamples += CalcLineLength(length*4, totalSamples, frequency, MAX_UPDATE_SAMPLES*4, &State->Delay); - // The early reflection lines. - for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, - frequency, 0, &State->Early.Delay[index]); + /* The early all-pass lines. */ + for(i = 0;i < 4;i++) + { + length = EARLY_ALLPASS_LENGTHS[i] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Early.Ap[i].Delay); + } - // The late delay lines are calculated from the lowest reverb density. - for(index = 0;index < 4;index++) + /* The early reflection lines. */ + for(i = 0;i < 4;i++) { - length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); + length = EARLY_LINE_LENGTHS[i] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.Delay[index]); + &State->Early.Delay[i]); } - // The late all-pass lines. - for(index = 0;index < 4;index++) + /* The late vector all-pass lines. */ + for(i = 0;i < 4;i++) { - ALuint k; - - length = 0.0f; - for(k = 0;k < 3;k++) - length += CalcAllpassLength(k, frequency, used_primes); - /* NOTE: Since 'length' is already the number of samples for the all- - * pass series, pass a sample rate of 1 so the sample length remains - * correct. - */ - totalSamples += CalcLineLength(length, totalSamples, 1, 1, - &State->Late.Ap[index].Delay); + length = LATE_ALLPASS_LENGTHS[i] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Late.Ap[i].Delay); } - // The echo all-pass and delay lines. - for(index = 0;index < 4;index++) + /* The late delay lines are calculated from the larger of the maximum + * density line length or the maximum echo time. + */ + for(i = 0;i < 4;i++) { - totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, - frequency, 0, &State->Echo.Delay[index].Ap); - totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, - frequency, 0, &State->Echo.Delay[index].Feedback); + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i] * multiplier); + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + &State->Late.Delay[i]); } if(totalSamples != State->TotalSamples) @@ -638,68 +583,50 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) State->TotalSamples = totalSamples; } - // Update all delays to reflect the new sample buffer. + /* Update all delays to reflect the new sample buffer. */ RealizeLineOffset(State->SampleBuffer, &State->Delay); - for(index = 0;index < 4;index++) + for(i = 0;i < 4;i++) { - RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay[i]); - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Early.Ap[i].Delay); + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[i]); - RealizeLineOffset(State->SampleBuffer, &State->Late.Ap[index].Delay); - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); - - RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay[index].Ap); - RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay[index].Feedback); + RealizeLineOffset(State->SampleBuffer, &State->Late.Ap[i].Delay); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[i]); } - // Clear the sample buffer. - for(index = 0;index < State->TotalSamples;index++) - State->SampleBuffer[index] = 0.0f; + /* Clear the sample buffer. */ + for(i = 0;i < State->TotalSamples;i++) + State->SampleBuffer[i] = 0.0f; return AL_TRUE; } static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) { - ALboolean used_primes[COUNTOF(PrimeTable)>>4] = { 0 }; - ALuint frequency = Device->Frequency, index; + ALuint frequency = Device->Frequency, i; + ALfloat multiplier; - // Allocate the delay lines. + /* Allocate the delay lines. */ if(!AllocLines(frequency, State)) return AL_FALSE; - // Calculate the modulation filter coefficient. Notice that the exponent - // is calculated given the current sample rate. This ensures that the - // resulting filter response over time is consistent across all sample - // rates. + /* Calculate the modulation filter coefficient. Notice that the exponent + * is calculated given the current sample rate. This ensures that the + * resulting filter response over time is consistent across all sample + * rates. + */ State->Mod.Coeff = powf(MODULATION_FILTER_COEFF, MODULATION_FILTER_CONST / frequency); - // The early reflection and late all-pass filter line lengths are static, - // so their offsets only need to be calculated once. - for(index = 0;index < 4;index++) - { - ALuint k; - - State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * frequency); - for(k = 0;k < 3;k++) - State->Late.Ap[index].Offsets[k] = (ALuint)CalcAllpassLength( - k, frequency, used_primes - ); - State->Late.Ap[index].Offsets[1] += State->Late.Ap[index].Offsets[0]; - State->Late.Ap[index].Offsets[2] += State->Late.Ap[index].Offsets[1]; - TRACE("Late all-pass %u: %u %u (%+d) %u (%+d)\n", index, - State->Late.Ap[index].Offsets[0], State->Late.Ap[index].Offsets[1], - (State->Late.Ap[index].Offsets[1] - State->Late.Ap[index].Offsets[0]), - State->Late.Ap[index].Offsets[2], - (State->Late.Ap[index].Offsets[2] - State->Late.Ap[index].Offsets[1]) - ); - } + multiplier = 1.0f + LINE_MULTIPLIER; - // The echo all-pass filter line length is static, so its offset only - // needs to be calculated once. - State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency); + /* The late feed taps are set a fixed position past the latest delay tap. */ + for(i = 0;i < 4;i++) + State->LateFeedTap = fastf2u((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + EARLY_TAP_LENGTHS[3]*multiplier) * + frequency); return AL_TRUE; } @@ -708,23 +635,26 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev * Effect Update * **************************************/ -// 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) +/* Calculate a decay coefficient given the length of each cycle and the time + * until the decay reaches -60 dB. + */ +static inline ALfloat CalcDecayCoeff(const ALfloat length, const 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) +/* Calculate a decay length from a coefficient and the time until the decay + * reaches -60 dB. + */ +static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) { return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; } -// 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) +/* 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(const 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 @@ -734,32 +664,34 @@ static inline ALfloat CalcDensityGain(ALfloat a) * where a is the attenuation coefficient, and n is the sample. The area * under this decay curve can be calculated as: 1 / (1 - a). * - * Modifying the above equation to find the squared area under the curve + * Modifying the above equation to find the area under the squared curve * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be * calculated by inverting the square root of this approximation, * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). */ - return sqrtf(1.0f - (a * a)); + return sqrtf(1.0f - a*a); } -// Calculate the mixing matrix coefficients given a diffusion factor. -static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) +/* Calculate the scattering matrix coefficients given a diffusion factor. */ +static inline ALvoid CalcMatrixCoeffs(const ALfloat diffusion, ALfloat *x, ALfloat *y) { ALfloat n, t; - // The matrix is of order 4, so n is sqrt (4 - 1). + /* The matrix is of order 4, so n is sqrt(4 - 1). */ n = sqrtf(3.0f); t = diffusion * atanf(n); - // Calculate the first mixing matrix coefficient. + /* Calculate the first mixing matrix coefficient. */ *x = cosf(t); - // Calculate the second mixing matrix coefficient. + /* Calculate the second mixing matrix coefficient. */ *y = sinf(t) / n; } -// Calculate the limited HF ratio for use with the late reverb low-pass -// filters. -static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) +/* Calculate the limited HF ratio for use with the late reverb low-pass + * filters. + */ +static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorptionGainHF, + const ALfloat decayTime) { ALfloat limitRatio; @@ -771,48 +703,343 @@ static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SPEEDOFSOUNDMETRESPERSEC); /* Using the limit calculated above, apply the upper bound to the HF - * ratio. Also need to limit the result to a minimum of 0.1, just like the - * HF ratio parameter. */ + * ratio. Also need to limit the result to a minimum of 0.1, just like + * the HF ratio parameter. + */ return clampf(limitRatio, 0.1f, hfRatio); } -// 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) +/* Calculates the first-order high-pass coefficients following the I3DL2 + * reference model. This is the transfer function: + * + * 1 - z^-1 + * H(z) = p ------------ + * 1 - p z^-1 + * + * And this is the I3DL2 coefficient calculation given gain (g) and reference + * angular frequency (w): + * + * g + * p = ------------------------------------------------------ + * g cos(w) + sqrt((cos(w) - 1) (g^2 cos(w) + g^2 - 2)) + * + * The coefficient is applied to the partial differential filter equation as: + * + * c_0 = p + * c_1 = -p + * c_2 = p + * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) + * + */ +static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) +{ + ALfloat g, g2, cw, p; + + if(gain >= 1.0f) + { + coeffs[0] = 1.0f; + coeffs[1] = 0.0f; + coeffs[2] = 0.0f; + + return; + } + + g = maxf(0.001f, gain); + g2 = g * g; + cw = cosf(w); + p = g / (g*cw + sqrt((cw - 1.0f) * (g2*cw + g2 - 2.0f))); + + coeffs[0] = p; + coeffs[1] = -p; + coeffs[2] = p; +} + +/* Calculates the first-order low-pass coefficients following the I3DL2 + * reference model. This is the transfer function: + * + * (1 - a) z^0 + * H(z) = ---------------- + * 1 z^0 - a z^-1 + * + * And this is the I3DL2 coefficient calculation given gain (g) and reference + * angular frequency (w): + * + * 1 - g^2 cos(w) - sqrt(2 g^2 (1 - cos(w)) - g^4 (1 - cos(w)^2)) + * a = ---------------------------------------------------------------- + * 1 - g^2 + * + * The coefficient is applied to the partial differential filter equation as: + * + * c_0 = 1 - a + * c_1 = 0 + * c_2 = a + * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) + * + */ +static inline void CalcLowpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) { - ALfloat coeff, g; + ALfloat g, g2, cw, a; - // Eventually this should boost the high frequencies when the ratio - // exceeds 1. - coeff = 0.0f; - if (hfRatio < 1.0f) + if(gain >= 1.0f) { - // Calculate the low-pass coefficient by dividing the HF decay - // coefficient by the full decay coefficient. - g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; + coeffs[0] = 1.0f; + coeffs[1] = 0.0f; + coeffs[2] = 0.0f; - // Damping is done with a 1-pole filter, so g needs to be squared. - g *= g; - if(g < 0.9999f) /* 1-epsilon */ + return; + } + + /* Be careful with gains < 0.001, as that causes the coefficient + * to head towards 1, which will flatten the signal. */ + g = maxf(0.001f, gain); + g2 = g * g; + cw = cosf(w); + a = (1.0f - g2*cw - sqrtf((2.0f*g2*(1.0f - cw)) - g2*g2*(1.0f - cw*cw))) / + (1.0f - g2); + + coeffs[0] = 1.0f - a; + coeffs[1] = 0.0f; + coeffs[2] = a; +} + +/* Calculates the first-order low-shelf coefficients. The shelf filters are + * used in place of low/high-pass filters to preserve the mid-band. This is + * the transfer function: + * + * a_0 + a_1 z^-1 + * H(z) = ---------------- + * 1 + b_1 z^-1 + * + * And these are the coefficient calculations given cut gain (g) and a center + * angular frequency (w): + * + * sin(0.5 (pi - w) - 0.25 pi) + * p = ----------------------------- + * sin(0.5 (pi - w) + 0.25 pi) + * + * g + 1 g + 1 + * a = ------- + sqrt((-------)^2 - 1) + * g - 1 g - 1 + * + * 1 + g + (1 - g) a + * b_0 = ------------------- + * 2 + * + * 1 - g + (1 + g) a + * b_1 = ------------------- + * 2 + * + * The coefficients are applied to the partial differential filter equation + * as: + * + * b_0 + p b_1 + * c_0 = ------------- + * 1 + p a + * + * -(b_1 + p b_0) + * c_1 = ---------------- + * 1 + p a + * + * p + a + * c_2 = --------- + * 1 + p a + * + * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) + * + */ +static inline void CalcLowShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) +{ + ALfloat g, rw, p, n; + ALfloat alpha, beta0, beta1; + + if(gain >= 1.0f) + { + coeffs[0] = 1.0f; + coeffs[1] = 0.0f; + coeffs[2] = 0.0f; + + return; + } + + g = maxf(0.001f, gain); + rw = F_PI - w; + p = sinf(0.5f*rw - 0.25f*F_PI) / sinf(0.5f*rw + 0.25f*F_PI); + n = (g + 1.0f) / (g - 1.0f); + alpha = n + sqrtf(n*n - 1.0f); + beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f; + beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f; + + coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha); + coeffs[1] = -(beta1 + p*beta0) / (1.0f + p*alpha); + coeffs[2] = (p + alpha) / (1.0f + p*alpha); +} + +/* Calculates the first-order high-shelf coefficients. The shelf filters are + * used in place of low/high-pass filters to preserve the mid-band. This is + * the transfer function: + * + * a_0 + a_1 z^-1 + * H(z) = ---------------- + * 1 + b_1 z^-1 + * + * And these are the coefficient calculations given cut gain (g) and a center + * angular frequency (w): + * + * sin(0.5 w - 0.25 pi) + * p = ---------------------- + * sin(0.5 w + 0.25 pi) + * + * g + 1 g + 1 + * a = ------- + sqrt((-------)^2 - 1) + * g - 1 g - 1 + * + * 1 + g + (1 - g) a + * b_0 = ------------------- + * 2 + * + * 1 - g + (1 + g) a + * b_1 = ------------------- + * 2 + * + * The coefficients are applied to the partial differential filter equation + * as: + * + * b_0 + p b_1 + * c_0 = ------------- + * 1 + p a + * + * b_1 + p b_0 + * c_1 = ------------- + * 1 + p a + * + * -(p + a) + * c_2 = ---------- + * 1 + p a + * + * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) + * + */ +static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) +{ + ALfloat g, p, n; + ALfloat alpha, beta0, beta1; + + if(gain >= 1.0f) + { + coeffs[0] = 1.0f; + coeffs[1] = 0.0f; + coeffs[2] = 0.0f; + + return; + } + + g = maxf(0.001f, gain); + p = sinf(0.5f*w - 0.25f*F_PI) / sinf(0.5f*w + 0.25f*F_PI); + n = (g + 1.0f) / (g - 1.0f); + alpha = n + sqrtf(n*n - 1.0f); + beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f; + beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f; + + coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha); + coeffs[1] = (beta1 + p*beta0) / (1.0f + p*alpha); + coeffs[2] = -(p + alpha) / (1.0f + p*alpha); +} + +/* Calculates the 3-band T60 damping coefficients for a particular delay line + * of specified length using a combination of two low/high-pass/shelf or + * pass-through filter sections (producing 3 coefficients each) and a general + * gain (7th coefficient) given decay times for each band split at two (LF/ + * HF) reference frequencies (w). + */ +static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, + const ALfloat mfDecayTime, const ALfloat hfDecayTime, + const ALfloat lfW, const ALfloat hfW, ALfloat lfcoeffs[3], + ALfloat hfcoeffs[3], ALfloat *midcoeff) +{ + ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); + ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); + ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); + + if(lfGain < mfGain) + { + if(mfGain < hfGain) { - /* 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); + CalcLowShelfCoeffs(mfGain / hfGain, hfW, lfcoeffs); + CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs); + *midcoeff = hfGain; } + else if(mfGain > hfGain) + { + CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs); + CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); + *midcoeff = mfGain; + } + else + { + lfcoeffs[0] = 1.0f; + lfcoeffs[1] = 0.0f; + lfcoeffs[2] = 0.0f; + CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs); + *midcoeff = mfGain; + } + } + else if(lfGain > mfGain) + { + if(mfGain < hfGain) + { + double hg = mfGain / lfGain; + double lg = mfGain / hfGain; - // Very low decay times will produce minimal output, so apply an - // upper bound to the coefficient. - coeff = minf(coeff, 0.98f); + CalcHighShelfCoeffs(hg, lfW, lfcoeffs); + CalcLowShelfCoeffs(lg, hfW, hfcoeffs); + *midcoeff = maxf(lfGain, hfGain) / maxf(hg, lg); + } + else if(mfGain > hfGain) + { + CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs); + CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); + *midcoeff = lfGain; + } + else + { + lfcoeffs[0] = 1.0f; + lfcoeffs[1] = 0.0f; + lfcoeffs[2] = 0.0f; + CalcHighShelfCoeffs(mfGain / lfGain, lfW, hfcoeffs); + *midcoeff = lfGain; + } + } + else + { + lfcoeffs[0] = 1.0f; + lfcoeffs[1] = 0.0f; + lfcoeffs[2] = 0.0f; + + if(mfGain < hfGain) + { + CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); + *midcoeff = hfGain; + } + else if(mfGain > hfGain) + { + CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); + *midcoeff = mfGain; + } + else + { + hfcoeffs[3] = 1.0f; + hfcoeffs[4] = 0.0f; + hfcoeffs[5] = 0.0f; + *midcoeff = mfGain; + } } - return coeff; } -// 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, ALreverbState *State) +/* 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(const ALfloat modTime, const ALfloat modDepth, const ALuint frequency, ALreverbState *State) { ALuint range; @@ -841,118 +1068,133 @@ static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequenc 2.0f * frequency; } -// Update the offsets for the main effect delay line. -static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALfloat density, ALuint frequency, ALreverbState *State) +/* Update the offsets for the main effect delay line. */ +static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State) { - ALfloat length; + ALfloat multiplier, length; ALuint i; - /* The early reflections and late reverb inputs are decorrelated to provide - * time-varying reflections, smooth out the reverb tail, and reduce harsh - * echoes. The first tap occurs immediately, while the remaining taps are - * delayed by multiples of a fraction of the smallest delay time. - * - * offset[index] = (FRACTION (MULTIPLIER^(index-1))) smallest_delay + multiplier = 1.0f + density*LINE_MULTIPLIER; + + /* Early reflection taps are decorrelated by means of an average room + * reflection approximation described above the definition of the taps. + * This approximation is linear and so the above density multiplier can + * be applied to adjust the width of the taps. A single-band decay + * coefficient is applied to simulate initial attenuation and absorption. * - * for index = 1...max_lines + * Late reverb taps are based on the late line lengths to allow a zero- + * delay path and offsets that would continue the propagation naturally + * into the late lines. */ - State->EarlyDelayTap[0] = fastf2u(earlyDelay*frequency + 0.5f); - for(i = 1;i < 4;i++) + for(i = 0;i < 4;i++) { - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * - EARLY_LINE_LENGTH[0]; - State->EarlyDelayTap[i] = fastf2u(length*frequency + 0.5f) + State->EarlyDelayTap[0]; + length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; + State->EarlyDelayTap[i][1] = fastf2u(length * frequency); + + length = EARLY_TAP_LENGTHS[i]*multiplier; + State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime); + + length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + State->LateDelayTap[i][1] = State->LateFeedTap + fastf2u(length * frequency); } +} - State->LateDelayTap[0] = fastf2u((earlyDelay + lateDelay)*frequency + 0.5f); - for(i = 1;i < 4;i++) +/* Update the early reflection line lengths and gain coefficients. */ +static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State) +{ + ALfloat multiplier, length; + ALsizei i; + + multiplier = 1.0f + density*LINE_MULTIPLIER; + + for(i = 0;i < 4;i++) { - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)i-1.0f)) * - LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->LateDelayTap[i] = fastf2u(length*frequency + 0.5f) + State->LateDelayTap[0]; + /* Calculate the length (in seconds) of each all-pass line. */ + length = EARLY_ALLPASS_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each all-pass line. */ + State->Early.Ap[i].Offset[1] = fastf2u(length * frequency); + + /* Calculate the length (in seconds) of each delay line. */ + length = EARLY_LINE_LENGTHS[i] * multiplier; + + /* Calculate the delay offset for each delay line. */ + State->Early.Offset[i][1] = fastf2u(length * frequency); + + /* Calculate the gain (coefficient) for each line. */ + State->Early.Coeff[i] = CalcDecayCoeff(length, decayTime); } } -// Update the late reverb mix, line lengths, and line coefficients. -static ALvoid UpdateLateLines(ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +/* Update the late reverb line lengths and T60 coefficients. */ +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALreverbState *State) { - ALfloat length; + ALfloat multiplier, length, bandWeights[3]; ALsizei i; - /* Calculate the late reverb gain. Since the output is tapped prior to the - * application of the next delay line coefficients, the output needs to be - * attenuated by the 'x' mixing matrix coefficient. Also attenuate the - * late reverb when echo depth is high and diffusion is low, so the echo is - * slightly stronger than the decorrelated echos in the reverb tail. - */ - State->Late.Gain = xMix * (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); - /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of * the outgoing signal. This approximation is used to keep the apparent * energy of the signal equal for all ranges of density and decay time. * - * The average length of the cyclcical delay lines is used to calculate - * the attenuation coefficient. + * The average length of the delay lines is used to calculate the + * attenuation coefficient. + */ + multiplier = 1.0f + density*LINE_MULTIPLIER; + length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + + LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; + /* Include the echo transformation (see below). */ + length = lerp(length, echoTime, echoDepth); + length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; + /* The density gain calculation uses an average decay time weighted by + * approximate bandwidth. This attempts to compensate for losses of + * energy that reduce decay time due to scattering into highly attenuated + * bands. */ - length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + - LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; - length *= 1.0f + (density * LATE_LINE_MULTIPLIER); + bandWeights[0] = lfW; + bandWeights[1] = hfW - lfW; + bandWeights[2] = F_TAU - hfW; State->Late.DensityGain = CalcDensityGain( - CalcDecayCoeff(length, decayTime) + CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + + bandWeights[2]*hfDecayTime) / F_TAU) ); - // Calculate the all-pass feed-back and feed-forward coefficient. - State->Late.ApFeedCoeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - for(i = 0;i < 4;i++) { - // Calculate the length (in seconds) of each delay line. - length = LATE_LINE_LENGTH[i] * (1.0f + (density*LATE_LINE_MULTIPLIER)); + /* Calculate the length (in seconds) of each all-pass line. */ + length = LATE_ALLPASS_LENGTHS[i] * multiplier; - // Calculate the delay offset for each delay line. - State->Late.Offset[i] = fastf2u(length * frequency); + /* Calculate the delay offset for each all-pass line. */ + State->Late.Ap[i].Offset[1] = fastf2u(length * frequency); - // Calculate the gain (coefficient) for each line. - State->Late.Coeff[i] = CalcDecayCoeff(length, decayTime); + /* Calculate the length (in seconds) of each delay line. This also + * applies the echo transformation. As the EAX echo depth approaches + * 1, the line lengths approach a length equal to the echoTime. This + * helps to produce distinct echoes along the tail. + */ + length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth); - // Calculate the damping coefficient for each low-pass filter. - State->Late.Lp[i].Coeff = CalcDampingCoeff( - hfRatio, length, decayTime, State->Late.Coeff[i], cw - ); + /* Calculate the delay offset for each delay line. */ + State->Late.Offset[i][1] = fastf2u(length * frequency); - // Attenuate the line coefficients by the mixing coefficient (x). - State->Late.Coeff[i] *= xMix; + /* Approximate the absorption that the vector all-pass would exhibit + * given the current diffusion so we don't have to process a full T60 + * filter for each of its four lines. + */ + length += lerp(LATE_ALLPASS_LENGTHS[i], + (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f, + diffusion) * multiplier; + + /* Calculate the T60 damping coefficients for each line. */ + CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, + lfW, hfW, State->Late.Filters[i].LFCoeffs, + State->Late.Filters[i].HFCoeffs, + &State->Late.Filters[i].MidCoeff); } } -// Update the echo gain, line offset, line coefficients, and mixing -// coefficients. -static ALvoid UpdateEchoLine(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); - - // Calculate the decay coefficient for the echo line. - State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); - - // Calculate the energy-based attenuation coefficient for the echo delay - // line. - State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); - - // Calculate the echo all-pass feed coefficient. - State->Echo.ApFeedCoeff = sqrtf(0.5f) * powf(diffusion, 2.0f); - - // Calculate the damping coefficient for each low-pass filter. - State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, - State->Echo.Coeff, cw); - - /* Calculate the echo mixing coefficient. This is applied to the output mix - * only, not the feedback. - */ - State->Echo.MixCoeff = echoDepth; -} - /* Creates a transform matrix given a reverb vector. This works by creating a * Z-focus transform, then a rotate transform around X, then Y, to place the * focal point in the direction of the vector, using the vector length as a @@ -1024,23 +1266,17 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) return tmp2; } -// Update the early and late 3D panning gains. -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALfloat EarlyGain, ALfloat LateGain, ALreverbState *State) +/* Update the early and late 3D panning gains. */ +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat gain, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State) { - /* Converts early reflections A-Format to B-Format (transposed). */ - static const aluMatrixf EarlyA2B = {{ + /* Converts A-Format to B-Format (transposed). */ + static const aluMatrixf A2B = {{ { 0.8660254038f, 0.8660254038f, 0.8660254038f, 0.8660254038f }, + { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f }, { 0.8660254038f, 0.8660254038f, -0.8660254038f, -0.8660254038f }, - { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f }, - { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f } - }}; - /* Converts late reverb A-Format to B-Format (transposed). */ - static const aluMatrixf LateA2B = {{ - { 0.8660254038f, 1.2247448714f, 0.0f, 0.8660254038f }, - { 0.8660254038f, 0.0f, -1.2247448714f, -0.8660254038f }, - { 0.8660254038f, 0.0f, 1.2247448714f, -0.8660254038f }, - { 0.8660254038f, -1.2247448714f, 0.0f, 0.8660254038f } + { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f } }}; + aluMatrixf transform, rot; ALsizei i; @@ -1048,38 +1284,38 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; /* Note: Both _m2 and _res are transposed. */ -#define MATRIX_MULT(_res, _m1, _m2) do { \ - int row, col; \ - for(col = 0;col < 4;col++) \ - { \ - for(row = 0;row < 4;row++) \ +#define MATRIX_MULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ _res.m[col][row] = _m1.m[row][0]*_m2.m[col][0] + _m1.m[row][1]*_m2.m[col][1] + \ _m1.m[row][2]*_m2.m[col][2] + _m1.m[row][3]*_m2.m[col][3]; \ - } \ + } \ } while(0) /* Create a matrix that first converts A-Format to B-Format, then rotates * the B-Format soundfield according to the panning vector. */ rot = GetTransformFromVector(ReflectionsPan); - MATRIX_MULT(transform, rot, EarlyA2B); + MATRIX_MULT(transform, rot, A2B); memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, transform.m[i], Gain*EarlyGain, State->Early.PanGain[i]); + ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*earlyGain, State->Early.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); - MATRIX_MULT(transform, rot, LateA2B); + MATRIX_MULT(transform, rot, A2B); memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, transform.m[i], Gain*LateGain, State->Late.PanGain[i]); + ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*lateGain, State->Late.PanGain[i]); #undef MATRIX_MULT } static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALuint frequency = Device->Frequency; - ALfloat lfscale, hfscale, hfRatio; + ALfloat lfScale, hfScale, hfRatio; + ALfloat lfDecayTime, hfDecayTime; ALfloat gain, gainlf, gainhf; - ALfloat cw, x, y; ALsizei i; if(Slot->Params.EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) @@ -1087,15 +1323,18 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device else if(Slot->Params.EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) State->IsEax = AL_FALSE; - // Calculate the master filters - hfscale = props->Reverb.HFReference / frequency; - gainhf = maxf(props->Reverb.GainHF, 0.0625f); /* Limit -24dB */ + /* Calculate the master filters */ + hfScale = props->Reverb.HFReference / frequency; + /* Restrict the filter gains from going below -40dB to keep the I3DL2 + * model from killing most of the signal. + */ + gainhf = maxf(props->Reverb.GainHF, 0.01f); ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, - gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); - lfscale = props->Reverb.LFReference / frequency; - gainlf = maxf(props->Reverb.GainLF, 0.0625f); + gainhf, hfScale, calc_rcpQ_from_slope(gainhf, 1.0f)); + lfScale = props->Reverb.LFReference / frequency; + gainlf = maxf(props->Reverb.GainLF, 0.01f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, - gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); + gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < 4;i++) { State->Filter[i].Lp.b0 = State->Filter[0].Lp.b0; @@ -1111,43 +1350,67 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; } - // Update the modulator line. + /* Update the modulator line. */ UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, frequency, State); - // Update the main effect delay. + /* Update the main effect delay and associated taps. */ UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, - props->Reverb.Density, frequency, State); + props->Reverb.Density, props->Reverb.DecayTime, frequency, + State); + + /* Calculate the all-pass feed-back/forward coefficient. */ + State->ApFeedCoeff = sqrtf(0.5f) * powf(props->Reverb.Diffusion, 2.0f); - // Get the mixing matrix coefficients (x and y). - CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); - // Then divide x into y to simplify the matrix calculation. - State->Late.MixCoeff = y / x; + /* Update the early lines. */ + UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime, + frequency, State); - // If the HF limit parameter is flagged, calculate an appropriate limit - // based on the air absorption parameter. + /* Get the mixing matrix coefficients. */ + CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); + + /* If the HF limit parameter is flagged, calculate an appropriate limit + * based on the air absorption parameter. + */ hfRatio = props->Reverb.DecayHFRatio; if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, props->Reverb.DecayTime); - cw = cosf(F_TAU * hfscale); - // Update the late lines. - UpdateLateLines(x, props->Reverb.Density, props->Reverb.DecayTime, - props->Reverb.Diffusion, props->Reverb.EchoDepth, - hfRatio, cw, frequency, State); - - // Update the echo line. - UpdateEchoLine(props->Reverb.EchoTime, props->Reverb.DecayTime, - props->Reverb.Diffusion, props->Reverb.EchoDepth, - hfRatio, cw, frequency, State); + /* Calculate the LF/HF decay times. */ + lfDecayTime = clampf(props->Reverb.DecayTime * props->Reverb.DecayLFRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, + AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + + /* Update the late lines. */ + UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, + lfDecayTime, props->Reverb.DecayTime, hfDecayTime, + F_TAU * lfScale, F_TAU * hfScale, + props->Reverb.EchoTime, props->Reverb.EchoDepth, + frequency, State); + /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; - // Update early and late 3D panning. Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, props->Reverb.LateReverbGain, State); + + /* Determine if delay-line cross-fading is required. */ + for(i = 0;i < 4;i++) + { + if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) || + (State->Early.Ap[i].Offset[1] != State->Early.Ap[i].Offset[0]) || + (State->Early.Offset[i][1] != State->Early.Offset[i][0]) || + (State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) || + (State->Late.Ap[i].Offset[1] != State->Late.Ap[i].Offset[0]) || + (State->Late.Offset[i][1] != State->Late.Offset[i][0])) + { + State->FadeCount = 0; + break; + } + } } @@ -1155,24 +1418,34 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device * Effect Processing * **************************************/ -// Basic delay line input/output routines. -static inline ALfloat DelayLineOut(DelayLine *Delay, ALsizei offset) +/* Basic delay line input/output routines. */ +static inline ALfloat DelayLineOut(DelayLine *Delay, const ALsizei offset) { return Delay->Line[offset&Delay->Mask]; } -static inline ALvoid DelayLineIn(DelayLine *Delay, ALsizei offset, ALfloat in) +/* Cross-faded delay line output routine. Instead of interpolating the + * offsets, this interpolates (cross-fades) the outputs at each offset. + */ +static inline ALfloat FadedDelayLineOut(DelayLine *Delay, const ALsizei off0, const ALsizei off1, const ALfloat mu) +{ + return lerp(Delay->Line[off0&Delay->Mask], Delay->Line[off1&Delay->Mask], mu); +} +#define DELAY_OUT_Faded(d, o0, o1, mu) FadedDelayLineOut(d, o0, o1, mu) +#define DELAY_OUT_Unfaded(d, o0, o1, mu) DelayLineOut(d, o0) + +static inline ALvoid DelayLineIn(DelayLine *Delay, const ALsizei offset, const ALfloat in) { Delay->Line[offset&Delay->Mask] = in; } -static inline ALfloat DelayLineInOut(DelayLine *Delay, ALsizei offset, ALsizei outoffset, ALfloat in) +static inline ALfloat DelayLineInOut(DelayLine *Delay, const ALsizei offset, const ALsizei outoffset, const ALfloat in) { Delay->Line[offset&Delay->Mask] = in; return Delay->Line[(offset-outoffset)&Delay->Mask]; } -static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, ALsizei todo) +static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo) { ALfloat sinus, range; ALsizei index, i; @@ -1181,7 +1454,7 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, range = State->Mod.Filter; for(i = 0;i < todo;i++) { - /* Calculate the sinus rythm (dependent on modulation time and the + /* Calculate the sinus rhythm (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. */ @@ -1203,9 +1476,10 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, State->Mod.Filter = range; } -// Given some input samples, this function produces modulation for the late -// reverb. -static void EAXModulation(DelayLine *ModDelay, ALsizei offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, ALsizei todo) +/* Given some input samples, this function produces modulation for the late + * reverb. + */ +static void EAXModulation(DelayLine *ModDelay, ALsizei offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, const ALsizei todo) { ALfloat frac, fdelay; ALfloat out0, out1; @@ -1233,229 +1507,268 @@ static void EAXModulation(DelayLine *ModDelay, ALsizei offset, const ALfloat *re } } -/* Given some input samples from the main delay line, this function produces - * four-channel outputs for the early reflections. +/* Applies a scattering matrix to the 4-line (vector) input. This is used + * for both the below vector all-pass model and to perform modal feed-back + * delay network (FDN) mixing. + * + * The matrix is derived from a skew-symmetric matrix to form a 4D rotation + * matrix with a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: + * + * 1 = x^2 + 3 y^2 + * + * Where a, b, and c are the coefficient y with differing signs, and d is the + * coefficient x. The final matrix is thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * Any square orthogonal matrix with an order that is a power of two will + * work (where ^T is transpose, ^-1 is inverse): + * + * M^T = M^-1 + * + * Using that knowledge, finding an appropriate matrix can be accomplished + * naively by searching all combinations of: + * + * M = D + S - S^T + * + * Where D is a diagonal matrix (of x), and S is a triangular matrix (of y) + * whose combination of signs are being iterated. */ -static ALvoid EarlyReflection(ALreverbState *State, ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +static inline void VectorPartialScatter(ALfloat *restrict vec, const ALfloat xCoeff, const ALfloat yCoeff) { - ALsizei offset = State->Offset; - ALfloat d[4], v, f[4]; - ALsizei i; + const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] }; - for(i = 0;i < todo;i++) - { - /* Obtain the first reflection samples from the main delay line. */ - f[0] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[0])*4 + 0); - f[1] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[1])*4 + 1); - f[2] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[2])*4 + 2); - f[3] = DelayLineOut(&State->Delay, (offset-State->EarlyDelayTap[3])*4 + 3); - - /* The following is a Householder matrix that was derived from a - * lossless scattering junction from waveguide theory. In this case, - * it's maximally diffuse scattering is used without feedback. - * - * N - * --- - * \ - * v = 2/N / d_i - * --- - * i=1 - */ - v = (f[0] + f[1] + f[2] + f[3]) * 0.5f; - - /* Calculate the values to pass through the delay lines. */ - d[0] = v - f[0]; - d[1] = v - f[1]; - d[2] = v - f[2]; - d[3] = v - f[3]; - - /* Store the post-junction results in the main delay line, helping - * compensate for the late reverb starting with a low echo density. - */ - DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[0])*4 + 0, d[0]); - DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[1])*4 + 1, d[1]); - DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[2])*4 + 2, d[2]); - DelayLineIn(&State->Delay, (offset-State->EarlyDelayTap[3])*4 + 3, d[3]); - - /* Feed the early delay lines, and load the delayed results. */ - f[0] += DelayLineInOut(&State->Early.Delay[0], offset, State->Early.Offset[0], d[0]); - f[1] += DelayLineInOut(&State->Early.Delay[1], offset, State->Early.Offset[1], d[1]); - f[2] += DelayLineInOut(&State->Early.Delay[2], offset, State->Early.Offset[2], d[2]); - f[3] += DelayLineInOut(&State->Early.Delay[3], offset, State->Early.Offset[3], d[3]); - offset++; + vec[0] = xCoeff*f[0] + yCoeff*( f[1] + -f[2] + f[3]); + vec[1] = xCoeff*f[1] + yCoeff*(-f[0] + f[2] + f[3]); + vec[2] = xCoeff*f[2] + yCoeff*( f[0] + -f[1] + f[3]); + vec[3] = xCoeff*f[3] + yCoeff*(-f[0] + -f[1] + -f[2] ); +} - /* Output the initial reflection taps and the results of the delayed - * junction for all four channels. - */ - out[0][i] = f[0]; - out[1][i] = f[1]; - out[2][i] = f[2]; - out[3][i] = f[3]; - } +/* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass + * filter to the 4-line input. + * + * It works by vectorizing a regular all-pass filter and replacing the delay + * element with a scattering matrix (like the one above) and a diagonal + * matrix of delay elements. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +#define DECL_TEMPLATE(T) \ +static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ + const ALfloat feedCoeff, const ALfloat xCoeff, \ + const ALfloat yCoeff, const ALfloat mu, \ + Allpass Ap[4]) \ +{ \ + ALfloat input; \ + ALfloat f[4]; \ + ALsizei i; \ + \ + (void)mu; /* Ignore for Unfaded. */ \ + \ + for(i = 0;i < 4;i++) \ + { \ + input = vec[i]; \ + vec[i] = DELAY_OUT_##T(&Ap[i].Delay, offset-Ap[i].Offset[0], \ + offset-Ap[i].Offset[1], mu) - \ + feedCoeff*input; \ + f[i] = input + feedCoeff*vec[i]; \ + } \ + \ + VectorPartialScatter(f, xCoeff, yCoeff); \ + \ + for(i = 0;i < 4;i++) \ + DelayLineIn(&Ap[i].Delay, offset, f[i]); \ } +DECL_TEMPLATE(Unfaded) +DECL_TEMPLATE(Faded) +#undef DECL_TEMPLATE -// Basic attenuated all-pass input/output routine. -static inline ALfloat AllpassInOut(DelayLine *Delay, ALsizei outOffset, ALsizei inOffset, ALfloat in, ALfloat feedCoeff) +/* A helper to reverse vector components. */ +static inline void VectorReverse(ALfloat vec[4]) { - ALfloat out, feed; + const ALfloat f[4] = { vec[0], vec[1], vec[2], vec[3] }; - out = DelayLineOut(Delay, outOffset); - feed = feedCoeff * in; - DelayLineIn(Delay, inOffset, in + feedCoeff*(out - feed)); + vec[0] = f[3]; + vec[1] = f[2]; + vec[2] = f[1]; + vec[3] = f[0]; +} - return out - feed; +/* This generates early reflections. + * + * This is done by obtaining the primary reflections (those arriving from the + * same direction as the source) from the main delay line. These are + * attenuated and all-pass filtered (based on the diffusion parameter). + * + * The early lines are then fed in reverse (according to the approximately + * opposite spatial location of the A-Format lines) to create the secondary + * reflections (those arriving from the opposite direction as the source). + * + * The early response is then completed by combining the primary reflections + * with the delayed and attenuated output from the early lines. + * + * Finally, the early response is reversed, scattered (based on diffusion), + * and fed into the late reverb section of the main delay line. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. + */ +#define DECL_TEMPLATE(T) \ +static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ + ALfloat fade, const ALfloat step, \ + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])\ +{ \ + ALsizei offset = State->Offset; \ + const ALfloat apFeedCoeff = State->ApFeedCoeff; \ + const ALfloat mixX = State->MixX; \ + const ALfloat mixY = State->MixY; \ + ALfloat f[4]; \ + ALsizei i, j; \ + \ + for(i = 0;i < todo;i++) \ + { \ + for(j = 0;j < 4;j++) \ + f[j] = DELAY_OUT_##T(&State->Delay, \ + (offset-State->EarlyDelayTap[j][0])*4 + j, \ + (offset-State->EarlyDelayTap[j][1])*4 + j, fade \ + ) * State->EarlyDelayCoeff[j]; \ + \ + VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ + State->Early.Ap); \ + \ + for(j = 0;j < 4;j++) \ + DelayLineIn(&State->Early.Delay[j], offset, f[3 - j]); \ + \ + for(j = 0;j < 4;j++) \ + f[j] += DELAY_OUT_##T(&State->Early.Delay[j], \ + offset-State->Early.Offset[j][0], \ + offset-State->Early.Offset[j][1], fade) * \ + State->Early.Coeff[j]; \ + \ + for(j = 0;j < 4;j++) \ + out[j][i] = f[j]; \ + \ + VectorReverse(f); \ + \ + VectorPartialScatter(f, mixX, mixY); \ + \ + for(j = 0;j < 4;j++) \ + DelayLineIn(&State->Delay, (offset-State->LateFeedTap)*4 + j, \ + f[j]); \ + \ + offset++; \ + fade = minf(1.0f, fade + step);/*fade += step;*/ \ + } \ } +DECL_TEMPLATE(Unfaded) +DECL_TEMPLATE(Faded) +#undef DECL_TEMPLATE -// All-pass series input/output routine for late reverb. -static inline ALfloat LateAllPassInOut(ALreverbState *State, ALsizei offset, ALsizei index, ALfloat sample) +/* Applies a first order filter section. */ +static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat coeffs[3], ALfloat state[2]) { - ALsizei inOffset; - ALsizei i; - - inOffset = offset; - for(i = 0;i < 3;i++) - { - ALuint outOffset = offset - State->Late.Ap[index].Offsets[i]; - sample = AllpassInOut(&State->Late.Ap[index].Delay, - outOffset, inOffset, sample, State->Late.ApFeedCoeff - ); - inOffset = outOffset; - } + ALfloat out = coeffs[0]*in + coeffs[1]*state[0] + coeffs[2]*state[1]; - return sample; -} + state[0] = in; + state[1] = out; -// Low-pass filter input/output routine for late reverb. -static inline ALfloat LateLowPassInOut(ALreverbState *State, ALsizei index, ALfloat in) -{ - in = lerp(in, State->Late.Lp[index].Sample, State->Late.Lp[index].Coeff); - State->Late.Lp[index].Sample = in; - return in; + return out; } -/* Given decorrelated input samples from the main delay line, this function - * produces four-channel output for the late reverb. - */ -static ALvoid LateReverb(ALreverbState *State, ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +/* Applies the two T60 damping filter sections. */ +static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALreverbState *State) { - ALfloat d[4], f[4]; - ALsizei offset; - ALsizei i, j; + ALfloat out = FirstOrderFilter(in, State->Late.Filters[index].LFCoeffs, + State->Late.Filters[index].States[0]); - offset = State->Offset; - for(i = 0;i < todo;i++) - { - /* Obtain four decorrelated input samples. */ - for(j = 0;j < 4;j++) - f[j] = DelayLineOut(&State->Delay, (offset-State->LateDelayTap[j])*4 + j) * - State->Late.DensityGain; - - /* Add the decayed results of the delay lines. */ - for(j = 0;j < 4;j++) - f[j] += DelayLineOut(&State->Late.Delay[j], offset-State->Late.Offset[j]) * - State->Late.Coeff[j]; - - /* Apply a low-pass filter to simulate surface absorption. */ - for(j = 0;j < 4;j++) - f[j] = LateLowPassInOut(State, j, f[j]); - - /* To help increase diffusion, run each line through three all-pass - * filters. This is where the feedback cycles from line 0 to 3 to 1 to - * 2 and back to 0. - */ - d[0] = LateAllPassInOut(State, offset, 2, f[2]); - d[1] = LateAllPassInOut(State, offset, 3, f[3]); - d[2] = LateAllPassInOut(State, offset, 1, f[1]); - d[3] = LateAllPassInOut(State, offset, 0, f[0]); - - /* Late reverb is done with a modified feed-back delay network (FDN) - * topology. Four input lines are each fed through their own all-pass - * filters and then into the mixing matrix. The four outputs of the - * mixing matrix are then cycled back to the inputs. - * - * The mixing matrix used is a 4D skew-symmetric rotation matrix - * derived using a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y - * with differing signs, and d is the coefficient x. The matrix is - * thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * To reduce the number of multiplies, the x coefficient is applied - * with the delay line coefficients. Thus only the y coefficient - * is applied when mixing, and is modified to be: y / x. - */ - f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); - f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); - f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); - f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); - - /* Re-feed the delay lines. */ - for(j = 0;j < 4;j++) - DelayLineIn(&State->Late.Delay[j], offset, f[j]); - offset++; - - /* Output the results of the matrix for all four channels, attenuated - * by the late reverb gain (which is attenuated by the 'x' mix - * coefficient). - */ - for(j = 0;j < 4;j++) - out[j][i] = f[j] * State->Late.Gain; - } + return State->Late.Filters[index].MidCoeff * + FirstOrderFilter(out, State->Late.Filters[index].HFCoeffs, + State->Late.Filters[index].States[1]); } -/* This function reads from the main delay line's late reverb tap, and mixes a - * continuous echo feedback into the four-channel late reverb output. +/* This generates the reverb tail using a modified feed-back delay network + * (FDN). + * + * Results from the early reflections are attenuated by the density gain and + * mixed with the output from the late delay lines. + * + * The late response is then completed by T60 and all-pass filtering the mix. + * + * Finally, the lines are reversed (so they feed their opposite directions) + * and scattered with the FDN matrix before re-feeding the delay lines. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. */ -static ALvoid EAXEcho(ALreverbState *State, ALsizei todo, ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) -{ - ALfloat feed; - ALsizei offset; - ALsizei c, i; - - for(c = 0;c < 4;c++) - { - offset = State->Offset; - for(i = 0;i < todo;i++) - { - // Get the attenuated echo feedback sample for output. - feed = DelayLineOut(&State->Echo.Delay[c].Feedback, offset-State->Echo.Offset) * - State->Echo.Coeff; - - // Write the output. - late[c][i] += State->Echo.MixCoeff * feed; - - // Mix the energy-attenuated input with the output and pass it through - // the echo low-pass filter. - feed += DelayLineOut(&State->Delay, (offset-State->LateDelayTap[0])*4 + c) * - State->Echo.DensityGain; - feed = lerp(feed, State->Echo.LpSample[c], State->Echo.LpCoeff); - State->Echo.LpSample[c] = feed; - - // Then the echo all-pass filter. - feed = AllpassInOut(&State->Echo.Delay[c].Ap, offset-State->Echo.ApOffset, - offset, feed, State->Echo.ApFeedCoeff); - - // Feed the delay with the mixed and filtered sample. - DelayLineIn(&State->Echo.Delay[c].Feedback, offset, feed); - offset++; - } - } +#define DECL_TEMPLATE(T) \ +static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ + ALfloat fade, const ALfloat step, \ + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ +{ \ + const ALfloat apFeedCoeff = State->ApFeedCoeff; \ + const ALfloat mixX = State->MixX; \ + const ALfloat mixY = State->MixY; \ + ALsizei offset; \ + ALsizei i, j; \ + ALfloat f[4]; \ + \ + offset = State->Offset; \ + for(i = 0;i < todo;i++) \ + { \ + for(j = 0;j < 4;j++) \ + f[j] = DELAY_OUT_##T(&State->Delay, \ + (offset-State->LateDelayTap[j][0])*4 + j, \ + (offset-State->LateDelayTap[j][1])*4 + j, fade \ + ) * State->Late.DensityGain; \ + \ + for(j = 0;j < 4;j++) \ + f[j] += DELAY_OUT_##T(&State->Late.Delay[j], \ + offset-State->Late.Offset[j][0], \ + offset-State->Late.Offset[j][1], fade); \ + \ + for(j = 0;j < 4;j++) \ + f[j] = LateT60Filter(j, f[j], State); \ + \ + VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ + State->Late.Ap); \ + \ + for(j = 0;j < 4;j++) \ + out[j][i] = f[j]; \ + \ + VectorReverse(f); \ + \ + VectorPartialScatter(f, mixX, mixY); \ + \ + for(j = 0;j < 4;j++) \ + DelayLineIn(&State->Late.Delay[j], offset, f[j]); \ + \ + offset++; \ + fade = minf(1.0f, fade + step);/*fade += step;*/ \ + } \ } +DECL_TEMPLATE(Unfaded) +DECL_TEMPLATE(Faded) +#undef DECL_TEMPLATE -// Perform the non-EAX reverb pass on a given input sample, resulting in -// four-channel output. -static ALvoid VerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +/* Perform the non-EAX reverb pass on a given input sample, resulting in + * four-channel output. + */ +static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, + const ALfloat step, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], + ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], + ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALsizei i, c; @@ -1465,23 +1778,40 @@ static ALvoid VerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict in * storage). */ ALfilterState_process(&State->Filter[c].Lp, &early[0][0], input[c], todo); + + /* Feed the initial delay line. */ for(i = 0;i < todo;i++) DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[0][i]); } - // Calculate the early reflection from the first delay tap. - EarlyReflection(State, todo, early); + if(fade < 1.0f) + { + /* Generate early reflections. */ + EarlyReflection_Faded(State, todo, fade, step, early); - // Calculate the late reverb from the decorrelator taps. - LateReverb(State, todo, late); + /* Generate late reverb. */ + LateReverb_Faded(State, todo, fade, step, late); + fade = minf(1.0f, fade + todo*step); + } + else + { + /* Generate early reflections. */ + EarlyReflection_Unfaded(State, todo, fade, step, early); - // Step all delays forward one sample. + /* Generate late reverb. */ + LateReverb_Unfaded(State, todo, fade, step, late); + } + + /* Step all delays forward one sample. */ State->Offset += todo; + + return fade; } -// Perform the EAX reverb pass on a given input sample, resulting in four- -// channel output. -static ALvoid EAXVerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +/* Perform the EAX reverb pass on a given input sample, resulting in four- + * channel output. + */ +static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, const ALfloat step, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALsizei i, c; @@ -1491,10 +1821,11 @@ static ALvoid EAXVerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict CalcModulationDelays(State, &late[0][0], todo); for(c = 0;c < 4;c++) { + /* Apply modulation. */ EAXModulation(&State->Mod.Delay[c], State->Offset, &late[0][0], &early[0][0], input[c], todo); - /* Band-pass the incoming samples */ + /* Band-pass the incoming samples. */ ALfilterState_process(&State->Filter[c].Lp, &early[1][0], &early[0][0], todo); ALfilterState_process(&State->Filter[c].Hp, &early[2][0], &early[1][0], todo); @@ -1503,31 +1834,51 @@ static ALvoid EAXVerbPass(ALreverbState *State, ALsizei todo, ALfloat (*restrict DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[2][i]); } - // Calculate the early reflection from the first delay tap. - EarlyReflection(State, todo, early); + if(fade < 1.0f) + { + /* Generate early reflections. */ + EarlyReflection_Faded(State, todo, fade, step, early); - // Calculate the late reverb from the decorrelator taps. - LateReverb(State, todo, late); + /* Generate late reverb. */ + LateReverb_Faded(State, todo, fade, step, late); + fade = minf(1.0f, fade + todo*step); + } + else + { + /* Generate early reflections. */ + EarlyReflection_Unfaded(State, todo, fade, step, early); - // Calculate and mix in any echo. - EAXEcho(State, todo, late); + /* Generate late reverb. */ + LateReverb_Unfaded(State, todo, fade, step, late); + } - // Step all delays forward. + /* Step all delays forward. */ State->Offset += todo; -} + return fade; +} -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], const ALuint NumChannels) { + /* The B-Format to A-Format conversion matrix. The arragement of rows + * is deliberately chosen to align the resulting lines to their spatial + * opposites (0:above front left <-> 3:above back right, 1:below front + * right <-> 2:below back left). It's not quite opposite, since the + * A-Format results in a tetrahedron, but it's close enough. Should the + * model be extended to 8-lines in the future, true opposites can be + * used. + */ static const aluMatrixf B2A = {{ { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f } + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; + ALfloat fade = (ALfloat)State->FadeCount / FADE_SAMPLES; + ALfloat step = 1.0f / FADE_SAMPLES; ALuint base, c; /* Process reverb for these samples. */ @@ -1542,7 +1893,8 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); - VerbPass(State, todo, afmt, early, late); + /* Process the samples for reverb. */ + fade = VerbPass(State, todo, fade, step, afmt, early, late); /* Mix the A-Format results to output, implicitly converting back to * B-Format. @@ -1562,17 +1914,27 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint Samples } } -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], const ALuint NumChannels) { + /* The B-Format to A-Format conversion matrix. The arragement of rows + * is deliberately chosen to align the resulting lines to their spatial + * opposites (0:above front left <-> 3:above back right, 1:below front + * right <-> 2:below back left). It's not quite opposite, since the + * A-Format results in a tetrahedron, but it's close enough. Should the + * model be extended to 8-lines in the future, true opposites can be + * used. + */ static const aluMatrixf B2A = {{ { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f } + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; + ALfloat fade = (ALfloat)State->FadeCount / FADE_SAMPLES; + ALfloat step = 1.0f / FADE_SAMPLES; ALuint base, c; /* Process reverb for these samples. */ @@ -1586,8 +1948,12 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); - EAXVerbPass(State, todo, afmt, early, late); + /* Process the samples for EAX reverb. */ + fade = EAXVerbPass(State, todo, fade, step, afmt, early, late); + /* Mix the A-Format results to output, implicitly converting back to + * B-Format. + */ for(c = 0;c < 4;c++) MixSamples(early[c], NumChannels, SamplesOut, State->Early.CurrentGain[c], State->Early.PanGain[c], @@ -1605,10 +1971,33 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { + /* Process the EAX or non-EAX reverb effect. */ if(State->IsEax) ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); else ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); + + /* Update the cross-fading delay line taps. */ + if(State->FadeCount < FADE_SAMPLES) + { + State->FadeCount += SamplesToDo; + if(State->FadeCount >= FADE_SAMPLES) + { + ALsizei i; + + State->FadeCount = FADE_SAMPLES; + + for(i = 0;i < 4;i++) + { + State->EarlyDelayTap[i][0] = State->EarlyDelayTap[i][1]; + State->Early.Ap[i].Offset[0] = State->Early.Ap[i].Offset[1]; + State->Early.Offset[i][0] = State->Early.Offset[i][1]; + State->LateDelayTap[i][0] = State->LateDelayTap[i][1]; + State->Late.Ap[i].Offset[0] = State->Late.Ap[i].Offset[1]; + State->Late.Offset[i][0] = State->Late.Offset[i][1]; + } + } + } } -- cgit v1.2.3 From 1754d54c18b58995718d2695151a945ee232b0f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2017 18:35:05 -0700 Subject: Compile with -fno-math-errno when available Helps GCC to inline some fp functions, e.g. lrintf --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac1133d4..efb06ebf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,11 @@ ELSE() ENDIF() ENDFOREACH() + CHECK_C_COMPILER_FLAG(-fno-math-errno HAVE_FNO_MATH_ERRNO) + IF(HAVE_FNO_MATH_ERRNO) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fno-math-errno") + ENDIF() + CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor)); int main() {return 0;}" HAVE_GCC_DESTRUCTOR) -- cgit v1.2.3 From ca5c732261bfacdb4702fcc253b3ef0dad357a35 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2017 18:38:09 -0700 Subject: Implement a limiter on the device output This reduces the output volume when the mixed samples extend outside of -1,+1, to prevent excessive clipping. It can reduce the volume by -80dB in 50ms, and increase it by +80dB in 1s (it will not go below -80dB or above 0dB). --- Alc/ALc.c | 14 ++++++++--- Alc/ALu.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++- OpenAL32/Include/alMain.h | 2 ++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 808580f3..537513f3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2192,13 +2192,19 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->FOAOut.NumChannels = device->Dry.NumChannels; } - /* Need to delay returning failure until replacement Send arrays have been - * allocated with the appropriate size. - */ device->NumAuxSends = new_sends; TRACE("Max sources: %d (%d + %d), effect slots: %d, sends: %d\n", device->SourcesMax, device->NumMonoSources, device->NumStereoSources, device->AuxiliaryEffectSlotMax, device->NumAuxSends); + + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", 1)) + device->LimiterGain = 1.0f; + else + device->LimiterGain = 0.0f; + + /* Need to delay returning failure until replacement Send arrays have been + * allocated with the appropriate size. + */ update_failed = AL_FALSE; SetMixerFPUMode(&oldMode); if(device->DefaultSlot) @@ -3794,6 +3800,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; + device->LimiterGain = 1.0f; device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); @@ -4322,6 +4329,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; + device->LimiterGain = 1.0f; device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); diff --git a/Alc/ALu.c b/Alc/ALu.c index 587952b2..01e6bbfa 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1333,6 +1333,49 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } +static ALfloat ApplyLimiter(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, + const ALfloat AttackRate, const ALfloat ReleaseRate, + const ALfloat InGain, ALfloat (*restrict Gains), + const ALsizei SamplesToDo) +{ + bool do_limit = false; + ALsizei c, i; + + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); + Gains = ASSUME_ALIGNED(Gains, 16); + + for(i = 0;i < SamplesToDo;i++) + Gains[i] = 1.0f; + + for(c = 0;c < NumChans;c++) + { + ALfloat lastgain = InGain; + for(i = 0;i < SamplesToDo;i++) + { + /* Clamp limiter range to 0dB...-80dB. */ + ALfloat gain = 1.0f / clampf(fabsf(OutBuffer[c][i]), 1.0f, 1000.0f); + if(lastgain >= gain) + lastgain = maxf(lastgain*AttackRate, gain); + else + lastgain = minf(lastgain/ReleaseRate, gain); + do_limit |= (lastgain < 1.0f); + + lastgain = minf(lastgain, Gains[i]); + Gains[i] = lastgain; + } + } + if(do_limit) + { + for(c = 0;c < NumChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[c][i] *= Gains[i]; + } + } + + return Gains[SamplesToDo-1]; +} + static inline ALfloat aluF2F(ALfloat val) { return val; } @@ -1579,8 +1622,23 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; - DistanceComp *DistComp = device->ChannelDelay; + DistanceComp *DistComp; + + if(device->LimiterGain > 0.0f) + { + /* Limiter attack drops -80dB in 50ms. */ + const ALfloat AttackRate = powf(0.0001f, 1.0f/(device->Frequency*0.05f)); + /* Limiter release raises +80dB in 1s. */ + const ALfloat ReleaseRate = powf(0.0001f, 1.0f/(device->Frequency*1.0f)); + + /* Use NFCtrlData for temp gain storage. */ + device->LimiterGain = ApplyLimiter(OutBuffer, OutChannels, + AttackRate, ReleaseRate, device->LimiterGain, device->NFCtrlData, + SamplesToDo + ); + } + DistComp = device->ChannelDelay; #define WRITE(T, a, b, c, d, e) do { \ Write_##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \ buffer = (T*)buffer + (d)*(e); \ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 174210fa..52c9465c 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -795,6 +795,8 @@ struct ALCdevice_struct ALsizei NumChannels; } RealOut; + ALfloat LimiterGain; + /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. */ -- cgit v1.2.3 From 8f56c9522e65405d591ee2eacdcbf9e29caab9fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Apr 2017 19:27:50 -0700 Subject: Document the output-limiter config option Expose it in alsoft-config as well. --- alsoftrc.sample | 6 ++++++ utils/alsoft-config/mainwindow.cpp | 16 ++++++++++++++++ utils/alsoft-config/mainwindow.ui | 29 +++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index fcdd4027..e8a28479 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -181,6 +181,12 @@ # than the default has no effect. #sends = 16 +## output-limiter: +# Applies a gain limiter on the final mixed output. This reduces the volume +# when the output samples would otherwise clamp, avoiding excessive clipping +# noise. +#output-limiter = true + ## volume-adjust: # A global volume adjustment for source output, expressed in decibels. The # value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 26d05f8f..d46bb029 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -328,6 +328,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->stereoEncodingComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->outputLimiterCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -641,6 +642,13 @@ void MainWindow::loadConfig(const QString &fname) updatePeriodCountSlider(); } + if(settings.value("output-limiter").isNull()) + ui->outputLimiterCheckBox->setCheckState(Qt::PartiallyChecked); + else + ui->outputLimiterCheckBox->setCheckState( + settings.value("output-limiter").toBool() ? Qt::Checked : Qt::Unchecked + ); + QString stereopan = settings.value("stereo-encoding").toString(); ui->stereoEncodingComboBox->setCurrentIndex(0); if(stereopan.isEmpty() == false) @@ -896,6 +904,14 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("stereo-encoding", getValueFromName(stereoEncList, ui->stereoEncodingComboBox->currentText())); settings.setValue("ambi-format", getValueFromName(ambiFormatList, ui->ambiFormatComboBox->currentText())); + Qt::CheckState limiter = ui->outputLimiterCheckBox->checkState(); + if(limiter == Qt::PartiallyChecked) + settings.setValue("output-limiter", QString()); + else if(limiter == Qt::Checked) + settings.setValue("output-limiter", QString("true")); + else if(limiter == Qt::Unchecked) + settings.setValue("output-limiter", QString("false")); + settings.setValue("decoder/hq-mode", ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index a527cfd5..153bcc04 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -129,7 +129,7 @@ to stereo output. 380 20 91 - 21 + 29 @@ -236,9 +236,9 @@ otherwise be suitable for speakers. -11 - 200 + 180 551 - 181 + 201 @@ -483,6 +483,27 @@ receiver. + + + + 30 + 160 + 231 + 20 + + + + Applies a gain limiter on the final mixed output. This reduces the +volume when the output samples would otherwise be clamped, +avoiding excessive clipping noise. + + + Enable Gain Limiter + + + true + + @@ -2107,7 +2128,7 @@ added by the ALC_EXT_DEDICATED extension. 160 20 123 - 21 + 29 -- cgit v1.2.3 From 55d9988f3f4090fda224e1e0989baa375cb5edaf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Apr 2017 06:35:53 -0700 Subject: Write directly to the output for HRTF --- Alc/mixer_inc.c | 77 +++++++++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index ee3286e9..16c3a61e 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -9,9 +9,6 @@ #include "alu.h" -#define MAX_UPDATE_SAMPLES 128 - - static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei irSize, const ALfloat (*restrict Coeffs)[2], @@ -28,34 +25,24 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat gainstep = hrtfparams->GainStep; ALfloat gain = hrtfparams->Gain; ALfloat left, right; - ALsizei pos, i; + ALsizei i; - for(pos = 0;pos < BufferSize;) + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) { - ALfloat out[MAX_UPDATE_SAMPLES][2]; - ALsizei todo = mini(BufferSize-pos, MAX_UPDATE_SAMPLES); - - for(i = 0;i < todo;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos++]; - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; - - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0]*gain; - out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1]*gain; - gain += gainstep; - } - - for(i = 0;i < todo;i++) - LeftOut[OutPos+i] += out[i][0]; - for(i = 0;i < todo;i++) - RightOut[OutPos+i] += out[i][1]; - OutPos += todo; + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; + + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]*gain; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]*gain; + gain += gainstep; } hrtfparams->Gain = gain; } @@ -65,30 +52,18 @@ void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], ALsizei BufferSize) { - ALfloat out[MAX_UPDATE_SAMPLES][2]; ALfloat insample; - ALsizei pos, i; + ALsizei i; - for(pos = 0;pos < BufferSize;) + for(i = 0;i < BufferSize;i++) { - ALsizei todo = mini(BufferSize-pos, MAX_UPDATE_SAMPLES); - - for(i = 0;i < todo;i++) - { - Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - insample = *(data++); - ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); - out[i][0] = Values[Offset&HRIR_MASK][0]; - out[i][1] = Values[Offset&HRIR_MASK][1]; - } - - for(i = 0;i < todo;i++) - LeftOut[pos+i] += out[i][0]; - for(i = 0;i < todo;i++) - RightOut[pos+i] += out[i][1]; - pos += todo; + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + insample = *(data++); + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + *(LeftOut++) += Values[Offset&HRIR_MASK][0]; + *(RightOut++) += Values[Offset&HRIR_MASK][1]; } } -- cgit v1.2.3 From 5dc7265ad3998f7de5b3f10b3b1322aef05b3104 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Apr 2017 18:54:33 -0700 Subject: Properly update the delay line offsets when fading is done --- Alc/effects/reverb.c | 72 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index e5cf11b0..000ba59a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -43,6 +43,12 @@ */ #define FADE_SAMPLES 128 +#ifdef __GNUC__ +#define UNEXPECTED(x) __builtin_expect((bool)(x), 0) +#else +#define UNEXPECTED(x) (x) +#endif + static MixerFunc MixSamples = Mix_C; static RowMixerFunc MixRowSamples = MixRow_C; @@ -1874,11 +1880,12 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint S { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; + static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALfloat fade = (ALfloat)State->FadeCount / FADE_SAMPLES; - ALfloat step = 1.0f / FADE_SAMPLES; + ALsizei fadeCount = State->FadeCount; + ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; ALuint base, c; /* Process reverb for these samples. */ @@ -1894,7 +1901,21 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint S ); /* Process the samples for reverb. */ - fade = VerbPass(State, todo, fade, step, afmt, early, late); + fade = VerbPass(State, todo, fade, FadeStep, afmt, early, late); + if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES) + { + /* Update the cross-fading delay line taps. */ + fadeCount = FADE_SAMPLES; + for(c = 0;c < 4;c++) + { + State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->Early.Ap[c].Offset[0] = State->Early.Ap[c].Offset[1]; + State->Early.Offset[c][0] = State->Early.Offset[c][1]; + State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; + State->Late.Ap[c].Offset[0] = State->Late.Ap[c].Offset[1]; + State->Late.Offset[c][0] = State->Late.Offset[c][1]; + } + } /* Mix the A-Format results to output, implicitly converting back to * B-Format. @@ -1912,6 +1933,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint S base += todo; } + State->FadeCount = fadeCount; } static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], const ALuint NumChannels) @@ -1930,11 +1952,12 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint Sample { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; + static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALfloat fade = (ALfloat)State->FadeCount / FADE_SAMPLES; - ALfloat step = 1.0f / FADE_SAMPLES; + ALsizei fadeCount = State->FadeCount; + ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; ALuint base, c; /* Process reverb for these samples. */ @@ -1949,7 +1972,21 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint Sample ); /* Process the samples for EAX reverb. */ - fade = EAXVerbPass(State, todo, fade, step, afmt, early, late); + fade = EAXVerbPass(State, todo, fade, FadeStep, afmt, early, late); + if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES) + { + /* Update the cross-fading delay line taps. */ + fadeCount = FADE_SAMPLES; + for(c = 0;c < 4;c++) + { + State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->Early.Ap[c].Offset[0] = State->Early.Ap[c].Offset[1]; + State->Early.Offset[c][0] = State->Early.Offset[c][1]; + State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; + State->Late.Ap[c].Offset[0] = State->Late.Ap[c].Offset[1]; + State->Late.Offset[c][0] = State->Late.Offset[c][1]; + } + } /* Mix the A-Format results to output, implicitly converting back to * B-Format. @@ -1967,6 +2004,7 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint Sample base += todo; } + State->FadeCount = fadeCount; } static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) @@ -1976,28 +2014,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, co ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); else ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); - - /* Update the cross-fading delay line taps. */ - if(State->FadeCount < FADE_SAMPLES) - { - State->FadeCount += SamplesToDo; - if(State->FadeCount >= FADE_SAMPLES) - { - ALsizei i; - - State->FadeCount = FADE_SAMPLES; - - for(i = 0;i < 4;i++) - { - State->EarlyDelayTap[i][0] = State->EarlyDelayTap[i][1]; - State->Early.Ap[i].Offset[0] = State->Early.Ap[i].Offset[1]; - State->Early.Offset[i][0] = State->Early.Offset[i][1]; - State->LateDelayTap[i][0] = State->LateDelayTap[i][1]; - State->Late.Ap[i].Offset[0] = State->Late.Ap[i].Offset[1]; - State->Late.Offset[i][0] = State->Late.Offset[i][1]; - } - } - } } -- cgit v1.2.3 From bf138fb4eaf773110a26ccc53c17c5ce1ec4de44 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 27 Apr 2017 19:23:42 -0700 Subject: Combine mostly duplicate functions --- Alc/effects/reverb.c | 171 +++++++++++++++------------------------------------ 1 file changed, 50 insertions(+), 121 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 000ba59a..60ff79b2 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -303,6 +303,30 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) ALeffectState_Destruct(STATIC_CAST(ALeffectState,State)); } +/* The B-Format to A-Format conversion matrix. The arrangement of rows is + * deliberately chosen to align the resulting lines to their spatial opposites + * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below + * back left). It's not quite opposite, since the A-Format results in a + * tetrahedron, but it's close enough. Should the model be extended to 8-lines + * in the future, true opposites can be used. + */ +static const aluMatrixf B2A = {{ + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } +}}; + +/* Converts A-Format to B-Format (transposed). */ +static const aluMatrixf A2B = {{ + { 0.8660254038f, 0.8660254038f, 0.8660254038f, 0.8660254038f }, + { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f }, + { 0.8660254038f, 0.8660254038f, -0.8660254038f, -0.8660254038f }, + { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f } +}}; + +static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; + /* This is a user config option for modifying the overall output of the reverb * effect. */ @@ -1275,14 +1299,6 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) /* Update the early and late 3D panning gains. */ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat gain, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State) { - /* Converts A-Format to B-Format (transposed). */ - static const aluMatrixf A2B = {{ - { 0.8660254038f, 0.8660254038f, 0.8660254038f, 0.8660254038f }, - { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f }, - { 0.8660254038f, 0.8660254038f, -0.8660254038f, -0.8660254038f }, - { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f } - }}; - aluMatrixf transform, rot; ALsizei i; @@ -1633,7 +1649,7 @@ static inline void VectorReverse(ALfloat vec[4]) */ #define DECL_TEMPLATE(T) \ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ - ALfloat fade, const ALfloat step, \ + ALfloat fade, \ ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])\ { \ ALsizei offset = State->Offset; \ @@ -1675,7 +1691,7 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ f[j]); \ \ offset++; \ - fade = minf(1.0f, fade + step);/*fade += step;*/ \ + fade = minf(1.0f, fade + FadeStep); \ } \ } DECL_TEMPLATE(Unfaded) @@ -1720,7 +1736,7 @@ static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALrev */ #define DECL_TEMPLATE(T) \ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ - ALfloat fade, const ALfloat step, \ + ALfloat fade, \ ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ { \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ @@ -1761,18 +1777,22 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ DelayLineIn(&State->Late.Delay[j], offset, f[j]); \ \ offset++; \ - fade = minf(1.0f, fade + step);/*fade += step;*/ \ + fade = minf(1.0f, fade + FadeStep); \ } \ } DECL_TEMPLATE(Unfaded) DECL_TEMPLATE(Faded) #undef DECL_TEMPLATE +typedef ALfloat (*ProcMethodType)(ALreverbState *State, const ALsizei todo, ALfloat fade, + const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], + ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]); + /* Perform the non-EAX reverb pass on a given input sample, resulting in * four-channel output. */ static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, - const ALfloat step, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], + const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { @@ -1793,19 +1813,19 @@ static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, if(fade < 1.0f) { /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, step, early); + EarlyReflection_Faded(State, todo, fade, early); /* Generate late reverb. */ - LateReverb_Faded(State, todo, fade, step, late); - fade = minf(1.0f, fade + todo*step); + LateReverb_Faded(State, todo, fade, late); + fade = minf(1.0f, fade + todo*FadeStep); } else { /* Generate early reflections. */ - EarlyReflection_Unfaded(State, todo, fade, step, early); + EarlyReflection_Unfaded(State, todo, fade, early); /* Generate late reverb. */ - LateReverb_Unfaded(State, todo, fade, step, late); + LateReverb_Unfaded(State, todo, fade, late); } /* Step all delays forward one sample. */ @@ -1817,7 +1837,10 @@ static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, /* Perform the EAX reverb pass on a given input sample, resulting in four- * channel output. */ -static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, const ALfloat step, ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) +static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, + const ALfloat (*restrict input)[MAX_UPDATE_SAMPLES], + ALfloat (*restrict early)[MAX_UPDATE_SAMPLES], + ALfloat (*restrict late)[MAX_UPDATE_SAMPLES]) { ALsizei i, c; @@ -1843,19 +1866,19 @@ static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fad if(fade < 1.0f) { /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, step, early); + EarlyReflection_Faded(State, todo, fade, early); /* Generate late reverb. */ - LateReverb_Faded(State, todo, fade, step, late); - fade = minf(1.0f, fade + todo*step); + LateReverb_Faded(State, todo, fade, late); + fade = minf(1.0f, fade + todo*FadeStep); } else { /* Generate early reflections. */ - EarlyReflection_Unfaded(State, todo, fade, step, early); + EarlyReflection_Unfaded(State, todo, fade, early); /* Generate late reverb. */ - LateReverb_Unfaded(State, todo, fade, step, late); + LateReverb_Unfaded(State, todo, fade, late); } /* Step all delays forward. */ @@ -1864,23 +1887,9 @@ static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fad return fade; } -static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], const ALuint NumChannels) +static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { - /* The B-Format to A-Format conversion matrix. The arragement of rows - * is deliberately chosen to align the resulting lines to their spatial - * opposites (0:above front left <-> 3:above back right, 1:below front - * right <-> 2:below back left). It's not quite opposite, since the - * A-Format results in a tetrahedron, but it's close enough. Should the - * model be extended to 8-lines in the future, true opposites can be - * used. - */ - static const aluMatrixf B2A = {{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } - }}; - static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; + ProcMethodType ReverbProc = State->IsEax ? EAXVerbPass : VerbPass; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; @@ -1901,78 +1910,7 @@ static ALvoid ALreverbState_processStandard(ALreverbState *State, const ALuint S ); /* Process the samples for reverb. */ - fade = VerbPass(State, todo, fade, FadeStep, afmt, early, late); - if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES) - { - /* Update the cross-fading delay line taps. */ - fadeCount = FADE_SAMPLES; - for(c = 0;c < 4;c++) - { - State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->Early.Ap[c].Offset[0] = State->Early.Ap[c].Offset[1]; - State->Early.Offset[c][0] = State->Early.Offset[c][1]; - State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.Ap[c].Offset[0] = State->Late.Ap[c].Offset[1]; - State->Late.Offset[c][0] = State->Late.Offset[c][1]; - } - } - - /* Mix the A-Format results to output, implicitly converting back to - * B-Format. - */ - for(c = 0;c < 4;c++) - MixSamples(early[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], - SamplesToDo-base, base, todo - ); - for(c = 0;c < 4;c++) - MixSamples(late[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], - SamplesToDo-base, base, todo - ); - - base += todo; - } - State->FadeCount = fadeCount; -} - -static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], const ALuint NumChannels) -{ - /* The B-Format to A-Format conversion matrix. The arragement of rows - * is deliberately chosen to align the resulting lines to their spatial - * opposites (0:above front left <-> 3:above back right, 1:below front - * right <-> 2:below back left). It's not quite opposite, since the - * A-Format results in a tetrahedron, but it's close enough. Should the - * model be extended to 8-lines in the future, true opposites can be - * used. - */ - static const aluMatrixf B2A = {{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } - }}; - static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; - ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; - ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; - ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; - ALsizei fadeCount = State->FadeCount; - ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; - ALuint base, c; - - /* Process reverb for these samples. */ - for(base = 0;base < SamplesToDo;) - { - ALsizei todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); - - memset(afmt, 0, 4*MAX_UPDATE_SAMPLES*sizeof(float)); - for(c = 0;c < 4;c++) - MixRowSamples(afmt[c], B2A.m[c], - SamplesIn, MAX_EFFECT_CHANNELS, base, todo - ); - - /* Process the samples for EAX reverb. */ - fade = EAXVerbPass(State, todo, fade, FadeStep, afmt, early, late); + fade = ReverbProc(State, todo, fade, afmt, early, late); if(UNEXPECTED(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES) { /* Update the cross-fading delay line taps. */ @@ -2007,15 +1945,6 @@ static ALvoid ALreverbState_processEax(ALreverbState *State, const ALuint Sample State->FadeCount = fadeCount; } -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) -{ - /* Process the EAX or non-EAX reverb effect. */ - if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); - else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); -} - typedef struct ALreverbStateFactory { DERIVE_FROM_TYPE(ALeffectStateFactory); -- cgit v1.2.3 From dc253700637d2154f3103ca627c8d2ac1a7c1ddd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Apr 2017 10:05:57 -0700 Subject: Fade HRTF coefficients over 64 samples at most This greatly improves HRTF performance since the dual-mix only applies to the 64-sample coefficient transition. So rather than doubling the full mix, it only doubles 64 samples out of the full mix. --- Alc/mixer.c | 109 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 40 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 39def41f..e8d04bc2 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -277,6 +277,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei OutPos; ALsizei IrSize; bool isplaying; + bool firstpass; ALsizei chan; ALsizei send; @@ -296,7 +297,9 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Resample_copy32_C : voice->Resampler); Counter = (voice->Flags&VOICE_IS_MOVING) ? SamplesToDo : 0; + firstpass = true; OutPos = 0; + do { ALsizei SrcBufferSize, DstBufferSize; @@ -485,6 +488,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei else { MixHrtfParams hrtfparams; + ALsizei fademix = 0; int lidx, ridx; lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); @@ -493,70 +497,94 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei if(!Counter) { + /* No fading, just overwrite the old HRTF params. */ parms->Hrtf.Old = parms->Hrtf.Target; - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Target.Gain; - hrtfparams.GainStep = 0.0f; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, DstBufferSize - ); } - else + else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to + * 0. The future mix will then fade from silence. + */ + parms->Hrtf.Old = parms->Hrtf.Target; + parms->Hrtf.Old.Gain = 0.0f; + } + else if(firstpass && parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) + { + HrtfState backupstate = parms->Hrtf.State; ALfloat gain; + /* Fade between the coefficients over 64 samples. */ + fademix = mini(DstBufferSize, 64); + /* The old coefficients need to fade to silence - * completely since they'll be replaced after the mix. - * So it needs to fade out over DstBufferSize instead - * of Counter. - * - * Don't bother with the fade out when starting from - * silence. + * completely since they'll be replaced after this mix. */ - if(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) - { - HrtfState backupstate = parms->Hrtf.State; - - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); - hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = -hrtfparams.Gain / - (ALfloat)DstBufferSize; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &backupstate, DstBufferSize - ); - } + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = -hrtfparams.Gain / (ALfloat)fademix; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &backupstate, fademix + ); /* The new coefficients need to fade in completely * since they're replacing the old ones. To keep the - * source gain fading consistent, interpolate between - * the old and new target gain given how much of the - * fade time this mix handles. + * gain fading consistent, interpolate between the old + * and new target gains given how much of the fade time + * this mix handles. */ gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - (ALfloat)DstBufferSize/Counter); + minf(1.0f, (ALfloat)fademix/Counter)); hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / (ALfloat)DstBufferSize; + hrtfparams.GainStep = gain / (ALfloat)fademix; MixHrtfSamples( voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, DstBufferSize + &parms->Hrtf.State, fademix ); /* Update the old parameters with the result. */ parms->Hrtf.Old = parms->Hrtf.Target; - if(DstBufferSize < Counter) + if(fademix < Counter) parms->Hrtf.Old.Gain = hrtfparams.Gain; } + + if(fademix < DstBufferSize) + { + ALsizei todo = DstBufferSize - fademix; + ALfloat gain = parms->Hrtf.Target.Gain; + + /* Interpolate the target gain if the gain fading lasts + * longer than this mix. + */ + if(Counter > DstBufferSize) + gain = lerp(parms->Hrtf.Old.Gain, gain, + (ALfloat)todo/(Counter-fademix)); + + hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, + &hrtfparams, &parms->Hrtf.State, todo + ); + /* Store the interpolated gain or the final target gain + * depending if the fade is done. + */ + if(DstBufferSize < Counter) + parms->Hrtf.Old.Gain = gain; + else + parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; + } } } @@ -589,6 +617,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei OutPos += DstBufferSize; voice->Offset += DstBufferSize; Counter = maxi(DstBufferSize, Counter) - DstBufferSize; + firstpass = false; /* Handle looping sources */ while(1) -- cgit v1.2.3 From 9767f4f9c3d61729e56699756c1c390547faf1df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Apr 2017 10:21:15 -0700 Subject: Don't do more reverb samples than there are to fade. This avoids having to clamp the fade value when incrementing it. --- Alc/effects/reverb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 60ff79b2..6e5144fa 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1691,7 +1691,7 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ f[j]); \ \ offset++; \ - fade = minf(1.0f, fade + FadeStep); \ + fade += FadeStep; \ } \ } DECL_TEMPLATE(Unfaded) @@ -1777,7 +1777,7 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ DelayLineIn(&State->Late.Delay[j], offset, f[j]); \ \ offset++; \ - fade = minf(1.0f, fade + FadeStep); \ + fade += FadeStep; \ } \ } DECL_TEMPLATE(Unfaded) @@ -1901,6 +1901,9 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, co for(base = 0;base < SamplesToDo;) { ALsizei todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); + /* If cross-fading, don't do more samples than there are to fade. */ + if(FADE_SAMPLES-fadeCount > 0) + todo = mini(todo, FADE_SAMPLES-fadeCount); /* Convert B-Format to A-Format for processing. */ memset(afmt, 0, sizeof(*afmt)*4); @@ -1915,6 +1918,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, co { /* Update the cross-fading delay line taps. */ fadeCount = FADE_SAMPLES; + fade = 1.0f; for(c = 0;c < 4;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; -- cgit v1.2.3 From fc2afa1eaab1dd29833c74e720210d54a6a449bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Apr 2017 04:21:48 -0700 Subject: Start an extension to toggle the output limiter --- Alc/ALc.c | 23 ++++++++++++++++++----- OpenAL32/Include/alMain.h | 5 +++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 537513f3..6644f271 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -364,6 +364,8 @@ static const struct { DECL(ALC_N3D_SOFT), DECL(ALC_SN3D_SOFT), + DECL(ALC_OUTPUT_LIMITER_SOFT), + DECL(ALC_NO_ERROR), DECL(ALC_INVALID_DEVICE), DECL(ALC_INVALID_CONTEXT), @@ -777,7 +779,7 @@ 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_SOFTX_device_clock ALC_SOFT_HRTF " - "ALC_SOFT_loopback ALC_SOFT_pause_device"; + "ALC_SOFT_loopback ALC_SOFTX_output_limiter ALC_SOFT_pause_device"; static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; @@ -1757,6 +1759,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { enum HrtfRequestMode hrtf_userreq = Hrtf_Default; enum HrtfRequestMode hrtf_appreq = Hrtf_Default; + ALCenum gainLimiter = (device->LimiterGain > 0.0f); const ALsizei old_sends = device->NumAuxSends; ALsizei new_sends = device->NumAuxSends; enum DevFmtChannels oldChans; @@ -1768,6 +1771,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) FPUCtl oldMode; size_t size; ALCsizei i; + int val; // Check for attributes if(device->Type == Loopback) @@ -1871,6 +1875,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); break; + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; + default: TRACE("Loopback 0x%04X = %d (0x%x)\n", attrList[attrIdx], attrList[attrIdx + 1], attrList[attrIdx + 1]); @@ -1993,6 +2002,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE_ATTR(ALC_HRTF_ID_SOFT, hrtf_id); break; + case ALC_OUTPUT_LIMITER_SOFT: + gainLimiter = attrList[attrIdx + 1]; + TRACE_ATTR(ALC_OUTPUT_LIMITER_SOFT, gainLimiter); + break; + default: TRACE("0x%04X = %d (0x%x)\n", attrList[attrIdx], attrList[attrIdx + 1], attrList[attrIdx + 1]); @@ -2197,10 +2211,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->SourcesMax, device->NumMonoSources, device->NumStereoSources, device->AuxiliaryEffectSlotMax, device->NumAuxSends); - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", 1)) - device->LimiterGain = 1.0f; - else - device->LimiterGain = 0.0f; + if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) + gainLimiter = val; + device->LimiterGain = gainLimiter ? 1.0f : 0.0f; /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 52c9465c..32865cae 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -152,6 +152,11 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #endif #endif +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + #if defined(_WIN64) #define SZFMT "%I64u" -- cgit v1.2.3 From 8d50b72d8ffeff6e8ba155ca46e9d4287c82e88e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Apr 2017 08:54:49 -0700 Subject: Allow querying the output limiter state --- Alc/ALc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 6644f271..d5286f4f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3015,8 +3015,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para static inline ALCsizei NumAttrsForDevice(ALCdevice *device) { if(device->Type == Loopback && device->FmtChans == DevFmtAmbi3D) - return 23; - return 17; + return 25; + return 19; } static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) @@ -3162,6 +3162,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->HrtfStatus; + + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -3268,6 +3271,10 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC almtx_unlock(&device->BackendLock); return 1; + case ALC_OUTPUT_LIMITER_SOFT: + values[0] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; + return 1; + default: alcSetError(device, ALC_INVALID_ENUM); return 0; @@ -3372,6 +3379,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = ALC_HRTF_STATUS_SOFT; values[i++] = device->HrtfStatus; + values[i++] = ALC_OUTPUT_LIMITER_SOFT; + values[i++] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; + clock = V0(device->Backend,getClockLatency)(); values[i++] = ALC_DEVICE_CLOCK_SOFT; values[i++] = clock.ClockTime; -- cgit v1.2.3 From f1a249b47a31eb7d7501cdc443611f6973159893 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 May 2017 15:46:25 -0700 Subject: Reimplement bilinear interpolation between HRIRs Some data sets are just too sparse, having noticeably few measurements to properly handle slowly panning sources. Although not perfect, bilinearly interpolating the HRIR measurements improves the positional accuracy. --- Alc/hrtf.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 25 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d791113d..5d49eaf5 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -67,20 +67,28 @@ static struct HrtfEntry *LoadedHrtfs = NULL; * will return an index between 0 and (evcount - 1). Assumes the FPU is in * round-to-zero mode. */ -static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev) +static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) { - ev = (F_PI_2 + ev) * (evcount-1) / F_PI; - return mini(fastf2i(ev + 0.5f), evcount-1); + ALsizei idx; + ev = (F_PI_2+ev) * (evcount-1) / F_PI; + idx = mini(fastf2i(ev), evcount-1); + + *mu = ev - idx; + return idx; } /* Calculate the azimuth index given the polar azimuth in radians. This will * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to- * zero mode. */ -static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az) +static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) { - az = (F_TAU + az) * azcount / F_TAU; - return fastf2i(az + 0.5f) % azcount; + ALsizei idx; + az = (F_TAU+az) * azcount / F_TAU; + + idx = fastf2i(az) % azcount; + *mu = az - floorf(az); + return idx; } /* Calculates static HRIR coefficients and delays for the given polar elevation @@ -88,38 +96,87 @@ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az) */ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays) { - ALsizei evidx, azidx, idx; + ALsizei evidx, azidx, idx[4]; ALsizei evoffset; + ALfloat emu, amu[2]; + ALfloat blend[4]; ALfloat dirfact; - ALsizei i; + ALsizei i, c; dirfact = 1.0f - (spread / F_TAU); - /* Claculate elevation index. */ - evidx = CalcEvIndex(Hrtf->evCount, elevation); + /* Claculate the lower elevation index. */ + evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu); evoffset = Hrtf->evOffset[evidx]; - /* Calculate azimuth index. */ - azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth); + /* Calculate lower azimuth index. */ + azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]); - /* Calculate the HRIR indices for left and right channels. */ - idx = evoffset + azidx; + /* Calculate the lower HRIR indices. */ + idx[0] = evoffset + azidx; + idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); + if(evidx < Hrtf->evCount-1) + { + /* Increment elevation to the next (upper) index. */ + evidx++; + evoffset = Hrtf->evOffset[evidx]; - /* Calculate the HRIR delays. */ - delays[0] = fastf2i(Hrtf->delays[idx][0]*dirfact + 0.5f); - delays[1] = fastf2i(Hrtf->delays[idx][1]*dirfact + 0.5f); + /* Calculate upper azimuth index. */ + azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[1]); - /* Calculate the sample offsets for the HRIR indices. */ - idx *= Hrtf->irSize; + /* Calculate the upper HRIR indices. */ + idx[2] = evoffset + azidx; + idx[3] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]); + } + else + { + /* If the lower elevation is the top index, the upper elevation is the + * same as the lower. + */ + amu[1] = amu[0]; + idx[2] = idx[0]; + idx[3] = idx[1]; + } - /* Calculate the normalized and attenuated HRIR coefficients. */ - i = 0; - coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[idx+i][0], dirfact); - coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[idx+i][1], dirfact); + /* Calculate bilinear blending weights, attenuated according to the + * directional panning factor. + */ + blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact; + blend[1] = (1.0f-emu) * ( amu[0]) * dirfact; + blend[2] = ( emu) * (1.0f-amu[1]) * dirfact; + blend[3] = ( emu) * ( amu[1]) * dirfact; + + /* Calculate the blended HRIR delays. */ + delays[0] = fastf2i( + Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + 0.5f + ); + delays[1] = fastf2i( + Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f + ); + + /* Calculate the sample offsets for the HRIR indices. */ + idx[0] *= Hrtf->irSize; + idx[1] *= Hrtf->irSize; + idx[2] *= Hrtf->irSize; + idx[3] *= Hrtf->irSize; + + /* Calculate the blended HRIR coefficients. */ + coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); + coeffs[0][1] = PassthruCoeff * (1.0f-dirfact); for(i = 1;i < Hrtf->irSize;i++) { - coeffs[i][0] = Hrtf->coeffs[idx+i][0] * dirfact; - coeffs[i][1] = Hrtf->coeffs[idx+i][1] * dirfact; + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + } + for(c = 0;c < 4;c++) + { + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] += Hrtf->coeffs[idx[c]+i][0] * blend[c]; + coeffs[i][1] += Hrtf->coeffs[idx[c]+i][1] * blend[c]; + } } } -- cgit v1.2.3 From afe2065d60d211a8009909abc327eea8830c10f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 03:57:17 -0700 Subject: Set a voice as 'moving' if it starts/resumes at an offset --- OpenAL32/alSource.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f2c4908f..3720ce49 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2438,6 +2438,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { ALbufferlistitem *BufferList; ALbuffer *buffer = NULL; + bool start_moving = false; + ALsizei s; source = LookupSource(context, sources[i]); WriteLock(&source->queue_lock); @@ -2478,11 +2480,17 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) case AL_PAUSED: assert(voice != NULL); - /* A source that's paused simply resumes. Make sure it uses the - * volume last specified; there's no reason to fade from where - * it stopped at. + /* A source that's paused simply resumes. Clear its mixing + * parameters and mark it as 'moving' so it fades in from + * silence. */ - voice->Flags &= ~VOICE_IS_MOVING; + voice->Step = 0; + voice->Flags |= VOICE_IS_MOVING; + memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])* + voice->NumChannels); + for(s = 0;s < device->NumAuxSends;s++) + memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])* + voice->NumChannels); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); goto finish_play; @@ -2521,7 +2529,12 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); if(source->OffsetType != AL_NONE) + { ApplyOffset(source, voice); + start_moving = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || + ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || + ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; + } voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); voice->SampleSize = BytesFromFmt(buffer->FmtType); @@ -2534,10 +2547,10 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) */ voice->Step = 0; - voice->Flags = 0; - for(j = 0;j < voice->NumChannels;j++) - memset(&voice->Direct.Params[j].Hrtf.State, 0, - sizeof(voice->Direct.Params[j].Hrtf.State)); + voice->Flags = start_moving ? VOICE_IS_MOVING : 0; + memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); + for(s = 0;s < device->NumAuxSends;s++) + memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels); if(device->AvgSpeakerDist > 0.0f) { ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / -- cgit v1.2.3 From 2f8d597f4ef3bcdfdad10edac2e9f74ddf3e23ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 04:09:01 -0700 Subject: Rename 'moving' flag to 'fading' --- Alc/mixer.c | 4 ++-- OpenAL32/Include/alu.h | 4 ++-- OpenAL32/alSource.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index e8d04bc2..64a8c1e1 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -296,7 +296,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? Resample_copy32_C : voice->Resampler); - Counter = (voice->Flags&VOICE_IS_MOVING) ? SamplesToDo : 0; + Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; firstpass = true; OutPos = 0; @@ -663,7 +663,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } } while(isplaying && OutPos < SamplesToDo); - voice->Flags |= VOICE_IS_MOVING; + voice->Flags |= VOICE_IS_FADING; /* Update source info */ ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c6706bad..76b88a3f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -221,8 +221,8 @@ struct ALvoiceProps { } Send[]; }; -/* If not 'moving', gain targets are used directly without fading. */ -#define VOICE_IS_MOVING (1<<0) +/* If not 'fading', gain targets are used directly without fading. */ +#define VOICE_IS_FADING (1<<0) #define VOICE_IS_HRTF (1<<1) #define VOICE_HAS_NFC (1<<2) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 3720ce49..a1ba0ebc 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2438,7 +2438,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { ALbufferlistitem *BufferList; ALbuffer *buffer = NULL; - bool start_moving = false; + bool start_fading = false; ALsizei s; source = LookupSource(context, sources[i]); @@ -2481,11 +2481,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) case AL_PAUSED: assert(voice != NULL); /* A source that's paused simply resumes. Clear its mixing - * parameters and mark it as 'moving' so it fades in from + * parameters and mark it as 'fading' so it fades in from * silence. */ voice->Step = 0; - voice->Flags |= VOICE_IS_MOVING; + voice->Flags |= VOICE_IS_FADING; memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])* voice->NumChannels); for(s = 0;s < device->NumAuxSends;s++) @@ -2531,7 +2531,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(source->OffsetType != AL_NONE) { ApplyOffset(source, voice); - start_moving = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || + start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; } @@ -2547,7 +2547,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) */ voice->Step = 0; - voice->Flags = start_moving ? VOICE_IS_MOVING : 0; + voice->Flags = start_fading ? VOICE_IS_FADING : 0; memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); for(s = 0;s < device->NumAuxSends;s++) memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels); -- cgit v1.2.3 From 1e5334176eb2bd9bae367218570a5fd24597f827 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 04:25:08 -0700 Subject: Rename VOICE_IS_HRTF to VOICE_HAS_HRTF --- Alc/ALu.c | 8 ++++---- Alc/mixer.c | 2 +- OpenAL32/Include/alu.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 01e6bbfa..06c21506 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -522,7 +522,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p break; } - voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC); + voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(isbformat) { ALfloat N[3], V[3], U[3]; @@ -682,7 +682,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p } } - voice->Flags |= VOICE_IS_HRTF; + voice->Flags |= VOICE_HAS_HRTF; } else { @@ -1098,7 +1098,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop BsincPrepare(voice->Step, &voice->ResampleState.bsinc); voice->Resampler = SelectResampler(props->Resampler); - voice->Flags &= ~(VOICE_IS_HRTF | VOICE_HAS_NFC); + voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render to the @@ -1151,7 +1151,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop voice->Send[i].Params[0].Gains.Target[j] = 0.0f; } - voice->Flags |= VOICE_IS_HRTF; + voice->Flags |= VOICE_HAS_HRTF; } else { diff --git a/Alc/mixer.c b/Alc/mixer.c index 64a8c1e1..b632d6ca 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -445,7 +445,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei &parms->LowPass, &parms->HighPass, Device->FilteredData, ResampledData, DstBufferSize, parms->FilterType ); - if(!(voice->Flags&VOICE_IS_HRTF)) + if(!(voice->Flags&VOICE_HAS_HRTF)) { if(!Counter) memcpy(parms->Gains.Current, parms->Gains.Target, diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 76b88a3f..3cb94270 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -223,7 +223,7 @@ struct ALvoiceProps { /* If not 'fading', gain targets are used directly without fading. */ #define VOICE_IS_FADING (1<<0) -#define VOICE_IS_HRTF (1<<1) +#define VOICE_HAS_HRTF (1<<1) #define VOICE_HAS_NFC (1<<2) typedef struct ALvoice { -- cgit v1.2.3 From 53c3d48fe0714f3b7a6cf4d12b28ed611277224d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 04:54:59 -0700 Subject: Change some ALuint parameters to ALsizei --- Alc/effects/chorus.c | 30 +++++++++++++++--------------- Alc/effects/compressor.c | 10 +++++----- Alc/effects/dedicated.c | 6 +++--- Alc/effects/distortion.c | 11 +++++------ Alc/effects/echo.c | 6 +++--- Alc/effects/equalizer.c | 10 +++++----- Alc/effects/flanger.c | 32 ++++++++++++++++---------------- Alc/effects/modulator.c | 32 ++++++++++++++++---------------- Alc/effects/null.c | 4 ++-- Alc/effects/reverb.c | 8 ++++---- OpenAL32/Include/alAuxEffectSlot.h | 4 ++-- 11 files changed, 76 insertions(+), 77 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index a44f9262..df8721b3 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -39,9 +39,9 @@ typedef struct ALchorusState { DERIVE_FROM_TYPE(ALeffectState); ALfloat *SampleBuffer[2]; - ALuint BufferLength; - ALuint offset; - ALuint lfo_range; + ALsizei BufferLength; + ALsizei offset; + ALsizei lfo_range; ALfloat lfo_scale; ALint lfo_disp; @@ -58,7 +58,7 @@ typedef struct ALchorusState { static ALvoid ALchorusState_Destruct(ALchorusState *state); static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device); static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALchorusState) DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState); @@ -88,8 +88,8 @@ static ALvoid ALchorusState_Destruct(ALchorusState *state) static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) { - ALuint maxlen; - ALuint it; + ALsizei maxlen; + ALsizei it; maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); @@ -152,7 +152,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device else { /* Calculate LFO coefficient */ - state->lfo_range = fastf2u(frequency/rate + 0.5f); + state->lfo_range = fastf2i(frequency/rate + 0.5f); switch(state->waveform) { case CWF_Triangle: @@ -197,15 +197,15 @@ static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset } #define DECL_TEMPLATE(Func) \ -static void Process##Func(ALchorusState *state, const ALuint SamplesToDo, \ +static void Process##Func(ALchorusState *state, const ALsizei SamplesToDo, \ const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \ { \ - const ALuint bufmask = state->BufferLength-1; \ + const ALsizei bufmask = state->BufferLength-1; \ ALfloat *restrict leftbuf = state->SampleBuffer[0]; \ ALfloat *restrict rightbuf = state->SampleBuffer[1]; \ - ALuint offset = state->offset; \ + ALsizei offset = state->offset; \ const ALfloat feedback = state->feedback; \ - ALuint it; \ + ALsizei it; \ \ for(it = 0;it < SamplesToDo;it++) \ { \ @@ -228,15 +228,15 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALuint it, kt; - ALuint base; + ALsizei it, kt; + ALsizei base; for(base = 0;base < SamplesToDo;) { ALfloat temps[128][2]; - ALuint td = minu(128, SamplesToDo-base); + ALsizei td = mini(128, SamplesToDo-base); switch(state->waveform) { diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index ab0a4216..25c7a3dc 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -43,7 +43,7 @@ typedef struct ALcompressorState { static ALvoid ALcompressorState_Destruct(ALcompressorState *state); static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device); static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALcompressorState) DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState); @@ -89,15 +89,15 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice slot->Params.Gain, state->Gain[i]); } -static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALuint i, j, k; - ALuint base; + ALsizei i, j, k; + ALsizei base; for(base = 0;base < SamplesToDo;) { ALfloat temps[64][4]; - ALuint td = minu(64, SamplesToDo-base); + ALsizei td = mini(64, SamplesToDo-base); /* Load samples into the temp buffer first. */ for(j = 0;j < 4;j++) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 93c7416e..52d0ec6d 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -38,7 +38,7 @@ typedef struct ALdedicatedState { static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device); static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState) DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); @@ -107,9 +107,9 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice * } } -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALuint i, c; + ALsizei i, c; SamplesIn = ASSUME_ALIGNED(SamplesIn, 16); SamplesOut = ASSUME_ALIGNED(SamplesOut, 16); diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 84063e84..4619894d 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -46,7 +46,7 @@ typedef struct ALdistortionState { static ALvoid ALdistortionState_Destruct(ALdistortionState *state); static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device); static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALdistortionState) DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState); @@ -106,17 +106,16 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain); } -static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALfloat fc = state->edge_coeff; - ALuint base; - ALuint it; - ALuint kt; + ALsizei it, kt; + ALsizei base; for(base = 0;base < SamplesToDo;) { float buffer[2][64 * 4]; - ALuint td = minu(64, SamplesToDo-base); + ALsizei td = mini(64, SamplesToDo-base); /* Perform 4x oversampling to avoid aliasing. Oversampling greatly * improves distortion quality and allows to implement lowpass and diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 1c37752f..c0b1bf63 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -53,7 +53,7 @@ typedef struct ALechoState { static ALvoid ALechoState_Destruct(ALechoState *state); static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device); static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALechoState) DEFINE_ALEFFECTSTATE_VTABLE(ALechoState); @@ -142,14 +142,14 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]); } -static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { const ALsizei mask = state->BufferLength-1; const ALsizei tap1 = state->Tap[0].delay; const ALsizei tap2 = state->Tap[1].delay; ALsizei offset = state->Offset; ALfloat x[2], y[2], in, out; - ALuint base, k; + ALsizei base, k; ALsizei i; x[0] = state->Filter.x[0]; diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 36683d79..5e6a2a9a 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -90,7 +90,7 @@ typedef struct ALequalizerState { static ALvoid ALequalizerState_Destruct(ALequalizerState *state); static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device); static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALequalizerState) DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); @@ -200,15 +200,15 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * } } -static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer; - ALuint it, kt, ft; - ALuint base; + ALsizei it, kt, ft; + ALsizei base; for(base = 0;base < SamplesToDo;) { - ALuint td = minu(MAX_UPDATE_SAMPLES, SamplesToDo-base); + ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td); diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 2a5d230c..346478e4 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -39,9 +39,9 @@ typedef struct ALflangerState { DERIVE_FROM_TYPE(ALeffectState); ALfloat *SampleBuffer[2]; - ALuint BufferLength; - ALuint offset; - ALuint lfo_range; + ALsizei BufferLength; + ALsizei offset; + ALsizei lfo_range; ALfloat lfo_scale; ALint lfo_disp; @@ -58,7 +58,7 @@ typedef struct ALflangerState { static ALvoid ALflangerState_Destruct(ALflangerState *state); static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device); static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALflangerState) DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); @@ -88,10 +88,10 @@ static ALvoid ALflangerState_Destruct(ALflangerState *state) static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device) { - ALuint maxlen; - ALuint it; + ALsizei maxlen; + ALsizei it; - maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1; + maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) @@ -152,7 +152,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi else { /* Calculate LFO coefficient */ - state->lfo_range = fastf2u(frequency/rate + 0.5f); + state->lfo_range = fastf2i(frequency/rate + 0.5f); switch(state->waveform) { case FWF_Triangle: @@ -197,15 +197,15 @@ static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset } #define DECL_TEMPLATE(Func) \ -static void Process##Func(ALflangerState *state, const ALuint SamplesToDo, \ +static void Process##Func(ALflangerState *state, const ALsizei SamplesToDo, \ const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \ { \ - const ALuint bufmask = state->BufferLength-1; \ + const ALsizei bufmask = state->BufferLength-1; \ ALfloat *restrict leftbuf = state->SampleBuffer[0]; \ ALfloat *restrict rightbuf = state->SampleBuffer[1]; \ - ALuint offset = state->offset; \ + ALsizei offset = state->offset; \ const ALfloat feedback = state->feedback; \ - ALuint it; \ + ALsizei it; \ \ for(it = 0;it < SamplesToDo;it++) \ { \ @@ -228,15 +228,15 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALuint it, kt; - ALuint base; + ALsizei it, kt; + ALsizei base; for(base = 0;base < SamplesToDo;) { ALfloat temps[128][2]; - ALuint td = minu(128, SamplesToDo-base); + ALsizei td = mini(128, SamplesToDo-base); switch(state->waveform) { diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 6d096048..e9026a62 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -33,10 +33,10 @@ typedef struct ALmodulatorState { DERIVE_FROM_TYPE(ALeffectState); - void (*Process)(ALfloat*, const ALfloat*, ALuint, const ALuint, ALuint); + void (*Process)(ALfloat*, const ALfloat*, ALsizei, const ALsizei, ALsizei); - ALuint index; - ALuint step; + ALsizei index; + ALsizei step; ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; @@ -46,7 +46,7 @@ typedef struct ALmodulatorState { static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device); static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState) DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); @@ -56,26 +56,26 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); #define WAVEFORM_FRACONE (1<> (WAVEFORM_FRACBITS - 1)) & 1); } #define DECL_TEMPLATE(func) \ static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\ - ALuint index, const ALuint step, ALuint todo) \ + ALsizei index, const ALsizei step, ALsizei todo) \ { \ - ALuint i; \ + ALsizei i; \ for(i = 0;i < todo;i++) \ { \ index += step; \ @@ -118,7 +118,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props) { ALfloat cw, a; - ALuint i; + ALsizei i; if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Process = ModulateSin; @@ -151,17 +151,17 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice * Slot->Params.Gain, state->Gain[i]); } -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALuint step = state->step; - ALuint index = state->index; - ALuint base; + const ALsizei step = state->step; + ALsizei index = state->index; + ALsizei base; for(base = 0;base < SamplesToDo;) { ALfloat temps[2][128]; - ALuint td = minu(128, SamplesToDo-base); - ALuint i, j, k; + ALsizei td = mini(128, SamplesToDo-base); + ALsizei i, j, k; for(j = 0;j < MAX_EFFECT_CHANNELS;j++) { diff --git a/Alc/effects/null.c b/Alc/effects/null.c index bff00b56..3812d8fc 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -17,7 +17,7 @@ typedef struct ALnullState { static ALvoid ALnullState_Destruct(ALnullState *state); static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALnullState_process(ALnullState *state, ALuint samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALuint NumChannels); +static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALsizei NumChannels); static void *ALnullState_New(size_t size); static void ALnullState_Delete(void *ptr); @@ -64,7 +64,7 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UN * 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 ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels)) +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(NumChannels)) { } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 6e5144fa..972bb717 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -186,7 +186,7 @@ typedef struct ALreverbState { static ALvoid ALreverbState_Destruct(ALreverbState *State); static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels); +static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); DECLARE_DEFAULT_ALLOCATORS(ALreverbState) DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); @@ -1887,7 +1887,7 @@ static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fad return fade; } -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) +static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ProcMethodType ReverbProc = State->IsEax ? EAXVerbPass : VerbPass; ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; @@ -1895,12 +1895,12 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, co ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; ALsizei fadeCount = State->FadeCount; ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; - ALuint base, c; + ALsizei base, c; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - ALsizei todo = minu(SamplesToDo-base, MAX_UPDATE_SAMPLES); + ALsizei todo = mini(SamplesToDo-base, MAX_UPDATE_SAMPLES); /* If cross-fading, don't do more samples than there are to fade. */ if(FADE_SAMPLES-fadeCount > 0) todo = mini(todo, FADE_SAMPLES-fadeCount); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 7f95dc91..4eb340a4 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -30,7 +30,7 @@ struct ALeffectStateVtable { ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props); - void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); + void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels); void (*const Delete)(void *ptr); }; @@ -39,7 +39,7 @@ struct ALeffectStateVtable { DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \ -DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ +DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ \ -- cgit v1.2.3 From 66f964078788fdfd5dfb32750bf8ab1e9075140f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 07:34:28 -0700 Subject: Remove a duplicate check --- Alc/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index b632d6ca..a7adf9b6 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -509,7 +509,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei parms->Hrtf.Old = parms->Hrtf.Target; parms->Hrtf.Old.Gain = 0.0f; } - else if(firstpass && parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD) + else if(firstpass) { HrtfState backupstate = parms->Hrtf.State; ALfloat gain; -- cgit v1.2.3 From 4e5c4b8e01060bb34c58480895e70a0529d8a55e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 May 2017 15:55:58 -0700 Subject: Add a slight bit of attenuation to the reverb output --- Alc/effects/reverb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 972bb717..820ab70a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1412,8 +1412,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, State); - /* Update early and late 3D panning. */ - gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; + /* Update early and late 3D panning. Attenuate the early and late stages + * both by 0.7071 (-3dB) to better balance the mixture. + */ + gain = sqrtf(0.5f) * props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, -- cgit v1.2.3 From 444e9563b357b4e2af0d428afac9f87596aba9a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 May 2017 03:29:21 -0700 Subject: Add a mixing function to blend HRIRs This is a bit more efficient than calling the normal HRTF mixing function twice, and helps solve the problem of the values generated from convolution not being consistent with the new HRIR. --- Alc/mixer.c | 40 +++++++++++++++++----------------- Alc/mixer_c.c | 1 + Alc/mixer_defs.h | 15 +++++++++++++ Alc/mixer_inc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++------ Alc/mixer_neon.c | 1 + Alc/mixer_sse.c | 1 + OpenAL32/Include/alu.h | 5 +++++ 7 files changed, 95 insertions(+), 27 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index a7adf9b6..6eaf4caf 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -53,6 +53,7 @@ enum Resampler ResamplerDefault = LinearResampler; static MixerFunc MixSamples = Mix_C; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; +HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; MixerFunc SelectMixer(void) { @@ -90,10 +91,22 @@ static inline HrtfMixerFunc SelectHrtfMixer(void) if((CPUCapFlags&CPU_CAP_SSE)) return MixHrtf_SSE; #endif - return MixHrtf_C; } +static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtfBlend_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtfBlend_SSE; +#endif + return MixHrtfBlend_C; +} + ResamplerFunc SelectResampler(enum Resampler resampler) { switch(resampler) @@ -174,6 +187,7 @@ void aluInitMixer(void) } } + MixHrtfBlendSamples = SelectHrtfBlendMixer(); MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); } @@ -511,25 +525,10 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei } else if(firstpass) { - HrtfState backupstate = parms->Hrtf.State; ALfloat gain; /* Fade between the coefficients over 64 samples. */ - fademix = mini(DstBufferSize, 64); - - /* The old coefficients need to fade to silence - * completely since they'll be replaced after this mix. - */ - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs); - hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = -hrtfparams.Gain / (ALfloat)fademix; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &backupstate, fademix - ); + fademix = mini(DstBufferSize, 64); /* The new coefficients need to fade in completely * since they're replacing the old ones. To keep the @@ -544,10 +543,11 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; hrtfparams.GainStep = gain / (ALfloat)fademix; - MixHrtfSamples( + + MixHrtfBlendSamples( voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, fademix + samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, + &hrtfparams, &parms->Hrtf.State, fademix ); /* Update the old parameters with the result. */ parms->Hrtf.Old = parms->Hrtf.Target; diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index f0db2ebc..87f2fe90 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -146,6 +146,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_C +#define MixHrtfBlend MixHrtfBlend_C #define MixDirectHrtf MixDirectHrtf_C #include "mixer_inc.c" #undef MixHrtf diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h index dce748c5..462d6179 100644 --- a/Alc/mixer_defs.h +++ b/Alc/mixer_defs.h @@ -24,6 +24,11 @@ void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], @@ -40,6 +45,11 @@ void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], @@ -89,6 +99,11 @@ void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, struct MixHrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c index 16c3a61e..3c9d4dc5 100644 --- a/Alc/mixer_inc.c +++ b/Alc/mixer_inc.c @@ -32,21 +32,66 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, for(i = 0;i < BufferSize;i++) { hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]*gain; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]*gain; + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + gain += gainstep; + Offset++; } hrtfparams->Gain = gain; } +void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); + const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; + ALfloat oldGain = oldparams->Gain; + ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); + const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; + ALfloat newGain = newparams->Gain; + ALfloat newGainStep = newparams->GainStep; + ALfloat left, right; + ALsizei i; + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + + left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; + right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); + + left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; + right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + oldGain += oldGainStep; + newGain += newGainStep; + Offset++; + } + newparams->Gain = newGain; +} + void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c index 65dd608c..51191783 100644 --- a/Alc/mixer_neon.c +++ b/Alc/mixer_neon.c @@ -221,6 +221,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_Neon +#define MixHrtfBlend MixHrtfBlend_Neon #define MixDirectHrtf MixDirectHrtf_Neon #include "mixer_inc.c" #undef MixHrtf diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c index d30ec982..68786573 100644 --- a/Alc/mixer_sse.c +++ b/Alc/mixer_sse.c @@ -124,6 +124,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], } #define MixHrtf MixHrtf_SSE +#define MixHrtfBlend MixHrtfBlend_SSE #define MixDirectHrtf MixDirectHrtf_SSE #include "mixer_inc.c" #undef MixHrtf diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3cb94270..168a754f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -301,6 +301,11 @@ typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict Right const ALfloat *data, ALsizei Offset, ALsizei OutPos, const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, ALsizei BufferSize); +typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, const ALfloat *data, ALsizei Offset, const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], -- cgit v1.2.3 From 732dee5375b2b2debf30ed81eb52c3cc058499fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 May 2017 03:34:44 -0700 Subject: Rename Zero-Order Hold to Nearest A bit of a misnomer now since "Nearest" implies rounding (i.e. when the sample offset is >= .5, it should pick the next sample being closer in time), but that adds unnecessary complications. --- OpenAL32/alState.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 231e2192..a7dc1006 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -48,7 +48,7 @@ static const ALchar alErrInvalidOp[] = "Invalid Operation"; static const ALchar alErrOutOfMemory[] = "Out of Memory"; /* Resampler strings */ -static const ALchar alPointResampler[] = "Zero-Order Hold (Point)"; +static const ALchar alPointResampler[] = "Nearest"; static const ALchar alLinearResampler[] = "Linear"; static const ALchar alSinc4Resampler[] = "4-Point Sinc"; static const ALchar alBSincResampler[] = "Band-limited Sinc (12/24)"; -- cgit v1.2.3 From ab1cca729f561d8c13f87e55548173ee9bb3f3fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 May 2017 04:33:38 -0700 Subject: Finalize AL_SOFT_source_resampler --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 13 ------------- include/AL/alext.h | 12 ++++++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index d5286f4f..40786a42 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -735,7 +735,7 @@ static const ALchar alExtList[] = "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length " - "AL_SOFTX_source_resampler"; + "AL_SOFT_source_resampler"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 32865cae..1ace123c 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -139,19 +139,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif #endif -#ifndef AL_SOFT_source_resampler -#define AL_SOFT_source_resampler -#define AL_NUM_RESAMPLERS_SOFT 0x1210 -#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 -#define AL_SOURCE_RESAMPLER_SOFT 0x1212 -#define AL_RESAMPLER_NAME_SOFT 0x1213 - -typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); -#ifdef AL_ALEXT_PROTOTYPES -AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); -#endif -#endif - #ifndef ALC_SOFT_output_limiter #define ALC_SOFT_output_limiter #define ALC_OUTPUT_LIMITER_SOFT 0x199A diff --git a/include/AL/alext.h b/include/AL/alext.h index 0090c804..50ad10ec 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -436,6 +436,18 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi #define AL_GAIN_LIMIT_SOFT 0x200E #endif +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From e0ae3c7cb6f8340cfd16aa56b98b9a7e147c58ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 May 2017 04:41:09 -0700 Subject: Update changelog --- ChangeLog | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a9652ff..f3bb5f5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,7 @@ openal-soft-1.18.0: - Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. - - Implemented the AL_SOFT_gain_clamp_ex extension. + Implemented the AL_EXT_STEREO_ANGLES, AL_EXT_SOURCE_RADIUS, + AL_SOFT_gain_clamp_ex, and AL_SOFT_source_resampler extensions. Implemented 3D processing for some effects. Currently implemented for Reverb, Compressor, Equalizer, and Ring Modulator. -- cgit v1.2.3 From 14b23c250268f01fbb5f0ed0ae8ff22c6a5c2810 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 May 2017 04:53:22 -0700 Subject: Print available resamplers in openal-info --- utils/openal-info.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/utils/openal-info.c b/utils/openal-info.c index 5fd8784b..617550f2 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -251,6 +251,38 @@ static void printALInfo(void) checkALErrors(); } +static void printResamplerInfo(void) +{ + LPALGETSTRINGISOFT alGetStringiSOFT; + ALint num_resamplers; + ALint def_resampler; + + if(!alIsExtensionPresent("AL_SOFT_source_resampler")) + { + printf("Resampler info not available\n"); + return; + } + + alGetStringiSOFT = alGetProcAddress("alGetStringiSOFT"); + + num_resamplers = alGetInteger(AL_NUM_RESAMPLERS_SOFT); + def_resampler = alGetInteger(AL_DEFAULT_RESAMPLER_SOFT); + + if(!num_resamplers) + printf("!!! No resamplers found !!!\n"); + else + { + ALint i; + printf("Available resamplers:\n"); + for(i = 0;i < num_resamplers;++i) + { + const ALchar *name = alGetStringiSOFT(AL_RESAMPLER_NAME_SOFT, i); + printf(" %s%s\n", name, (i==def_resampler)?" *":""); + } + } + checkALErrors(); +} + static void printEFXInfo(ALCdevice *device) { ALCint major, minor, sends; @@ -394,6 +426,7 @@ int main(int argc, char *argv[]) } printALInfo(); + printResamplerInfo(); printEFXInfo(device); alcMakeContextCurrent(NULL); -- cgit v1.2.3 From 23bf3d39594982a9cd5e66da1921e940f10b51f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2017 04:35:53 -0700 Subject: Calculate the multi-channel panning in a separate function --- Alc/ALu.c | 498 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 249 insertions(+), 249 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 06c21506..127852d1 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -349,137 +349,76 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) } -static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) -{ - static const struct ChanMap MonoMap[1] = { - { FrontCenter, 0.0f, 0.0f } - }, RearMap[2] = { - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } - }, QuadMap[4] = { - { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, - { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } - }, X51Map[6] = { - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } - }, X61Map[7] = { - { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } - }, X71Map[8] = { - { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, - { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, - { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, - { LFE, 0.0f, 0.0f }, - { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, - { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, - { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, - { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } - }; +static const struct ChanMap MonoMap[1] = { + { FrontCenter, 0.0f, 0.0f } +}, RearMap[2] = { + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } +}, QuadMap[4] = { + { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, + { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } +}, X51Map[6] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } +}, X61Map[7] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } +}, X71Map[8] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } +}; - const ALCdevice *Device = ALContext->Device; - const ALlistener *Listener = ALContext->Listener; - ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat HFScale, LFScale; - ALuint NumSends, Frequency; - ALboolean Relative; - const struct ChanMap *chans = NULL; +static void CalcPanningAndFilters(ALvoice *voice, + const ALfloat DryGain, const ALfloat DryGainHF, + const ALfloat DryGainLF, const ALfloat *WetGain, + const ALfloat *WetGainLF, const ALfloat *WetGainHF, + ALeffectslot **SendSlots, const ALbuffer *Buffer, + const struct ALvoiceProps *props, const ALlistener *Listener, + const ALCdevice *Device) +{ struct ChanMap StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } }; - ALuint num_channels = 0; - ALboolean DirectChannels; - ALboolean isbformat = AL_FALSE; - ALfloat Pitch; - ALuint i, j, c; - - /* Get device properties */ - NumSends = Device->NumAuxSends; - Frequency = Device->Frequency; - - /* Get listener properties */ - ListenerGain = Listener->Params.Gain; - - /* Get source properties */ - SourceVolume = props->Gain; - MinVolume = props->MinGain; - MaxVolume = props->MaxGain; - Pitch = props->Pitch; - Relative = props->HeadRelative; - DirectChannels = props->DirectChannels; - - /* Convert counter-clockwise to clockwise. */ - StereoMap[0].angle = -props->StereoPan[0]; - StereoMap[1].angle = -props->StereoPan[1]; - - voice->Direct.Buffer = Device->Dry.Buffer; - voice->Direct.Channels = Device->Dry.NumChannels; - for(i = 0;i < NumSends;i++) - { - SendSlots[i] = props->Send[i].Slot; - if(!SendSlots[i] && i == 0) - SendSlots[i] = Device->DefaultSlot; - if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) - { - SendSlots[i] = NULL; - voice->Send[i].Buffer = NULL; - voice->Send[i].Channels = 0; - } - else - { - voice->Send[i].Buffer = SendSlots[i]->WetBuffer; - voice->Send[i].Channels = SendSlots[i]->NumChannels; - } - } - - /* Calculate the stepping value */ - Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); - BsincPrepare(voice->Step, &voice->ResampleState.bsinc); - voice->Resampler = SelectResampler(props->Resampler); - - /* Calculate gains */ - DryGain = clampf(SourceVolume, MinVolume, MaxVolume); - DryGain *= props->Direct.Gain * ListenerGain; - DryGain = minf(DryGain, GAIN_MIX_MAX); - DryGainHF = props->Direct.GainHF; - DryGainLF = props->Direct.GainLF; - for(i = 0;i < NumSends;i++) - { - WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); - WetGain[i] *= props->Send[i].Gain * ListenerGain; - WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); - WetGainHF[i] = props->Send[i].GainHF; - WetGainLF[i] = props->Send[i].GainLF; - } + bool DirectChannels = props->DirectChannels; + const ALsizei NumSends = Device->NumAuxSends; + const ALuint Frequency = Device->Frequency; + const struct ChanMap *chans = NULL; + ALsizei num_channels = 0; + bool isbformat = false; + ALsizei c, i, j; - switch(ALBuffer->FmtChannels) + switch(Buffer->FmtChannels) { case FmtMono: chans = MonoMap; num_channels = 1; + /* Mono buffers are never played direct. */ + DirectChannels = false; break; case FmtStereo: + /* Convert counter-clockwise to clockwise. */ + StereoMap[0].angle = -props->StereoPan[0]; + StereoMap[1].angle = -props->StereoPan[1]; + chans = StereoMap; num_channels = 2; break; @@ -511,14 +450,14 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p case FmtBFormat2D: num_channels = 3; - isbformat = AL_TRUE; - DirectChannels = AL_FALSE; + isbformat = true; + DirectChannels = false; break; case FmtBFormat3D: num_channels = 4; - isbformat = AL_TRUE; - DirectChannels = AL_FALSE; + isbformat = true; + DirectChannels = false; break; } @@ -538,7 +477,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p V[1] = props->Orientation[1][1]; V[2] = props->Orientation[1][2]; aluNormalize(V); - if(!Relative) + if(!props->HeadRelative) { const aluMatrixf *lmatrix = &Listener->Params.Matrix; aluMatrixfFloat3(N, 0.0f, lmatrix); @@ -592,189 +531,250 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p } } } - else + else if(DirectChannels) { - ALfloat coeffs[MAX_AMBI_COEFFS]; + /* Skip the virtual channels and write inputs to the real output. */ + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; + for(c = 0;c < num_channels;c++) + { + int idx; + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Params[c].Gains.Target[j] = 0.0f; + if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) + voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } - if(DirectChannels) + /* Auxiliary sends still use normal panning since they mix to B-Format, + * which can't channel-match. + */ + for(c = 0;c < num_channels;c++) { - /* Skip the virtual channels and write inputs to the real output. */ - voice->Direct.Buffer = Device->RealOut.Buffer; - voice->Direct.Channels = Device->RealOut.NumChannels; - for(c = 0;c < num_channels;c++) - { - int idx; - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Params[c].Gains.Target[idx] = DryGain; - } + ALfloat coeffs[MAX_AMBI_COEFFS]; + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - /* Auxiliary sends still use normal panning since they mix to B-Format, which can't - * channel-match. */ - for(c = 0;c < num_channels;c++) + for(i = 0;i < NumSends;i++) { - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } - else if(Device->Render_Mode == HrtfRender) + } + else if(Device->Render_Mode == HrtfRender) + { + /* Full HRTF rendering. Skip the virtual channels and render each input + * channel to the real outputs. + */ + voice->Direct.Buffer = Device->RealOut.Buffer; + voice->Direct.Channels = Device->RealOut.NumChannels; + for(c = 0;c < num_channels;c++) { - /* Full HRTF rendering. Skip the virtual channels and render each - * input channel to the real outputs. - */ - voice->Direct.Buffer = Device->RealOut.Buffer; - voice->Direct.Channels = Device->RealOut.NumChannels; - for(c = 0;c < num_channels;c++) + ALfloat coeffs[MAX_AMBI_COEFFS]; + + if(chans[c].channel == LFE) { - if(chans[c].channel == LFE) + /* Skip LFE */ + voice->Direct.Params[c].Hrtf.Target.Delay[0] = 0; + voice->Direct.Params[c].Hrtf.Target.Delay[1] = 0; + for(i = 0;i < HRIR_LENGTH;i++) { - /* Skip LFE */ - voice->Direct.Params[c].Hrtf.Target.Delay[0] = 0; - voice->Direct.Params[c].Hrtf.Target.Delay[1] = 0; - for(i = 0;i < HRIR_LENGTH;i++) - { - voice->Direct.Params[c].Hrtf.Target.Coeffs[i][0] = 0.0f; - voice->Direct.Params[c].Hrtf.Target.Coeffs[i][1] = 0.0f; - } - - for(i = 0;i < NumSends;i++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } - - continue; + voice->Direct.Params[c].Hrtf.Target.Coeffs[i][0] = 0.0f; + voice->Direct.Params[c].Hrtf.Target.Coeffs[i][1] = 0.0f; } - /* Get the static HRIR coefficients and delays for this channel. */ - GetHrtfCoeffs(Device->HrtfHandle, - chans[c].elevation, chans[c].angle, 0.0f, - voice->Direct.Params[c].Hrtf.Target.Coeffs, - voice->Direct.Params[c].Hrtf.Target.Delay - ); - voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; - - /* Normal panning for auxiliary sends. */ - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - for(i = 0;i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } + + continue; } - voice->Flags |= VOICE_HAS_HRTF; + /* Get the static HRIR coefficients and delays for this channel. */ + GetHrtfCoeffs(Device->HrtfHandle, + chans[c].elevation, chans[c].angle, 0.0f, + voice->Direct.Params[c].Hrtf.Target.Coeffs, + voice->Direct.Params[c].Hrtf.Target.Delay + ); + voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; + + /* Normal panning for auxiliary sends. */ + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } } - else + + voice->Flags |= VOICE_HAS_HRTF; + } + else + { + /* Non-HRTF rendering. Use normal panning to the output. */ + for(c = 0;c < num_channels;c++) { - /* Non-HRTF rendering. Use normal panning to the output. */ - for(c = 0;c < num_channels;c++) + ALfloat coeffs[MAX_AMBI_COEFFS]; + + /* Special-case LFE */ + if(chans[c].channel == LFE) { - /* Special-case LFE */ - if(chans[c].channel == LFE) + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Params[c].Gains.Target[j] = 0.0f; + if(Device->Dry.Buffer == Device->RealOut.Buffer) { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - if(Device->Dry.Buffer == Device->RealOut.Buffer) - { - int idx; - if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Params[c].Gains.Target[idx] = DryGain; - } - - for(i = 0;i < NumSends;i++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - } - continue; + int idx; + if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) + voice->Direct.Params[c].Gains.Target[idx] = DryGain; } - if(Device->Render_Mode == StereoPair) - CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - else - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - ComputePanningGains(Device->Dry, - coeffs, DryGain, voice->Direct.Params[c].Gains.Target - ); - for(i = 0;i < NumSends;i++) { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Direct.Params[c].Gains.Target[j] = 0.0f; } + continue; + } + + if(Device->Render_Mode == StereoPair) + CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + else + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + ComputePanningGains(Device->Dry, + coeffs, DryGain, voice->Direct.Params[c].Gains.Target + ); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } } { - HFScale = props->Direct.HFReference / Frequency; - LFScale = props->Direct.LFReference / Frequency; - DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ - DryGainLF = maxf(DryGainLF, 0.0625f); + ALfloat hfScale = props->Direct.HFReference / Frequency; + ALfloat lfScale = props->Direct.LFReference / Frequency; + ALfloat gainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ + ALfloat gainLF = maxf(DryGainLF, 0.0625f); for(c = 0;c < num_channels;c++) { voice->Direct.Params[c].FilterType = AF_None; - if(DryGainHF != 1.0f) voice->Direct.Params[c].FilterType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; + if(gainHF != 1.0f) voice->Direct.Params[c].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[c].LowPass, ALfilterType_HighShelf, - DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 1.0f) + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); ALfilterState_setParams( &voice->Direct.Params[c].HighPass, ALfilterType_LowShelf, - DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 1.0f) + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); } } for(i = 0;i < NumSends;i++) { - HFScale = props->Send[i].HFReference / Frequency; - LFScale = props->Send[i].LFReference / Frequency; - WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); - WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); + ALfloat hfScale = props->Send[i].HFReference / Frequency; + ALfloat lfScale = props->Send[i].LFReference / Frequency; + ALfloat gainHF = maxf(WetGainHF[i], 0.0625f); + ALfloat gainLF = maxf(WetGainLF[i], 0.0625f); for(c = 0;c < num_channels;c++) { voice->Send[i].Params[c].FilterType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; + if(gainHF != 1.0f) voice->Send[i].Params[c].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[c].LowPass, ALfilterType_HighShelf, - WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 1.0f) + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); ALfilterState_setParams( &voice->Send[i].Params[c].HighPass, ALfilterType_LowShelf, - WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 1.0f) + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); } } } +static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) +{ + const ALCdevice *Device = ALContext->Device; + const ALlistener *Listener = ALContext->Listener; + ALfloat DryGain, DryGainHF, DryGainLF; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALfloat WetGainLF[MAX_SENDS]; + ALeffectslot *SendSlots[MAX_SENDS]; + ALfloat Pitch; + ALsizei i; + + voice->Direct.Buffer = Device->Dry.Buffer; + voice->Direct.Channels = Device->Dry.NumChannels; + for(i = 0;i < Device->NumAuxSends;i++) + { + SendSlots[i] = props->Send[i].Slot; + if(!SendSlots[i] && i == 0) + SendSlots[i] = Device->DefaultSlot; + if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL) + { + SendSlots[i] = NULL; + voice->Send[i].Buffer = NULL; + voice->Send[i].Channels = 0; + } + else + { + voice->Send[i].Buffer = SendSlots[i]->WetBuffer; + voice->Send[i].Channels = SendSlots[i]->NumChannels; + } + } + + /* Calculate the stepping value */ + Pitch = (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; + if(Pitch > (ALfloat)MAX_PITCH) + voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + BsincPrepare(voice->Step, &voice->ResampleState.bsinc); + voice->Resampler = SelectResampler(props->Resampler); + + /* Calculate gains */ + DryGain = clampf(props->Gain, props->MinGain, props->MaxGain); + DryGain *= props->Direct.Gain * Listener->Params.Gain; + DryGain = minf(DryGain, GAIN_MIX_MAX); + DryGainHF = props->Direct.GainHF; + DryGainLF = props->Direct.GainLF; + for(i = 0;i < Device->NumAuxSends;i++) + { + WetGain[i] = clampf(props->Gain, props->MinGain, props->MaxGain); + WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; + WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); + WetGainHF[i] = props->Send[i].GainHF; + WetGainLF[i] = props->Send[i].GainLF; + } + + CalcPanningAndFilters(voice, DryGain, DryGainHF, DryGainLF, WetGain, WetGainLF, WetGainHF, + SendSlots, ALBuffer, props, Listener, Device); +} + static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; -- cgit v1.2.3 From 7829ad8fc9802442759b80014a695d7425fdf6de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2017 11:09:45 -0700 Subject: Handle attenuated sources in CalcPanningAndFilters --- Alc/ALu.c | 819 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 442 insertions(+), 377 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 127852d1..e3160dab 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -385,13 +385,13 @@ static const struct ChanMap MonoMap[1] = { { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; -static void CalcPanningAndFilters(ALvoice *voice, - const ALfloat DryGain, const ALfloat DryGainHF, - const ALfloat DryGainLF, const ALfloat *WetGain, - const ALfloat *WetGainLF, const ALfloat *WetGainHF, - ALeffectslot **SendSlots, const ALbuffer *Buffer, - const struct ALvoiceProps *props, const ALlistener *Listener, - const ALCdevice *Device) +static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat *Dir, + const ALfloat Spread, const ALfloat DryGain, + const ALfloat DryGainHF, const ALfloat DryGainLF, + const ALfloat *WetGain, const ALfloat *WetGainLF, + const ALfloat *WetGainHF, ALeffectslot **SendSlots, + const ALbuffer *Buffer, const struct ALvoiceProps *props, + const ALlistener *Listener, const ALCdevice *Device) { struct ChanMap StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, @@ -464,78 +464,159 @@ static void CalcPanningAndFilters(ALvoice *voice, voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(isbformat) { - ALfloat N[3], V[3], U[3]; - aluMatrixf matrix; - ALfloat scale; - - /* AT then UP */ - N[0] = props->Orientation[0][0]; - N[1] = props->Orientation[0][1]; - N[2] = props->Orientation[0][2]; - aluNormalize(N); - V[0] = props->Orientation[1][0]; - V[1] = props->Orientation[1][1]; - V[2] = props->Orientation[1][2]; - aluNormalize(V); - if(!props->HeadRelative) - { - const aluMatrixf *lmatrix = &Listener->Params.Matrix; - aluMatrixfFloat3(N, 0.0f, lmatrix); - aluMatrixfFloat3(V, 0.0f, lmatrix); - } - /* Build and normalize right-vector */ - aluCrossproduct(N, V, U); - aluNormalize(U); - - /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). */ - scale = 1.732050808f; - aluMatrixfSet(&matrix, - 1.414213562f, 0.0f, 0.0f, 0.0f, - 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, - 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale, - 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale - ); + /* Special handling for B-Format sources. */ - voice->Direct.Buffer = Device->FOAOut.Buffer; - voice->Direct.Channels = Device->FOAOut.NumChannels; - for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, - voice->Direct.Params[c].Gains.Target); - if(Device->AvgSpeakerDist > 0.0f) + if(Distance > FLT_EPSILON) { - /* NOTE: The NFCtrlFilters were created with a w0 of 0, which is - * what we want for FOA input. So there's nothing to adjust. + /* Panning a B-Format sound toward some direction is easy. Just pan + * the first (W) channel as a normal mono sound and silence the + * others. */ - voice->Direct.ChannelsPerOrder[0] = 1; - voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); - voice->Direct.ChannelsPerOrder[2] = 0; - voice->Direct.ChannelsPerOrder[3] = 0; - voice->Flags |= VOICE_HAS_NFC; - } + ALfloat coeffs[MAX_AMBI_COEFFS]; - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) + if(Device->AvgSpeakerDist > 0.0f && Listener->Params.MetersPerUnit > 0.0f) { - for(c = 0;c < num_channels;c++) - ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, - matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target - ); + ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency); + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + /* Clamp w0 for really close distances, to prevent excessive + * bass. + */ + w0 = minf(w0, w1*4.0f); + + /* Only need to adjust the first channel of a B-Format source. */ + NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); + NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); + NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + if(Device->Render_Mode == StereoPair) + { + ALfloat ev = asinf(Dir[1]); + ALfloat az = atan2f(Dir[0], -Dir[2]); + CalcAnglePairwiseCoeffs(az, ev, Spread, coeffs); } else + CalcDirectionCoeffs(Dir, Spread, coeffs); + + /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ + ComputePanningGains(Device->Dry, coeffs, DryGain*1.414213562f, + voice->Direct.Params[0].Gains.Target); + for(c = 1;c < num_channels;c++) { - for(c = 0;c < num_channels;c++) + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Params[c].Gains.Target[j] = 0.0f; + } + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i]*1.414213562f, voice->Send[i].Params[0].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[0].Gains.Target[j] = 0.0f; + for(c = 1;c < num_channels;c++) + { for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } + } + } + else + { + /* Non-panned B-Format has its XYZ channels rotated according to + * the orientation. + */ + ALfloat N[3], V[3], U[3]; + aluMatrixf matrix; + ALfloat scale; + + if(Device->AvgSpeakerDist > 0.0f) + { + /* NOTE: The NFCtrlFilters were created with a w0 of 0, which + * is what we want for FOA input. The first channel may have + * been previously re-adjusted if panned, so reset it. + */ + NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], 0.0f); + NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], 0.0f); + NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], 0.0f); + + voice->Direct.ChannelsPerOrder[0] = 1; + voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); + for(i = 2;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[2] = 0; + voice->Flags |= VOICE_HAS_NFC; + } + + /* AT then UP */ + N[0] = props->Orientation[0][0]; + N[1] = props->Orientation[0][1]; + N[2] = props->Orientation[0][2]; + aluNormalize(N); + V[0] = props->Orientation[1][0]; + V[1] = props->Orientation[1][1]; + V[2] = props->Orientation[1][2]; + aluNormalize(V); + if(!props->HeadRelative) + { + const aluMatrixf *lmatrix = &Listener->Params.Matrix; + aluMatrixfFloat3(N, 0.0f, lmatrix); + aluMatrixfFloat3(V, 0.0f, lmatrix); + } + /* Build and normalize right-vector */ + aluCrossproduct(N, V, U); + aluNormalize(U); + + /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). */ + scale = 1.732050808f; + aluMatrixfSet(&matrix, + 1.414213562f, 0.0f, 0.0f, 0.0f, + 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, + 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale, + 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale + ); + + voice->Direct.Buffer = Device->FOAOut.Buffer; + voice->Direct.Channels = Device->FOAOut.NumChannels; + for(c = 0;c < num_channels;c++) + ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, + voice->Direct.Params[c].Gains.Target); + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + { + for(c = 0;c < num_channels;c++) + ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, + matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } + else + { + for(c = 0;c < num_channels;c++) + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } } } } else if(DirectChannels) { - /* Skip the virtual channels and write inputs to the real output. */ + /* Skip the virtual channels and write inputs to the real output with + * no explicit panning. + */ voice->Direct.Buffer = Device->RealOut.Buffer; voice->Direct.Channels = Device->RealOut.NumChannels; + for(c = 0;c < num_channels;c++) { int idx; @@ -545,8 +626,8 @@ static void CalcPanningAndFilters(ALvoice *voice, voice->Direct.Params[c].Gains.Target[idx] = DryGain; } - /* Auxiliary sends still use normal panning since they mix to B-Format, - * which can't channel-match. + /* Auxiliary sends still use normal channel panning since they mix to + * B-Format, which can't channel-match. */ for(c = 0;c < num_channels;c++) { @@ -568,106 +649,270 @@ static void CalcPanningAndFilters(ALvoice *voice, } else if(Device->Render_Mode == HrtfRender) { - /* Full HRTF rendering. Skip the virtual channels and render each input - * channel to the real outputs. + /* Full HRTF rendering. Skip the virtual channels and render to the + * real outputs. */ voice->Direct.Buffer = Device->RealOut.Buffer; voice->Direct.Channels = Device->RealOut.NumChannels; - for(c = 0;c < num_channels;c++) + + if(Distance > FLT_EPSILON) { ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat ev, az; - if(chans[c].channel == LFE) - { - /* Skip LFE */ - voice->Direct.Params[c].Hrtf.Target.Delay[0] = 0; - voice->Direct.Params[c].Hrtf.Target.Delay[1] = 0; - for(i = 0;i < HRIR_LENGTH;i++) - { - voice->Direct.Params[c].Hrtf.Target.Coeffs[i][0] = 0.0f; - voice->Direct.Params[c].Hrtf.Target.Coeffs[i][1] = 0.0f; - } + ev = asinf(Dir[1]); + az = atan2f(Dir[0], -Dir[2]); - for(i = 0;i < NumSends;i++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } + /* Get the HRIR coefficients and delays just once, for the given + * source direction. + */ + GetHrtfCoeffs(Device->HrtfHandle, ev, az, Spread, + voice->Direct.Params[0].Hrtf.Target.Coeffs, + voice->Direct.Params[0].Hrtf.Target.Delay); + voice->Direct.Params[0].Hrtf.Target.Gain = DryGain; - continue; + /* Remaining channels use the same results as the first. */ + for(c = 1;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + memset(&voice->Direct.Params[c].Hrtf.Target, 0, + sizeof(voice->Direct.Params[c].Hrtf.Target)); + else + voice->Direct.Params[c].Hrtf.Target = voice->Direct.Params[0].Hrtf.Target; } - /* Get the static HRIR coefficients and delays for this channel. */ - GetHrtfCoeffs(Device->HrtfHandle, - chans[c].elevation, chans[c].angle, 0.0f, - voice->Direct.Params[c].Hrtf.Target.Coeffs, - voice->Direct.Params[c].Hrtf.Target.Delay - ); - voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; - - /* Normal panning for auxiliary sends. */ - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); + /* Calculate the directional coefficients once, which apply to all + * input channels of the source sends. + */ + CalcDirectionCoeffs(Dir, Spread, coeffs); for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); + for(c = 0;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + else + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } else for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } + else + { + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + if(chans[c].channel == LFE) + { + /* Skip LFE */ + memset(&voice->Direct.Params[c].Hrtf.Target, 0, + sizeof(voice->Direct.Params[c].Hrtf.Target)); + for(i = 0;i < NumSends;i++) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } + continue; + } + + /* Get the HRIR coefficients and delays for this channel + * position. + */ + GetHrtfCoeffs(Device->HrtfHandle, + chans[c].elevation, chans[c].angle, Spread, + voice->Direct.Params[c].Hrtf.Target.Coeffs, + voice->Direct.Params[c].Hrtf.Target.Delay + ); + voice->Direct.Params[c].Hrtf.Target.Gain = DryGain; + + /* Normal panning for auxiliary sends. */ + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } + } + } voice->Flags |= VOICE_HAS_HRTF; } else { /* Non-HRTF rendering. Use normal panning to the output. */ - for(c = 0;c < num_channels;c++) + + if(Distance > FLT_EPSILON) { ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat w0 = 0.0f; - /* Special-case LFE */ - if(chans[c].channel == LFE) + /* Calculate NFC filter coefficient if needed. */ + if(Device->AvgSpeakerDist > 0.0f && Listener->Params.MetersPerUnit > 0.0f) { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - if(Device->Dry.Buffer == Device->RealOut.Buffer) + ALfloat mdist = Distance * Listener->Params.MetersPerUnit; + ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + w0 = SPEEDOFSOUNDMETRESPERSEC / + (mdist * (ALfloat)Device->Frequency); + /* Clamp w0 for really close distances, to prevent excessive + * bass. + */ + w0 = minf(w0, w1*4.0f); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + /* Calculate the directional coefficients once, which apply to all + * input channels. + */ + if(Device->Render_Mode == StereoPair) + { + ALfloat ev = asinf(Dir[1]); + ALfloat az = atan2f(Dir[0], -Dir[2]); + CalcAnglePairwiseCoeffs(az, ev, Spread, coeffs); + } + else + CalcDirectionCoeffs(Dir, Spread, coeffs); + + for(c = 0;c < num_channels;c++) + { + /* Adjust NFC filters if needed. */ + if((voice->Flags&VOICE_HAS_NFC)) { - int idx; - if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Params[c].Gains.Target[idx] = DryGain; + NfcFilterAdjust1(&voice->Direct.Params[c].NFCtrlFilter[0], w0); + NfcFilterAdjust2(&voice->Direct.Params[c].NFCtrlFilter[1], w0); + NfcFilterAdjust3(&voice->Direct.Params[c].NFCtrlFilter[2], w0); } - for(i = 0;i < NumSends;i++) + /* Special-case LFE */ + if(chans[c].channel == LFE) { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Params[c].Gains.Target[j] = 0.0f; + if(Device->Dry.Buffer == Device->RealOut.Buffer) + { + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } + continue; } - continue; - } - if(Device->Render_Mode == StereoPair) - CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - else - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs); - ComputePanningGains(Device->Dry, - coeffs, DryGain, voice->Direct.Params[c].Gains.Target - ); + ComputePanningGains(Device->Dry, + coeffs, DryGain, voice->Direct.Params[c].Gains.Target + ); + } for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target - ); + for(c = 0;c < num_channels;c++) + { + /* Skip LFE */ + if(chans[c].channel == LFE) + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + else + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + } else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + for(c = 0;c < num_channels;c++) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } + } + } + else + { + ALfloat w0 = 0.0f; + + if(Device->AvgSpeakerDist > 0.0f) + { + /* If the source distance is 0, set w0 to w1 to act as a pass- + * through. We still want to pass the signal through the + * filters so they keep an appropriate history, in case the + * source moves away from the listener. + */ + w0 = SPEEDOFSOUNDMETRESPERSEC / + (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + + for(i = 0;i < MAX_AMBI_ORDER+1;i++) + voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Flags |= VOICE_HAS_NFC; + } + + for(c = 0;c < num_channels;c++) + { + ALfloat coeffs[MAX_AMBI_COEFFS]; + + if((voice->Flags&VOICE_HAS_NFC)) + { + NfcFilterAdjust1(&voice->Direct.Params[c].NFCtrlFilter[0], w0); + NfcFilterAdjust2(&voice->Direct.Params[c].NFCtrlFilter[1], w0); + NfcFilterAdjust3(&voice->Direct.Params[c].NFCtrlFilter[2], w0); + } + + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Params[c].Gains.Target[j] = 0.0f; + if(Device->Dry.Buffer == Device->RealOut.Buffer) + { + int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; + } + + for(i = 0;i < NumSends;i++) + { + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } + continue; + } + + if(Device->Render_Mode == StereoPair) + CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + else + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + ComputePanningGains(Device->Dry, + coeffs, DryGain, voice->Direct.Params[c].Gains.Target + ); + + for(i = 0;i < NumSends;i++) + { + const ALeffectslot *Slot = SendSlots[i]; + if(Slot) + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, + coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ); + else + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + voice->Send[i].Params[c].Gains.Target[j] = 0.0f; + } } } } @@ -717,6 +962,7 @@ static void CalcPanningAndFilters(ALvoice *voice, static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { + static const ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; ALfloat DryGain, DryGainHF, DryGainLF; @@ -771,72 +1017,37 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p WetGainLF[i] = props->Send[i].GainLF; } - CalcPanningAndFilters(voice, DryGain, DryGainHF, DryGainLF, WetGain, WetGainLF, WetGainHF, - SendSlots, ALBuffer, props, Listener, Device); + CalcPanningAndFilters(voice, 0.0f, dir, 0.0f, DryGain, DryGainHF, DryGainLF, WetGain, + WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; + const ALsizei NumSends = Device->NumAuxSends; aluVector Position, Velocity, Direction, SourceToListener; - ALfloat InnerAngle,OuterAngle,Distance,ClampedDist; - ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; - ALfloat SourceVolume,ListenerGain; - ALfloat DopplerFactor, SpeedOfSound; - ALfloat AirAbsorptionFactor; + ALfloat Distance, ClampedDist; + ALfloat DopplerFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat Attenuation; ALfloat RoomAttenuation[MAX_SENDS]; - ALfloat MetersPerUnit; - ALfloat RoomRolloffBase; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; - ALfloat DryGain; - ALfloat DryGainHF; - ALfloat DryGainLF; - ALboolean DryGainHFAuto; + ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; - ALfloat HFScale, LFScale; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; + ALfloat dir[3]; + ALfloat spread; ALfloat Pitch; - ALuint Frequency; - ALint NumSends; - ALint i, j; - - /* Get context/device properties */ - DopplerFactor = Listener->Params.DopplerFactor; - SpeedOfSound = Listener->Params.SpeedOfSound; - NumSends = Device->NumAuxSends; - Frequency = Device->Frequency; - - /* Get listener properties */ - ListenerGain = Listener->Params.Gain; - MetersPerUnit = Listener->Params.MetersPerUnit; - - /* Get source properties */ - SourceVolume = props->Gain; - MinVolume = props->MinGain; - MaxVolume = props->MaxGain; - Pitch = props->Pitch; + ALint i; + + Pitch = 1.0f; aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - MinDist = props->RefDistance; - MaxDist = props->MaxDistance; - Rolloff = props->RollOffFactor; - DopplerFactor *= props->DopplerFactor; - InnerAngle = props->InnerAngle; - OuterAngle = props->OuterAngle; - AirAbsorptionFactor = props->AirAbsorptionFactor; - DryGainHFAuto = props->DryGainHFAuto; - WetGainAuto = props->WetGainAuto; - WetGainHFAuto = props->WetGainHFAuto; - RoomRolloffBase = props->RoomRolloffFactor; voice->Direct.Buffer = Device->Dry.Buffer; voice->Direct.Channels = Device->Dry.NumChannels; @@ -854,7 +1065,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } else if(SendSlots[i]->Params.AuxSendAuto) { - RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + RoomRolloffBase; + RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; DecayDistance[i] = SendSlots[i]->Params.DecayTime * SPEEDOFSOUNDMETRESPERSEC; RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF; @@ -863,7 +1074,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop { /* If the slot's auxiliary send auto is off, the data sent to the * effect slot is the same as the dry path, sans filter effects */ - RoomRolloff[i] = Rolloff; + RoomRolloff[i] = props->RollOffFactor; DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = AIRABSORBGAINHF; } @@ -915,81 +1126,83 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop props->DistanceModel : Listener->Params.DistanceModel) { case InverseDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case InverseDistance: - if(MinDist > 0.0f) + if(props->RefDistance > 0.0f) { - ALfloat dist = lerp(MinDist, ClampedDist, Rolloff); - if(dist > 0.0f) Attenuation = MinDist / dist; + ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RollOffFactor); + if(dist > 0.0f) Attenuation = props->RefDistance / dist; for(i = 0;i < NumSends;i++) { - dist = lerp(MinDist, ClampedDist, RoomRolloff[i]); - if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist; + dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); + if(dist > 0.0f) RoomAttenuation[i] = props->RefDistance / dist; } } break; case LinearDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case LinearDistance: - if(MaxDist != MinDist) + if(props->MaxDistance != props->RefDistance) { - Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist)); - Attenuation = maxf(Attenuation, 0.0f); + Attenuation = props->RollOffFactor * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + Attenuation = maxf(1.0f - Attenuation, 0.0f); for(i = 0;i < NumSends;i++) { - RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist)); - RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f); + RoomAttenuation[i] = RoomRolloff[i] * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + RoomAttenuation[i] = maxf(1.0f - RoomAttenuation[i], 0.0f); } } break; case ExponentDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) + ClampedDist = clampf(ClampedDist, props->RefDistance, props->MaxDistance); + if(props->MaxDistance < props->RefDistance) break; /*fall-through*/ case ExponentDistance: - if(ClampedDist > 0.0f && MinDist > 0.0f) + if(ClampedDist > 0.0f && props->RefDistance > 0.0f) { - Attenuation = powf(ClampedDist/MinDist, -Rolloff); + Attenuation = powf(ClampedDist/props->RefDistance, -props->RollOffFactor); for(i = 0;i < NumSends;i++) - RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]); + RoomAttenuation[i] = powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); } break; case DisableDistance: - ClampedDist = MinDist; + ClampedDist = props->RefDistance; break; } /* Source Gain + Attenuation */ - DryGain = SourceVolume * Attenuation; + DryGain = props->Gain * Attenuation; DryGainHF = 1.0f; DryGainLF = 1.0f; for(i = 0;i < NumSends;i++) { - WetGain[i] = SourceVolume * RoomAttenuation[i]; + WetGain[i] = props->Gain * RoomAttenuation[i]; WetGainHF[i] = 1.0f; WetGainLF[i] = 1.0f; } /* Distance-based air absorption */ - if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) + if(props->AirAbsorptionFactor > 0.0f && ClampedDist > props->RefDistance) { - ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit; - DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters); + ALfloat meters = (ClampedDist-props->RefDistance) * Listener->Params.MetersPerUnit; + DryGainHF *= powf(AIRABSORBGAINHF, props->AirAbsorptionFactor*meters); for(i = 0;i < NumSends;i++) - WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters); + WetGainHF[i] *= powf(RoomAirAbsorption[i], props->AirAbsorptionFactor*meters); } - if(WetGainAuto) + if(props->WetGainAuto) { ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f; @@ -1008,7 +1221,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Calculate directional soundcones */ - if(InnerAngle < 360.0f) + if(props->InnerAngle < 360.0f) { ALfloat ConeVolume; ALfloat ConeHF; @@ -1016,11 +1229,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat scale; Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; - if(Angle > InnerAngle) + if(Angle > props->InnerAngle) { - if(Angle < OuterAngle) + if(Angle < props->OuterAngle) { - scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); + scale = (Angle-props->InnerAngle) / (props->OuterAngle-props->InnerAngle); ConeVolume = lerp(1.0f, props->OuterGain, scale); ConeHF = lerp(1.0f, props->OuterGainHF, scale); } @@ -1030,22 +1243,22 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ConeHF = props->OuterGainHF; } DryGain *= ConeVolume; - if(DryGainHFAuto) + if(props->DryGainHFAuto) DryGainHF *= ConeHF; } /* Wet path uses the total area of the cone emitter (the room will * receive the same amount of sound regardless of its direction). */ - scale = (asinf(maxf((OuterAngle-InnerAngle)/360.0f, 0.0f)) / F_PI) + - (InnerAngle/360.0f); - if(WetGainAuto) + scale = (asinf(maxf((props->OuterAngle-props->InnerAngle)/360.0f, 0.0f)) / F_PI) + + (props->InnerAngle/360.0f); + if(props->WetGainAuto) { ConeVolume = lerp(1.0f, props->OuterGain, scale); for(i = 0;i < NumSends;i++) WetGain[i] *= ConeVolume; } - if(WetGainHFAuto) + if(props->WetGainHFAuto) { ConeHF = lerp(1.0f, props->OuterGainHF, scale); for(i = 0;i < NumSends;i++) @@ -1054,24 +1267,26 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Apply gain and frequency filters */ - DryGain = clampf(DryGain, MinVolume, MaxVolume); - DryGain *= props->Direct.Gain * ListenerGain; + DryGain = clampf(DryGain, props->MinGain, props->MaxGain); + DryGain *= props->Direct.Gain * Listener->Params.Gain; DryGain = minf(DryGain, GAIN_MIX_MAX); DryGainHF *= props->Direct.GainHF; DryGainLF *= props->Direct.GainLF; for(i = 0;i < NumSends;i++) { - WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); - WetGain[i] *= props->Send[i].Gain * ListenerGain; + WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); + WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); WetGainHF[i] *= props->Send[i].GainHF; WetGainLF[i] *= props->Send[i].GainLF; } /* Calculate velocity-based doppler effect */ + DopplerFactor = props->DopplerFactor * Listener->Params.DopplerFactor; if(DopplerFactor > 0.0f) { const aluVector *lvelocity = &Listener->Params.Velocity; + ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; ALfloat VSS, VLS; if(SpeedOfSound < 1.0f) @@ -1090,7 +1305,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop /* Calculate fixed-point stepping value, based on the pitch, buffer * frequency, and output frequency. */ - Pitch *= (ALfloat)ALBuffer->Frequency / Frequency; + Pitch *= (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<Step, &voice->ResampleState.bsinc); voice->Resampler = SelectResampler(props->Resampler); - voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); - if(Device->Render_Mode == HrtfRender) + if(Distance > FLT_EPSILON) { - /* Full HRTF rendering. Skip the virtual channels and render to the - * real outputs. + dir[0] = -SourceToListener.v[0]; + /* Clamp Y, in case rounding errors caused it to end up outside of + * -1...+1. */ - ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat radius = props->Radius; - ALfloat ev = 0.0f, az = 0.0f; - ALfloat spread = 0.0f; - - voice->Direct.Buffer = Device->RealOut.Buffer; - voice->Direct.Channels = Device->RealOut.NumChannels; - - if(Distance > FLT_EPSILON) - { - dir[0] = -SourceToListener.v[0]; - dir[1] = -SourceToListener.v[1]; - dir[2] = -SourceToListener.v[2] * ZScale; - - /* Calculate elevation and azimuth only when the source is not at - * the listener. This prevents +0 and -0 Z from producing - * inconsistent panning. Also, clamp Y in case FP precision errors - * cause it to land outside of -1..+1. */ - ev = asinf(clampf(dir[1], -1.0f, 1.0f)); - az = atan2f(dir[0], -dir[2]); - } - if(radius > Distance) - spread = F_TAU - Distance/radius*F_PI; - else if(Distance > FLT_EPSILON) - spread = asinf(radius / Distance) * 2.0f; - - /* Get the HRIR coefficients and delays. */ - GetHrtfCoeffs(Device->HrtfHandle, ev, az, spread, - voice->Direct.Params[0].Hrtf.Target.Coeffs, - voice->Direct.Params[0].Hrtf.Target.Delay); - voice->Direct.Params[0].Hrtf.Target.Gain = DryGain; - - CalcDirectionCoeffs(dir, spread, coeffs); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target - ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[0].Gains.Target[j] = 0.0f; - } - - voice->Flags |= VOICE_HAS_HRTF; + dir[1] = clampf(-SourceToListener.v[1], -1.0f, 1.0f); + dir[2] = -SourceToListener.v[2] * ZScale; } else { - /* Non-HRTF rendering. */ - ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat radius = props->Radius; - ALfloat spread = 0.0f; - - /* Get the localized direction, and compute panned gains. */ - if(Distance > FLT_EPSILON) - { - if(Device->AvgSpeakerDist > 0.0f && MetersPerUnit > 0.0f) - { - ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / - (Distance*MetersPerUnit * (ALfloat)Device->Frequency); - ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - /* Clamp w0 for really close distances, to prevent excessive - * bass. - */ - w0 = minf(w0, w1*4.0f); - - NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); - NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); - NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); - - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; - voice->Flags |= VOICE_HAS_NFC; - } - - dir[0] = -SourceToListener.v[0]; - dir[1] = -SourceToListener.v[1]; - dir[2] = -SourceToListener.v[2] * ZScale; - } - else if(Device->AvgSpeakerDist > 0.0f) - { - /* If the source distance is 0, set w0 to w1 to act as a pass- - * through. We still want to pass the signal through the filters so - * they keep an appropriate history, in case the source moves away - * from the listener. - */ - ALfloat w0 = SPEEDOFSOUNDMETRESPERSEC / - (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); - - NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); - NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); - NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); - - for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; - voice->Flags |= VOICE_HAS_NFC; - } - - if(radius > Distance) - spread = F_TAU - Distance/radius*F_PI; - else if(Distance > FLT_EPSILON) - spread = asinf(radius / Distance) * 2.0f; - - if(Device->Render_Mode == StereoPair) - { - ALfloat ev = asinf(clampf(dir[1], -1.0f, 1.0f)); - ALfloat az = atan2f(dir[0], -dir[2]); - CalcAnglePairwiseCoeffs(az, ev, radius, coeffs); - } - else - CalcDirectionCoeffs(dir, spread, coeffs); - ComputePanningGains(Device->Dry, - coeffs, DryGain, voice->Direct.Params[0].Gains.Target - ); - - for(i = 0;i < NumSends;i++) - { - const ALeffectslot *Slot = SendSlots[i]; - if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[0].Gains.Target - ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[0].Gains.Target[j] = 0.0f; - } + dir[0] = 0.0f; + dir[1] = 0.0f; + dir[2] = -1.0f; } + if(props->Radius > Distance) + spread = F_TAU - Distance/props->Radius*F_PI; + else if(Distance > FLT_EPSILON) + spread = asinf(props->Radius / Distance) * 2.0f; + else + spread = 0.0f; - { - HFScale = props->Direct.HFReference / Frequency; - LFScale = props->Direct.LFReference / Frequency; - DryGainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ - DryGainLF = maxf(DryGainLF, 0.0625f); - voice->Direct.Params[0].FilterType = AF_None; - if(DryGainHF != 1.0f) voice->Direct.Params[0].FilterType |= AF_LowPass; - if(DryGainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, - DryGainHF, HFScale, calc_rcpQ_from_slope(DryGainHF, 1.0f) - ); - ALfilterState_setParams( - &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, - DryGainLF, LFScale, calc_rcpQ_from_slope(DryGainLF, 1.0f) - ); - } - for(i = 0;i < NumSends;i++) - { - HFScale = props->Send[i].HFReference / Frequency; - LFScale = props->Send[i].LFReference / Frequency; - WetGainHF[i] = maxf(WetGainHF[i], 0.0625f); - WetGainLF[i] = maxf(WetGainLF[i], 0.0625f); - voice->Send[i].Params[0].FilterType = AF_None; - if(WetGainHF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_LowPass; - if(WetGainLF[i] != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, - WetGainHF[i], HFScale, calc_rcpQ_from_slope(WetGainHF[i], 1.0f) - ); - ALfilterState_setParams( - &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, - WetGainLF[i], LFScale, calc_rcpQ_from_slope(WetGainLF[i], 1.0f) - ); - } + CalcPanningAndFilters(voice, Distance, dir, spread, DryGain, DryGainHF, DryGainLF, WetGain, + WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean force) -- cgit v1.2.3 From b639bc99132015217ff173680e1a43f44fad2ce3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 May 2017 12:17:50 -0700 Subject: Add a property to force source spatialization on or off --- Alc/ALu.c | 8 +++++--- OpenAL32/Include/alSource.h | 1 + OpenAL32/Include/alu.h | 7 +++++++ OpenAL32/alSource.c | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e3160dab..9ce452e9 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1355,6 +1355,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc ATOMIC_REPLACE_HEAD(struct ALvoiceProps*, &voice->FreeList, props); } + props = voice->Props; BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); while(BufferListItem != NULL) @@ -1362,10 +1363,11 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, ALboolean forc const ALbuffer *buffer; if((buffer=BufferListItem->buffer) != NULL) { - if(buffer->FmtChannels == FmtMono) - CalcAttnSourceParams(voice, voice->Props, buffer, context); + if(props->SpatializeMode == SpatializeOn || + (props->SpatializeMode == SpatializeAuto && buffer->FmtChannels == FmtMono)) + CalcAttnSourceParams(voice, props, buffer, context); else - CalcNonAttnSourceParams(voice, voice->Props, buffer, context); + CalcNonAttnSourceParams(voice, props, buffer, context); break; } BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index f9cbc55b..7d2ff59a 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -45,6 +45,7 @@ typedef struct ALsource { enum DistanceModel DistanceModel; enum Resampler Resampler; ALboolean DirectChannels; + enum SpatializeMode Spatialize; ALboolean DryGainHFAuto; ALboolean WetGainAuto; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 168a754f..cccc9719 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -40,6 +40,12 @@ struct ALvoice; struct ALeffectslot; +enum SpatializeMode { + SpatializeOff, + SpatializeOn, + SpatializeAuto +}; + enum Resampler { PointResampler, LinearResampler, @@ -189,6 +195,7 @@ struct ALvoiceProps { enum DistanceModel DistanceModel; enum Resampler Resampler; ALboolean DirectChannels; + enum SpatializeMode SpatializeMode; ALboolean DryGainHFAuto; ALboolean WetGainAuto; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a1ba0ebc..9ef9a4eb 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2984,6 +2984,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->DistanceModel = DefaultDistanceModel; Source->Resampler = ResamplerDefault; Source->DirectChannels = AL_FALSE; + Source->Spatialize = SpatializeAuto; Source->StereoPan[0] = DEG2RAD( 30.0f); Source->StereoPan[1] = DEG2RAD(-30.0f); @@ -3093,6 +3094,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send props->DistanceModel = source->DistanceModel; props->Resampler = source->Resampler; props->DirectChannels = source->DirectChannels; + props->SpatializeMode = source->Spatialize; props->DryGainHFAuto = source->DryGainHFAuto; props->WetGainAuto = source->WetGainAuto; -- cgit v1.2.3 From 9c9ad2f60aead15416c8b582e20fadf847a13ce8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 02:41:34 -0700 Subject: Start an extension to change the source's spatialize property --- Alc/ALc.c | 5 ++++- OpenAL32/Include/alMain.h | 6 ++++++ OpenAL32/Include/alu.h | 6 +++--- OpenAL32/alSource.c | 22 ++++++++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 40786a42..f1319b16 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -701,6 +701,9 @@ static const struct { DECL(AL_DEFAULT_RESAMPLER_SOFT), DECL(AL_SOURCE_RESAMPLER_SOFT), DECL(AL_RESAMPLER_NAME_SOFT), + + DECL(AL_SOURCE_SPATIALIZE_SOFT), + DECL(AL_AUTO_SOFT), }; #undef DECL @@ -735,7 +738,7 @@ static const ALchar alExtList[] = "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length " - "AL_SOFT_source_resampler"; + "AL_SOFT_source_resampler AL_SOFTX_source_spatialize"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1ace123c..1b1b1909 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -144,6 +144,12 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #define ALC_OUTPUT_LIMITER_SOFT 0x199A #endif +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1213 +#define AL_AUTO_SOFT 0x0002 +#endif + #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index cccc9719..5cd233b9 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -41,9 +41,9 @@ struct ALeffectslot; enum SpatializeMode { - SpatializeOff, - SpatializeOn, - SpatializeAuto + SpatializeOff = AL_FALSE, + SpatializeOn = AL_TRUE, + SpatializeAuto = AL_AUTO_SOFT }; enum Resampler { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 9ef9a4eb..6030bd3c 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -119,6 +119,9 @@ typedef enum SourceProp { /* AL_SOFT_source_resampler */ srcResampler = AL_SOURCE_RESAMPLER_SOFT, + + /* AL_SOFT_source_spatialize */ + srcSpatialize = AL_SOURCE_SPATIALIZE_SOFT, } SourceProp; static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); @@ -218,6 +221,7 @@ static ALint FloatValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: return 1; case AL_STEREO_ANGLES: @@ -282,6 +286,7 @@ static ALint DoubleValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: return 1; case AL_SEC_OFFSET_LATENCY_SOFT: @@ -347,6 +352,7 @@ static ALint IntValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: return 1; case AL_POSITION: @@ -408,6 +414,7 @@ static ALint Int64ValsByProp(ALenum prop) case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: return 1; case AL_SAMPLE_OFFSET_LATENCY_SOFT: @@ -656,6 +663,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: ival = (ALint)values[0]; return SetSourceiv(Source, Context, prop, &ival); @@ -888,6 +896,13 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p DO_UPDATEPROPS(); return AL_TRUE; + case AL_SOURCE_SPATIALIZE_SOFT: + CHECKVAL(*values >= AL_FALSE && *values <= AL_AUTO_SOFT); + + Source->Spatialize = *values; + DO_UPDATEPROPS(); + return AL_TRUE; + case AL_AUXILIARY_SEND_FILTER: LockEffectSlotsRead(Context); @@ -1029,6 +1044,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_DIRECT_CHANNELS_SOFT: case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); ivals[0] = (ALint)*values; @@ -1269,6 +1285,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_LENGTH_SOFT: case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) *values = (ALdouble)ivals[0]; return err; @@ -1443,6 +1460,10 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values = Source->Resampler; return AL_TRUE; + case AL_SOURCE_SPATIALIZE_SOFT: + *values = Source->Spatialize; + return AL_TRUE; + /* 1x float/double */ case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: @@ -1602,6 +1623,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_DIRECT_CHANNELS_SOFT: case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: + case AL_SOURCE_SPATIALIZE_SOFT: if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) *values = ivals[0]; return err; -- cgit v1.2.3 From 17dfaca43d4f72c1691a66a5124247f121d967d8 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 5 May 2017 13:29:52 +0300 Subject: Implement cross-platform embedding of HRTF data --- Alc/hrtf.c | 77 +++-------------------------- Alc/hrtf_res.h | 5 -- Alc/hrtf_res.rc | 4 -- CMakeLists.txt | 67 +++++++++++-------------- utils/native-tools/CMakeLists.txt | 8 +++ utils/native-tools/bin2h.c | 100 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+), 116 deletions(-) delete mode 100644 Alc/hrtf_res.h delete mode 100644 Alc/hrtf_res.rc create mode 100644 utils/native-tools/CMakeLists.txt create mode 100644 utils/native-tools/bin2h.c diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 5d49eaf5..3017113d 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -869,99 +869,38 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam } -#ifndef ALSOFT_EMBED_HRTF_DATA #define IDR_DEFAULT_44100_MHR 1 #define IDR_DEFAULT_48000_MHR 2 -static const ALubyte *GetResource(int UNUSED(name), size_t *size) -{ - *size = 0; - return NULL; -} - -#else -#include "hrtf_res.h" - -#ifdef _WIN32 -static const ALubyte *GetResource(int name, size_t *size) -{ - HMODULE handle; - HGLOBAL res; - HRSRC rc; - - GetModuleHandleExW( - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCWSTR)GetResource, &handle - ); - rc = FindResourceW(handle, MAKEINTRESOURCEW(name), MAKEINTRESOURCEW(MHRTYPE)); - res = LoadResource(handle, rc); - - *size = SizeofResource(handle, rc); - return LockResource(res); -} - -#elif defined(__APPLE__) - -#include -#include -#include +#ifndef ALSOFT_EMBED_HRTF_DATA -static const ALubyte *GetResource(int name, size_t *size) +static const ALubyte *GetResource(int UNUSED(name), size_t *size) { -#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070) - /* NOTE: OSX 10.7 and up need to call getsectiondata(&_mh_dylib_header, ...). However, that - * call requires 10.7. - */ - if(name == IDR_DEFAULT_44100_MHR) - return getsectiondata(&_mh_dylib_header, "binary", "default_44100", size); - if(name == IDR_DEFAULT_48000_MHR) - return getsectiondata(&_mh_dylib_header, "binary", "default_48000", size); -#else - if(name == IDR_DEFAULT_44100_MHR) - return getsectdata("binary", "default_44100", size); - if(name == IDR_DEFAULT_48000_MHR) - return getsectdata("binary", "default_48000", size); -#endif *size = 0; return NULL; } #else -extern const ALubyte _binary_default_44100_mhr_start[] HIDDEN_DECL; -extern const ALubyte _binary_default_44100_mhr_end[] HIDDEN_DECL; -extern const ALubyte _binary_default_44100_mhr_size[] HIDDEN_DECL; - -extern const ALubyte _binary_default_48000_mhr_start[] HIDDEN_DECL; -extern const ALubyte _binary_default_48000_mhr_end[] HIDDEN_DECL; -extern const ALubyte _binary_default_48000_mhr_size[] HIDDEN_DECL; +#include "default-44100.mhr.h" +#include "default-48000.mhr.h" static const ALubyte *GetResource(int name, size_t *size) { if(name == IDR_DEFAULT_44100_MHR) { - /* Make sure all symbols are referenced, to ensure the compiler won't - * ignore the declarations and lose the visibility attribute used to - * hide them (would be nice if ld or objcopy could automatically mark - * them as hidden when generating them, but apparently they can't). - */ - const void *volatile ptr =_binary_default_44100_mhr_size; - (void)ptr; - *size = _binary_default_44100_mhr_end - _binary_default_44100_mhr_start; - return _binary_default_44100_mhr_start; + *size = sizeof(hrtf_default_44100); + return hrtf_default_44100; } if(name == IDR_DEFAULT_48000_MHR) { - const void *volatile ptr =_binary_default_48000_mhr_size; - (void)ptr; - *size = _binary_default_48000_mhr_end - _binary_default_48000_mhr_start; - return _binary_default_48000_mhr_start; + *size = sizeof(hrtf_default_48000); + return hrtf_default_48000; } *size = 0; return NULL; } #endif -#endif vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname) { diff --git a/Alc/hrtf_res.h b/Alc/hrtf_res.h deleted file mode 100644 index 2dc39cf1..00000000 --- a/Alc/hrtf_res.h +++ /dev/null @@ -1,5 +0,0 @@ - -#define MHRTYPE 256 - -#define IDR_DEFAULT_44100_MHR 1 -#define IDR_DEFAULT_48000_MHR 2 diff --git a/Alc/hrtf_res.rc b/Alc/hrtf_res.rc deleted file mode 100644 index a17b7447..00000000 --- a/Alc/hrtf_res.rc +++ /dev/null @@ -1,4 +0,0 @@ -#include "hrtf_res.h" - -IDR_DEFAULT_44100_MHR MHRTYPE "../hrtf/default-44100.mhr" -IDR_DEFAULT_48000_MHR MHRTYPE "../hrtf/default-48000.mhr" diff --git a/CMakeLists.txt b/CMakeLists.txt index efb06ebf..f15bcea2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1102,44 +1102,35 @@ SET(BACKENDS "${BACKENDS} Null") option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" OFF) if(ALSOFT_EMBED_HRTF_DATA) - if(WIN32) - set(ALC_OBJS ${ALC_OBJS} Alc/hrtf_res.rc) - elseif(APPLE) - macro(add_custom_binary FILENAME BIN_NAME) - set(outfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}) - set(stubsrcfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}.stub.c) - set(stubfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}.stub${CMAKE_C_OUTPUT_EXTENSION}) - add_custom_command(OUTPUT ${outfile} - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/hrtf/${FILENAME}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/hrtf" - COMMAND touch "${stubsrcfile}" - COMMAND "${CMAKE_C_COMPILER}" -o "${stubfile}" -c "${stubsrcfile}" - COMMAND "${CMAKE_LINKER}" -r -o "${outfile}" -sectcreate binary ${BIN_NAME} ${FILENAME} "${stubfile}" - COMMAND rm "${stubsrcfile}" "${stubfile}" - COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" - VERBATIM - ) - set(ALC_OBJS ${ALC_OBJS} ${outfile}) - endmacro() - add_custom_binary(default-44100.mhr "default_44100") - add_custom_binary(default-48000.mhr "default_48000") - else() - set(FILENAMES default-44100.mhr default-48000.mhr) - foreach(FILENAME ${FILENAMES}) - set(outfile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}) - add_custom_command(OUTPUT ${outfile} - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/hrtf/${FILENAME}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/hrtf" - COMMAND "${CMAKE_LINKER}" -r -b binary -o "${outfile}" ${FILENAME} - COMMAND "${CMAKE_OBJCOPY}" --rename-section .data=.rodata,alloc,load,readonly,data,contents "${outfile}" "${outfile}" - COMMENT "Generating ${FILENAME}${CMAKE_C_OUTPUT_EXTENSION}" - VERBATIM - ) - set(ALC_OBJS ${ALC_OBJS} ${outfile}) - endforeach() - unset(outfile) - unset(FILENAMES) - endif() + SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/utils/native-tools/") + SET(NATIVE_BIN_DIR "${OpenAL_BINARY_DIR}/native-tools/") + FILE(MAKE_DIRECTORY "${NATIVE_BIN_DIR}") + + SET(BIN2H_COMMAND "${NATIVE_BIN_DIR}bin2h") + ADD_CUSTOM_COMMAND(OUTPUT "${BIN2H_COMMAND}" + COMMAND ${CMAKE_COMMAND} "${NATIVE_SRC_DIR}" + COMMAND ${CMAKE_COMMAND} --build . --config "Release" + WORKING_DIRECTORY "${NATIVE_BIN_DIR}" + DEPENDS "${NATIVE_SRC_DIR}CMakeLists.txt" "${NATIVE_SRC_DIR}bin2h.c" + VERBATIM + ) + + MACRO(make_hrtf_header FILENAME VARNAME) + SET(infile "${OpenAL_SOURCE_DIR}/hrtf/${FILENAME}") + SET(outfile "${OpenAL_BINARY_DIR}/${FILENAME}.h") + + ADD_CUSTOM_COMMAND(OUTPUT "${outfile}" + COMMAND "${BIN2H_COMMAND}" "${infile}" "${outfile}" ${VARNAME} + DEPENDS "${BIN2H_COMMAND}" "${infile}" + COMMENT "Generating ${FILENAME}.h" + VERBATIM + ) + + SET(ALC_OBJS ${ALC_OBJS} "${outfile}") + ENDMACRO() + + make_hrtf_header(default-44100.mhr "hrtf_default_44100") + make_hrtf_header(default-48000.mhr "hrtf_default_48000") endif() diff --git a/utils/native-tools/CMakeLists.txt b/utils/native-tools/CMakeLists.txt new file mode 100644 index 00000000..4713dc56 --- /dev/null +++ b/utils/native-tools/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.0.2) +project(native-tools) +add_executable(bin2h bin2h.c) +# Enforce no dressing for executable names, so the main script can find it +set_target_properties(bin2h PROPERTIES OUTPUT_NAME bin2h) +# Avoid configuration-dependent subdirectories while building with Visual Studio +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}") +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}") diff --git a/utils/native-tools/bin2h.c b/utils/native-tools/bin2h.c new file mode 100644 index 00000000..d9f5eb9a --- /dev/null +++ b/utils/native-tools/bin2h.c @@ -0,0 +1,100 @@ + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + char* input_name; + FILE* input_file; + + char* output_name; + FILE* output_file; + + char* variable_name; + + if (4 != argc) + { + puts("Usage: bin2h [input] [output] [variable]"); + return EXIT_FAILURE; + } + + input_name = argv[1]; + output_name = argv[2]; + variable_name = argv[3]; + + input_file = fopen(input_name, "rb"); + + if (NULL == input_file) + { + printf("Could not open input file '%s': %s\n", input_name, strerror(errno)); + return EXIT_FAILURE; + } + + output_file = fopen(output_name, "w"); + + if (NULL == output_file) + { + printf("Could not open output file '%s': %s\n", output_name, strerror(errno)); + return EXIT_FAILURE; + } + + if (fprintf(output_file, "unsigned char %s[] = {", variable_name) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + while (0 == feof(input_file)) + { + unsigned char buffer[4096]; + size_t i, count = fread(buffer, 1, sizeof(buffer), input_file); + + if (sizeof(buffer) != count) + { + if (0 == feof(input_file) || 0 != ferror(input_file)) + { + printf("Could not read from input file '%s': %s\n", input_name, strerror(ferror(input_file))); + return EXIT_FAILURE; + } + } + + for (i = 0; i < count; ++i) + { + if ((i & 15) == 0) + { + if (fprintf(output_file, "\n ") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + } + + if (fprintf(output_file, "0x%2.2x, ", buffer[i]) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + } + } + + if (fprintf(output_file, "\n};\n") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + if (fclose(output_file) < 0) + { + printf("Could not close output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3 From 24bc8070c89c2c8ca74f1e80eda1ea4504064b8b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Fri, 5 May 2017 13:30:27 +0300 Subject: Enable embedding of HRTF data in CI config files --- .travis.yml | 3 +++ appveyor.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c24cd95b..e0a64c84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,7 @@ script: -DALSOFT_REQUIRE_PORTAUDIO=ON \ -DALSOFT_REQUIRE_PULSEAUDIO=ON \ -DALSOFT_REQUIRE_JACK=ON \ + -DALSOFT_EMBED_HRTF_DATA=YES \ . fi - > @@ -56,12 +57,14 @@ script: cmake \ -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r14/build/cmake/android.toolchain.cmake \ -DALSOFT_REQUIRE_OPENSL=ON \ + -DALSOFT_EMBED_HRTF_DATA=YES \ . fi - > if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then cmake \ -DALSOFT_REQUIRE_COREAUDIO=ON \ + -DALSOFT_EMBED_HRTF_DATA=YES \ . fi - make -j2 diff --git a/appveyor.yml b/appveyor.yml index 0d60cf61..9ea05d4e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,6 @@ install: build_script: - cd build - - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_MMDEVAPI=ON .. + - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_MMDEVAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. - cmake --build . --config %CFG% --clean-first -- cgit v1.2.3 From d82e3be8f753763aaea29fd273d02afb5d7cc1ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 03:10:58 -0700 Subject: Increase the HRTF transition to 128 samples --- Alc/mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 6eaf4caf..71714c70 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -527,8 +527,8 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei { ALfloat gain; - /* Fade between the coefficients over 64 samples. */ - fademix = mini(DstBufferSize, 64); + /* Fade between the coefficients over 128 samples. */ + fademix = mini(DstBufferSize, 128); /* The new coefficients need to fade in completely * since they're replacing the old ones. To keep the -- cgit v1.2.3 From db6f14748c0fce4d43d2e2c27a4c2847638297d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 03:19:50 -0700 Subject: Rename RollOff to Rolloff --- Alc/ALu.c | 8 ++++---- OpenAL32/Include/alSource.h | 2 +- OpenAL32/Include/alu.h | 2 +- OpenAL32/alSource.c | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9ce452e9..2817f982 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1074,7 +1074,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop { /* If the slot's auxiliary send auto is off, the data sent to the * effect slot is the same as the dry path, sans filter effects */ - RoomRolloff[i] = props->RollOffFactor; + RoomRolloff[i] = props->RolloffFactor; DecayDistance[i] = 0.0f; RoomAirAbsorption[i] = AIRABSORBGAINHF; } @@ -1133,7 +1133,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop case InverseDistance: if(props->RefDistance > 0.0f) { - ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RollOffFactor); + ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); if(dist > 0.0f) Attenuation = props->RefDistance / dist; for(i = 0;i < NumSends;i++) { @@ -1151,7 +1151,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop case LinearDistance: if(props->MaxDistance != props->RefDistance) { - Attenuation = props->RollOffFactor * (ClampedDist-props->RefDistance) / + Attenuation = props->RolloffFactor * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); Attenuation = maxf(1.0f - Attenuation, 0.0f); for(i = 0;i < NumSends;i++) @@ -1171,7 +1171,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop case ExponentDistance: if(ClampedDist > 0.0f && props->RefDistance > 0.0f) { - Attenuation = powf(ClampedDist/props->RefDistance, -props->RollOffFactor); + Attenuation = powf(ClampedDist/props->RefDistance, -props->RolloffFactor); for(i = 0;i < NumSends;i++) RoomAttenuation[i] = powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); } diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 7d2ff59a..03034ce8 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -35,7 +35,7 @@ typedef struct ALsource { ALfloat OuterAngle; ALfloat RefDistance; ALfloat MaxDistance; - ALfloat RollOffFactor; + ALfloat RolloffFactor; ALfloat Position[3]; ALfloat Velocity[3]; ALfloat Direction[3]; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 5cd233b9..8e2fe1e9 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -186,7 +186,7 @@ struct ALvoiceProps { ALfloat OuterAngle; ALfloat RefDistance; ALfloat MaxDistance; - ALfloat RollOffFactor; + ALfloat RolloffFactor; ALfloat Position[3]; ALfloat Velocity[3]; ALfloat Direction[3]; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 6030bd3c..46f23a75 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -504,7 +504,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_ROLLOFF_FACTOR: CHECKVAL(*values >= 0.0f); - Source->RollOffFactor = *values; + Source->RolloffFactor = *values; DO_UPDATEPROPS(); return AL_TRUE; @@ -1143,7 +1143,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_ROLLOFF_FACTOR: - *values = Source->RollOffFactor; + *values = Source->RolloffFactor; return AL_TRUE; case AL_REFERENCE_DISTANCE: @@ -2988,7 +2988,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->Orientation[1][2] = 0.0f; Source->RefDistance = 1.0f; Source->MaxDistance = FLT_MAX; - Source->RollOffFactor = 1.0f; + Source->RolloffFactor = 1.0f; Source->Gain = 1.0f; Source->MinGain = 0.0f; Source->MaxGain = 1.0f; @@ -3099,7 +3099,7 @@ static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_send props->OuterAngle = source->OuterAngle; props->RefDistance = source->RefDistance; props->MaxDistance = source->MaxDistance; - props->RollOffFactor = source->RollOffFactor; + props->RolloffFactor = source->RolloffFactor; for(i = 0;i < 3;i++) props->Position[i] = source->Position[i]; for(i = 0;i < 3;i++) -- cgit v1.2.3 From 47f843632fde72c53599740f0480b55ef666ac9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 04:59:07 -0700 Subject: Make the generated data array static const --- utils/native-tools/bin2h.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/native-tools/bin2h.c b/utils/native-tools/bin2h.c index d9f5eb9a..92f2b8a5 100644 --- a/utils/native-tools/bin2h.c +++ b/utils/native-tools/bin2h.c @@ -44,7 +44,7 @@ int main (int argc, char *argv[]) return EXIT_FAILURE; } - if (fprintf(output_file, "unsigned char %s[] = {", variable_name) < 0) + if (fprintf(output_file, "static const unsigned char %s[] = {", variable_name) < 0) { printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); return EXIT_FAILURE; -- cgit v1.2.3 From 64f0630fef7fadc8c30a0bd02cde37aa69ac64da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 05:03:50 -0700 Subject: Move native-tools to the root directory --- CMakeLists.txt | 2 +- native-tools/CMakeLists.txt | 8 +++ native-tools/bin2h.c | 100 ++++++++++++++++++++++++++++++++++++++ utils/native-tools/CMakeLists.txt | 8 --- utils/native-tools/bin2h.c | 100 -------------------------------------- 5 files changed, 109 insertions(+), 109 deletions(-) create mode 100644 native-tools/CMakeLists.txt create mode 100644 native-tools/bin2h.c delete mode 100644 utils/native-tools/CMakeLists.txt delete mode 100644 utils/native-tools/bin2h.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f15bcea2..66402624 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1102,7 +1102,7 @@ SET(BACKENDS "${BACKENDS} Null") option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" OFF) if(ALSOFT_EMBED_HRTF_DATA) - SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/utils/native-tools/") + SET(NATIVE_SRC_DIR "${OpenAL_SOURCE_DIR}/native-tools/") SET(NATIVE_BIN_DIR "${OpenAL_BINARY_DIR}/native-tools/") FILE(MAKE_DIRECTORY "${NATIVE_BIN_DIR}") diff --git a/native-tools/CMakeLists.txt b/native-tools/CMakeLists.txt new file mode 100644 index 00000000..4713dc56 --- /dev/null +++ b/native-tools/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.0.2) +project(native-tools) +add_executable(bin2h bin2h.c) +# Enforce no dressing for executable names, so the main script can find it +set_target_properties(bin2h PROPERTIES OUTPUT_NAME bin2h) +# Avoid configuration-dependent subdirectories while building with Visual Studio +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}") +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}") diff --git a/native-tools/bin2h.c b/native-tools/bin2h.c new file mode 100644 index 00000000..92f2b8a5 --- /dev/null +++ b/native-tools/bin2h.c @@ -0,0 +1,100 @@ + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + char* input_name; + FILE* input_file; + + char* output_name; + FILE* output_file; + + char* variable_name; + + if (4 != argc) + { + puts("Usage: bin2h [input] [output] [variable]"); + return EXIT_FAILURE; + } + + input_name = argv[1]; + output_name = argv[2]; + variable_name = argv[3]; + + input_file = fopen(input_name, "rb"); + + if (NULL == input_file) + { + printf("Could not open input file '%s': %s\n", input_name, strerror(errno)); + return EXIT_FAILURE; + } + + output_file = fopen(output_name, "w"); + + if (NULL == output_file) + { + printf("Could not open output file '%s': %s\n", output_name, strerror(errno)); + return EXIT_FAILURE; + } + + if (fprintf(output_file, "static const unsigned char %s[] = {", variable_name) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + while (0 == feof(input_file)) + { + unsigned char buffer[4096]; + size_t i, count = fread(buffer, 1, sizeof(buffer), input_file); + + if (sizeof(buffer) != count) + { + if (0 == feof(input_file) || 0 != ferror(input_file)) + { + printf("Could not read from input file '%s': %s\n", input_name, strerror(ferror(input_file))); + return EXIT_FAILURE; + } + } + + for (i = 0; i < count; ++i) + { + if ((i & 15) == 0) + { + if (fprintf(output_file, "\n ") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + } + + if (fprintf(output_file, "0x%2.2x, ", buffer[i]) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + } + } + + if (fprintf(output_file, "\n};\n") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + if (fclose(output_file) < 0) + { + printf("Could not close output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/utils/native-tools/CMakeLists.txt b/utils/native-tools/CMakeLists.txt deleted file mode 100644 index 4713dc56..00000000 --- a/utils/native-tools/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.0.2) -project(native-tools) -add_executable(bin2h bin2h.c) -# Enforce no dressing for executable names, so the main script can find it -set_target_properties(bin2h PROPERTIES OUTPUT_NAME bin2h) -# Avoid configuration-dependent subdirectories while building with Visual Studio -set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}") -set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}") diff --git a/utils/native-tools/bin2h.c b/utils/native-tools/bin2h.c deleted file mode 100644 index 92f2b8a5..00000000 --- a/utils/native-tools/bin2h.c +++ /dev/null @@ -1,100 +0,0 @@ - -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#include -#include -#include - -int main (int argc, char *argv[]) -{ - char* input_name; - FILE* input_file; - - char* output_name; - FILE* output_file; - - char* variable_name; - - if (4 != argc) - { - puts("Usage: bin2h [input] [output] [variable]"); - return EXIT_FAILURE; - } - - input_name = argv[1]; - output_name = argv[2]; - variable_name = argv[3]; - - input_file = fopen(input_name, "rb"); - - if (NULL == input_file) - { - printf("Could not open input file '%s': %s\n", input_name, strerror(errno)); - return EXIT_FAILURE; - } - - output_file = fopen(output_name, "w"); - - if (NULL == output_file) - { - printf("Could not open output file '%s': %s\n", output_name, strerror(errno)); - return EXIT_FAILURE; - } - - if (fprintf(output_file, "static const unsigned char %s[] = {", variable_name) < 0) - { - printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); - return EXIT_FAILURE; - } - - while (0 == feof(input_file)) - { - unsigned char buffer[4096]; - size_t i, count = fread(buffer, 1, sizeof(buffer), input_file); - - if (sizeof(buffer) != count) - { - if (0 == feof(input_file) || 0 != ferror(input_file)) - { - printf("Could not read from input file '%s': %s\n", input_name, strerror(ferror(input_file))); - return EXIT_FAILURE; - } - } - - for (i = 0; i < count; ++i) - { - if ((i & 15) == 0) - { - if (fprintf(output_file, "\n ") < 0) - { - printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); - return EXIT_FAILURE; - } - } - - if (fprintf(output_file, "0x%2.2x, ", buffer[i]) < 0) - { - printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); - return EXIT_FAILURE; - } - - } - } - - if (fprintf(output_file, "\n};\n") < 0) - { - printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); - return EXIT_FAILURE; - } - - if (fclose(output_file) < 0) - { - printf("Could not close output file '%s': %s\n", output_name, strerror(ferror(output_file))); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} -- cgit v1.2.3 From 074e4496ba1136b5c9590dff21b6c1181b2a5541 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 07:38:26 -0700 Subject: Calculate the output limiter gain using the RMS --- Alc/ALc.c | 26 +++++++++++---- Alc/ALu.c | 82 ++++++++++++++++++++++++++++++++++------------- OpenAL32/Include/alMain.h | 3 +- OpenAL32/Include/alu.h | 18 +++++++++++ 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f1319b16..fe8a0266 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1762,7 +1762,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { enum HrtfRequestMode hrtf_userreq = Hrtf_Default; enum HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = (device->LimiterGain > 0.0f); + ALCenum gainLimiter = !!device->Limiter; const ALsizei old_sends = device->NumAuxSends; ALsizei new_sends = device->NumAuxSends; enum DevFmtChannels oldChans; @@ -2216,7 +2216,16 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) gainLimiter = val; - device->LimiterGain = gainLimiter ? 1.0f : 0.0f; + if(gainLimiter) + { + if(!device->Limiter) + device->Limiter = alloc_limiter(); + } + else if(device->Limiter) + { + al_free(device->Limiter); + device->Limiter = NULL; + } /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. @@ -2418,6 +2427,9 @@ static ALCvoid FreeDevice(ALCdevice *device) ambiup_free(device->AmbiUp); device->AmbiUp = NULL; + al_free(device->Limiter); + device->Limiter = NULL; + al_free(device->ChannelDelay[0].Buffer); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -3167,7 +3179,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = device->HrtfStatus; values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -3275,7 +3287,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_OUTPUT_LIMITER_SOFT: - values[0] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; + values[0] = device->Limiter ? ALC_TRUE : ALC_FALSE; return 1; default: @@ -3383,7 +3395,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = device->HrtfStatus; values[i++] = ALC_OUTPUT_LIMITER_SOFT; - values[i++] = (device->LimiterGain > 0.0f) ? ALC_TRUE : ALC_FALSE; + values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; clock = V0(device->Backend,getClockLatency)(); values[i++] = ALC_DEVICE_CLOCK_SOFT; @@ -3826,7 +3838,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - device->LimiterGain = 1.0f; + device->Limiter = alloc_limiter(); device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); @@ -4355,7 +4367,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - device->LimiterGain = 1.0f; + device->Limiter = alloc_limiter(); device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); diff --git a/Alc/ALu.c b/Alc/ALu.c index 2817f982..f9defedd 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -100,6 +100,17 @@ const aluMatrixf IdentityMatrixf = {{ }}; +struct OutputLimiter *alloc_limiter(void) +{ + struct OutputLimiter *limiter = al_calloc(16, sizeof(*limiter)); + /* Limiter attack drops -80dB in 50ms. */ + limiter->AttackRate = 0.05f; + /* Limiter release raises +80dB in 1s. */ + limiter->ReleaseRate = 1.0f; + limiter->Gain = 1.0f; + return limiter; +} + void DeinitVoice(ALvoice *voice) { struct ALvoiceProps *props; @@ -1400,47 +1411,74 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } -static ALfloat ApplyLimiter(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, - const ALfloat AttackRate, const ALfloat ReleaseRate, - const ALfloat InGain, ALfloat (*restrict Gains), - const ALsizei SamplesToDo) +static void ApplyLimiter(struct OutputLimiter *Limiter, + ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, + const ALfloat AttackRate, const ALfloat ReleaseRate, + ALfloat *restrict Values, const ALsizei SamplesToDo) { bool do_limit = false; ALsizei c, i; OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - Gains = ASSUME_ALIGNED(Gains, 16); + Values = ASSUME_ALIGNED(Values, 16); for(i = 0;i < SamplesToDo;i++) - Gains[i] = 1.0f; + Values[i] = 0.0f; + /* First, find the maximum amplitude (squared) for each sample position in each channel. */ for(c = 0;c < NumChans;c++) { - ALfloat lastgain = InGain; for(i = 0;i < SamplesToDo;i++) { + ALfloat amp_sqr = OutBuffer[c][i] * OutBuffer[c][i]; + Values[i] = maxf(Values[i], amp_sqr); + } + } + + /* Next, calculate the gains needed to limit the output. */ + { + ALfloat lastgain = Limiter->Gain; + ALsizei wpos = Limiter->Pos; + ALfloat sum = 0.0f; + ALfloat gain; + + /* Unfortunately we can't store the running sum due to fp inaccuracies + * causing it to drift over time. So we need to recalculate it every + * once in a while (i.e. every invocation). + */ + for(i = 0;i < LIMITER_WINDOW_SIZE;i++) + sum += Limiter->Window[i]; + + for(i = 0;i < SamplesToDo;i++) + { + sum -= Limiter->Window[wpos]; + Limiter->Window[wpos] = Values[i]; + sum += Values[i]; + /* Clamp limiter range to 0dB...-80dB. */ - ALfloat gain = 1.0f / clampf(fabsf(OutBuffer[c][i]), 1.0f, 1000.0f); + gain = 1.0f / clampf(sqrtf(sum / (ALfloat)LIMITER_WINDOW_SIZE), 1.0f, 1000.0f); if(lastgain >= gain) lastgain = maxf(lastgain*AttackRate, gain); else lastgain = minf(lastgain/ReleaseRate, gain); do_limit |= (lastgain < 1.0f); + Values[i] = lastgain; - lastgain = minf(lastgain, Gains[i]); - Gains[i] = lastgain; + wpos = (wpos+1)&LIMITER_WINDOW_MASK; } + + Limiter->Gain = lastgain; + Limiter->Pos = wpos; } if(do_limit) { + /* Finally, apply the gains to each channel. */ for(c = 0;c < NumChans;c++) { for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= Gains[i]; + OutBuffer[c][i] *= Values[i]; } } - - return Gains[SamplesToDo-1]; } static inline ALfloat aluF2F(ALfloat val) @@ -1689,19 +1727,17 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; + struct OutputLimiter *Limiter = device->Limiter; DistanceComp *DistComp; - if(device->LimiterGain > 0.0f) + if(Limiter) { - /* Limiter attack drops -80dB in 50ms. */ - const ALfloat AttackRate = powf(0.0001f, 1.0f/(device->Frequency*0.05f)); - /* Limiter release raises +80dB in 1s. */ - const ALfloat ReleaseRate = powf(0.0001f, 1.0f/(device->Frequency*1.0f)); - - /* Use NFCtrlData for temp gain storage. */ - device->LimiterGain = ApplyLimiter(OutBuffer, OutChannels, - AttackRate, ReleaseRate, device->LimiterGain, device->NFCtrlData, - SamplesToDo + const ALfloat AttackRate = powf(0.0001f, 1.0f/(device->Frequency*Limiter->AttackRate)); + const ALfloat ReleaseRate = powf(0.0001f, 1.0f/(device->Frequency*Limiter->ReleaseRate)); + + /* Use NFCtrlData for temp value storage. */ + ApplyLimiter(Limiter, OutBuffer, OutChannels, + AttackRate, ReleaseRate, device->NFCtrlData, SamplesToDo ); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1b1b1909..55f52bef 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -391,6 +391,7 @@ extern "C" { struct Hrtf; struct HrtfEntry; +struct OutputLimiter; #define DEFAULT_OUTPUT_RATE (44100) @@ -793,7 +794,7 @@ struct ALCdevice_struct ALsizei NumChannels; } RealOut; - ALfloat LimiterGain; + struct OutputLimiter *Limiter; /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8e2fe1e9..6fdbac6f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -297,6 +297,24 @@ typedef struct ALvoice { void DeinitVoice(ALvoice *voice); +#define LIMITER_WINDOW_SIZE (1<<7) /* 128 */ +#define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1) +struct OutputLimiter { + /* RMS detection window and the next write pos. */ + alignas(16) ALfloat Window[LIMITER_WINDOW_SIZE]; + ALsizei Pos; + + /* In milliseconds. */ + ALfloat AttackRate; + ALfloat ReleaseRate; + + /* The gain last used for limiting. */ + ALfloat Gain; +}; + +struct OutputLimiter *alloc_limiter(void); + + typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, -- cgit v1.2.3 From e1bc4c0730960761593481d2b048f760a9f008f8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 May 2017 07:49:56 -0700 Subject: Include the Built-In HRTF names in alsoft-config when enabled --- utils/alsoft-config/mainwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index d46bb029..4f16726f 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -540,6 +540,11 @@ QStringList MainWindow::collectHrtfs() } } } + +#ifdef ALSOFT_EMBED_HRTF_DATA + ret.push_back("Built-In 44100hz"); + ret.push_back("Built-In 48000hz"); +#endif } return ret; } -- cgit v1.2.3 From d9d2e732284eef9b386e312b131757370625c3d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 May 2017 10:10:10 -0700 Subject: Update AL_SOURCE_SPATIALIZE_SOFT value Though it didn't strictly clash since it was for a different component (global state vs source property), 0x1213 was used by AL_RESAMPLER_NAME_SOFT. Probably best to avoid duplicate property values regardless. --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 55f52bef..7d9ab4d9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -146,7 +146,7 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #ifndef AL_SOFT_source_spatialize #define AL_SOFT_source_spatialize -#define AL_SOURCE_SPATIALIZE_SOFT 0x1213 +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 #define AL_AUTO_SOFT 0x0002 #endif -- cgit v1.2.3 From 5308ea7e2afa2d99a420f9bb7c7e9acac3294d94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 May 2017 04:29:18 -0700 Subject: Put the app name after filename in the window title --- examples/alffplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 00d51673..10870930 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -1193,7 +1193,7 @@ void MovieState::setTitle(SDL_Window *window) auto fpos = ((pos1 == std::string::npos) ? pos2 : (pos2 == std::string::npos) ? pos1 : std::max(pos1, pos2)) + 1; - SDL_SetWindowTitle(window, (AppName+" - "+mFilename.substr(fpos)).c_str()); + SDL_SetWindowTitle(window, (mFilename.substr(fpos)+" - "+AppName).c_str()); } double MovieState::getClock() -- cgit v1.2.3 From 0dabe6398f8806931e6ac0933b67931f11242ff0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 May 2017 18:28:43 -0700 Subject: Apply attenuation when downmixing multi-channel sounds for panning --- Alc/ALu.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f9defedd..8d9356c5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -414,6 +414,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const const struct ChanMap *chans = NULL; ALsizei num_channels = 0; bool isbformat = false; + ALfloat downmix_gain = 1.0f; ALsizei c, i, j; switch(Buffer->FmtChannels) @@ -432,31 +433,40 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const chans = StereoMap; num_channels = 2; + downmix_gain = 1.0f / 2.0f; break; case FmtRear: chans = RearMap; num_channels = 2; + downmix_gain = 1.0f / 2.0f; break; case FmtQuad: chans = QuadMap; num_channels = 4; + downmix_gain = 1.0f / 4.0f; break; case FmtX51: chans = X51Map; num_channels = 6; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 5.0f; break; case FmtX61: chans = X61Map; num_channels = 7; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 6.0f; break; case FmtX71: chans = X71Map; num_channels = 8; + /* NOTE: Excludes LFE. */ + downmix_gain = 1.0f / 7.0f; break; case FmtBFormat2D: @@ -544,8 +554,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const } else { - /* Non-panned B-Format has its XYZ channels rotated according to - * the orientation. + /* Local B-Format sources have their XYZ channels rotated according + * to the orientation. */ ALfloat N[3], V[3], U[3]; aluMatrixf matrix; @@ -622,8 +632,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const } else if(DirectChannels) { - /* Skip the virtual channels and write inputs to the real output with - * no explicit panning. + /* Direct source channels always play local. Skip the virtual channels + * and write inputs to the matching real outputs. */ voice->Direct.Buffer = Device->RealOut.Buffer; voice->Direct.Channels = Device->RealOut.NumChannels; @@ -680,7 +690,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const GetHrtfCoeffs(Device->HrtfHandle, ev, az, Spread, voice->Direct.Params[0].Hrtf.Target.Coeffs, voice->Direct.Params[0].Hrtf.Target.Delay); - voice->Direct.Params[0].Hrtf.Target.Gain = DryGain; + voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; /* Remaining channels use the same results as the first. */ for(c = 1;c < num_channels;c++) @@ -709,8 +719,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Send[i].Params[c].Gains.Target[j] = 0.0f; else - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ComputePanningGainsBF(Slot->ChanMap, + Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, + voice->Send[i].Params[c].Gains.Target ); } else @@ -720,6 +731,10 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const } else { + /* Local sources on HRTF play with each channel panned to its + * relative location around the listener, providing "virtual + * speaker" responses. + */ for(c = 0;c < num_channels;c++) { ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -829,7 +844,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const } ComputePanningGains(Device->Dry, - coeffs, DryGain, voice->Direct.Params[c].Gains.Target + coeffs, DryGain * downmix_gain, voice->Direct.Params[c].Gains.Target ); } @@ -844,8 +859,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(j = 0;j < MAX_EFFECT_CHANNELS;j++) voice->Send[i].Params[c].Gains.Target[j] = 0.0f; else - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target + ComputePanningGainsBF(Slot->ChanMap, + Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, + voice->Send[i].Params[c].Gains.Target ); } else -- cgit v1.2.3 From f880f6704927488e0a29fdd576009cea0450fc58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 May 2017 13:57:31 -0700 Subject: Update reverb conversion matrices and output gain --- Alc/effects/reverb.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 820ab70a..41ec423b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -311,18 +311,18 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) * in the future, true opposites can be used. */ static const aluMatrixf B2A = {{ - { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } + { 0.866025403785f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.866025403785f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, + { 0.866025403785f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.866025403785f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; /* Converts A-Format to B-Format (transposed). */ static const aluMatrixf A2B = {{ - { 0.8660254038f, 0.8660254038f, 0.8660254038f, 0.8660254038f }, - { 0.8660254038f, -0.8660254038f, -0.8660254038f, 0.8660254038f }, - { 0.8660254038f, 0.8660254038f, -0.8660254038f, -0.8660254038f }, - { 0.8660254038f, -0.8660254038f, 0.8660254038f, -0.8660254038f } + { 0.288675134595f, 0.866025403785f, 0.866025403785f, 0.8660254038f }, + { 0.288675134595f, -0.866025403785f, -0.866025403785f, 0.8660254038f }, + { 0.288675134595f, 0.866025403785f, -0.866025403785f, -0.8660254038f }, + { 0.288675134595f, -0.866025403785f, 0.866025403785f, -0.8660254038f } }}; static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; @@ -1413,9 +1413,11 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device frequency, State); /* Update early and late 3D panning. Attenuate the early and late stages - * both by 0.7071 (-3dB) to better balance the mixture. + * both by 0.5 (-6dB) to better balance the early and late mixture, and + * also to balance the two-step early reflection taps (which feed into the + * late reverb). */ - gain = sqrtf(0.5f) * props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; + gain = 0.5f * props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, -- cgit v1.2.3 From 4a4442ad91d34964b1d695381fafbdef07bb14ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 May 2017 16:23:16 -0700 Subject: Store the output limiter values as fixed-point integers This helps keep the squared sum stable over larger updates, also avoiding the need to keep recalculating it. --- Alc/ALu.c | 17 ++++++----------- OpenAL32/Include/alu.h | 8 ++++++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8d9356c5..b8c93c69 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1455,24 +1455,18 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, { ALfloat lastgain = Limiter->Gain; ALsizei wpos = Limiter->Pos; - ALfloat sum = 0.0f; + ALuint sum = Limiter->SquaredSum; ALfloat gain; - /* Unfortunately we can't store the running sum due to fp inaccuracies - * causing it to drift over time. So we need to recalculate it every - * once in a while (i.e. every invocation). - */ - for(i = 0;i < LIMITER_WINDOW_SIZE;i++) - sum += Limiter->Window[i]; - for(i = 0;i < SamplesToDo;i++) { sum -= Limiter->Window[wpos]; - Limiter->Window[wpos] = Values[i]; - sum += Values[i]; + Limiter->Window[wpos] = fastf2u(minf(Values[i]*65536.0f, LIMITER_VALUE_MAX)); + sum += Limiter->Window[wpos]; /* Clamp limiter range to 0dB...-80dB. */ - gain = 1.0f / clampf(sqrtf(sum / (ALfloat)LIMITER_WINDOW_SIZE), 1.0f, 1000.0f); + gain = 1.0f / clampf(sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)), + 1.0f, 1000.0f); if(lastgain >= gain) lastgain = maxf(lastgain*AttackRate, gain); else @@ -1485,6 +1479,7 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, Limiter->Gain = lastgain; Limiter->Pos = wpos; + Limiter->SquaredSum = sum; } if(do_limit) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6fdbac6f..8ac25e35 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -299,9 +299,13 @@ void DeinitVoice(ALvoice *voice); #define LIMITER_WINDOW_SIZE (1<<7) /* 128 */ #define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1) +#define LIMITER_VALUE_MAX (UINT_MAX / LIMITER_WINDOW_SIZE) struct OutputLimiter { - /* RMS detection window and the next write pos. */ - alignas(16) ALfloat Window[LIMITER_WINDOW_SIZE]; + /* RMS detection window, sum of values in the window, and the next write + * pos. Values are 16.16 fixed-point. + */ + ALuint Window[LIMITER_WINDOW_SIZE]; + ALuint SquaredSum; ALsizei Pos; /* In milliseconds. */ -- cgit v1.2.3 From a2c25378a970792461c961054e2b47cd3a086e05 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 May 2017 11:50:25 -0700 Subject: Reduce LIMITER_VALUE_MAX The previous value couldn't actually be expressed as a float and got rounded up to the next whole number value, leaving the potential for an overrun in the squared sum. --- Alc/ALu.c | 18 ++++++++++++------ OpenAL32/Include/alu.h | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index b8c93c69..e564ee00 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1427,6 +1427,8 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } +static_assert(LIMITER_VALUE_MAX < (UINT_MAX/LIMITER_WINDOW_SIZE), "LIMITER_VALUE_MAX is too big"); + static void ApplyLimiter(struct OutputLimiter *Limiter, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, const ALfloat AttackRate, const ALfloat ReleaseRate, @@ -1446,8 +1448,8 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, { for(i = 0;i < SamplesToDo;i++) { - ALfloat amp_sqr = OutBuffer[c][i] * OutBuffer[c][i]; - Values[i] = maxf(Values[i], amp_sqr); + ALfloat amp = OutBuffer[c][i]; + Values[i] = maxf(Values[i], amp*amp); } } @@ -1456,7 +1458,7 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, ALfloat lastgain = Limiter->Gain; ALsizei wpos = Limiter->Pos; ALuint sum = Limiter->SquaredSum; - ALfloat gain; + ALfloat gain, rms; for(i = 0;i < SamplesToDo;i++) { @@ -1464,9 +1466,13 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, Limiter->Window[wpos] = fastf2u(minf(Values[i]*65536.0f, LIMITER_VALUE_MAX)); sum += Limiter->Window[wpos]; - /* Clamp limiter range to 0dB...-80dB. */ - gain = 1.0f / clampf(sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)), - 1.0f, 1000.0f); + rms = sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)); + + /* Clamp the minimum RMS to 0dB. The uint used for the squared sum + * inherently limits the maximum RMS to about 21dB, thus the gain + * ranges from 0dB to -21dB. + */ + gain = 1.0f / maxf(rms, 1.0f); if(lastgain >= gain) lastgain = maxf(lastgain*AttackRate, gain); else diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8ac25e35..30b245a5 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -299,7 +299,7 @@ void DeinitVoice(ALvoice *voice); #define LIMITER_WINDOW_SIZE (1<<7) /* 128 */ #define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1) -#define LIMITER_VALUE_MAX (UINT_MAX / LIMITER_WINDOW_SIZE) +#define LIMITER_VALUE_MAX (1<<24) /* 16777216 */ struct OutputLimiter { /* RMS detection window, sum of values in the window, and the next write * pos. Values are 16.16 fixed-point. -- cgit v1.2.3 From a6f6533a28fd68c4e552353235b9a2a7aeffa0cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 May 2017 11:04:25 -0700 Subject: Update ALC_OUTPUT_LIMITER_SOFT to handle ALC_DONT_CARE_SOFT Essentially just adding a comment about it. Since we default to on, the behavior already fit. --- Alc/ALc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fe8a0266..55292480 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1762,7 +1762,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { enum HrtfRequestMode hrtf_userreq = Hrtf_Default; enum HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = !!device->Limiter; + ALCenum gainLimiter = device->Limiter ? ALC_TRUE : ALC_FALSE; const ALsizei old_sends = device->NumAuxSends; ALsizei new_sends = device->NumAuxSends; enum DevFmtChannels oldChans; @@ -2215,13 +2215,17 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->AuxiliaryEffectSlotMax, device->NumAuxSends); if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) - gainLimiter = val; - if(gainLimiter) + gainLimiter = val ? ALC_TRUE : ALC_FALSE; + /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and + * ALC_FALSE. We default to on, so ALC_DONT_CARE_SOFT is the same as + * ALC_TRUE. + */ + if(gainLimiter != ALC_FALSE) { if(!device->Limiter) device->Limiter = alloc_limiter(); } - else if(device->Limiter) + else { al_free(device->Limiter); device->Limiter = NULL; -- cgit v1.2.3 From 748dfb1526aaa5411bba98352fc7546e19881ad0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 May 2017 14:38:04 -0700 Subject: Finalize AL_SOFT_source_spatialize --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 6 ------ include/AL/alext.h | 6 ++++++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 55292480..0ac65077 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -738,7 +738,7 @@ static const ALchar alExtList[] = "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length " - "AL_SOFT_source_resampler AL_SOFTX_source_spatialize"; + "AL_SOFT_source_resampler AL_SOFT_source_spatialize"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7d9ab4d9..ec65c8fc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -144,12 +144,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #define ALC_OUTPUT_LIMITER_SOFT 0x199A #endif -#ifndef AL_SOFT_source_spatialize -#define AL_SOFT_source_spatialize -#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 -#define AL_AUTO_SOFT 0x0002 -#endif - #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/include/AL/alext.h b/include/AL/alext.h index 50ad10ec..ac422e25 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -448,6 +448,12 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #endif #endif +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From ef58a8f2056d5a85f33543cebc23d08388c78e52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 May 2017 16:29:05 -0700 Subject: Log whether the output limiter is enabled or disabled --- Alc/ALc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0ac65077..75c0e957 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2230,6 +2230,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Limiter); device->Limiter = NULL; } + TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. -- cgit v1.2.3 From 685dc24299b0ce7d51f27387af2cbf69f9fec7b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 May 2017 21:48:47 -0700 Subject: Restore the previous reverb B2A and A2B matrices Also, untranspose the A2B matrix. --- Alc/effects/reverb.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 41ec423b..77a19c7f 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -311,18 +311,18 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) * in the future, true opposites can be used. */ static const aluMatrixf B2A = {{ - { 0.866025403785f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, - { 0.866025403785f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, - { 0.866025403785f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, - { 0.866025403785f, -0.288675134595f, 0.288675134595f, -0.288675134595f } + { 0.288675134595f, 0.288675134595f, 0.288675134595f, 0.288675134595f }, + { 0.288675134595f, -0.288675134595f, -0.288675134595f, 0.288675134595f }, + { 0.288675134595f, 0.288675134595f, -0.288675134595f, -0.288675134595f }, + { 0.288675134595f, -0.288675134595f, 0.288675134595f, -0.288675134595f } }}; -/* Converts A-Format to B-Format (transposed). */ +/* Converts A-Format to B-Format. */ static const aluMatrixf A2B = {{ - { 0.288675134595f, 0.866025403785f, 0.866025403785f, 0.8660254038f }, - { 0.288675134595f, -0.866025403785f, -0.866025403785f, 0.8660254038f }, - { 0.288675134595f, 0.866025403785f, -0.866025403785f, -0.8660254038f }, - { 0.288675134595f, -0.866025403785f, 0.866025403785f, -0.8660254038f } + { 0.866025403785f, 0.866025403785f, 0.866025403785f, 0.866025403785f }, + { 0.866025403785f, -0.866025403785f, 0.866025403785f, -0.866025403785f }, + { 0.866025403785f, -0.866025403785f, -0.866025403785f, 0.866025403785f }, + { 0.866025403785f, 0.866025403785f, -0.866025403785f, -0.866025403785f } }}; static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; @@ -1305,14 +1305,14 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection STATIC_CAST(ALeffectState,State)->OutBuffer = Device->FOAOut.Buffer; STATIC_CAST(ALeffectState,State)->OutChannels = Device->FOAOut.NumChannels; - /* Note: Both _m2 and _res are transposed. */ + /* Note: _res is transposed. */ #define MATRIX_MULT(_res, _m1, _m2) do { \ int row, col; \ for(col = 0;col < 4;col++) \ { \ for(row = 0;row < 4;row++) \ - _res.m[col][row] = _m1.m[row][0]*_m2.m[col][0] + _m1.m[row][1]*_m2.m[col][1] + \ - _m1.m[row][2]*_m2.m[col][2] + _m1.m[row][3]*_m2.m[col][3]; \ + _res.m[col][row] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ + _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ } \ } while(0) /* Create a matrix that first converts A-Format to B-Format, then rotates -- cgit v1.2.3 From d456c799fdb844a3ef9e96a95084a7b68928247f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 May 2017 23:26:29 -0700 Subject: Remove the 0.5 gain on the reverb output Turns out to be unnecessary, as it reduced the volume below what other reverb implementations provide with the same presets. --- Alc/effects/reverb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 77a19c7f..07a1b679 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1412,12 +1412,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, State); - /* Update early and late 3D panning. Attenuate the early and late stages - * both by 0.5 (-6dB) to better balance the early and late mixture, and - * also to balance the two-step early reflection taps (which feed into the - * late reverb). - */ - gain = 0.5f * props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; + /* Update early and late 3D panning. */ + gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, gain, props->Reverb.ReflectionsGain, -- cgit v1.2.3 From 87d4710bc4f980663fa8ca67a9ef416aa56b2a93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 May 2017 20:53:14 -0700 Subject: Apply reverb modulation to the late feedback lines This seems to be more in-line with the intended behavior, to allow build-up and overlap within the reverb decay, rather than a pitch-shift on input. Unfortunately there's no readily available implementation of this reverb model that includes modulation to compare with, so a low depth coefficient is used to keep it very subtle. --- Alc/effects/reverb.c | 175 +++++++++++++++++++++------------------------------ 1 file changed, 71 insertions(+), 104 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 07a1b679..c1b0369b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -89,22 +89,6 @@ typedef struct ALreverbState { ALfilterState Hp; /* EAX only */ } Filter[4]; - struct { - /* Modulator delay lines. */ - DelayLine Delay[4]; - - /* The vibrato time is tracked with an index over a modulus-wrapped - * range (in samples). - */ - ALuint Index; - ALuint Range; - - /* The depth of frequency change (also in samples) and its filter. */ - ALfloat Depth; - ALfloat Coeff; - ALfloat Filter; - } Mod; /* EAX only */ - /* Core delay line (early reflections and late reverb tap from this). */ DelayLine Delay; @@ -142,6 +126,19 @@ typedef struct ALreverbState { ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Early; + struct { + /* The vibrato time is tracked with an index over a modulus-wrapped + * range (in samples). + */ + ALuint Index; + ALuint Range; + + /* The depth of frequency change (also in samples) and its filter. */ + ALfloat Depth; + ALfloat Coeff; + ALfloat Filter; + } Mod; /* EAX only */ + struct { /* Attenuation to compensate for the modal density and decay rate of * the late lines. @@ -207,17 +204,8 @@ static void ALreverbState_Construct(ALreverbState *state) { ALfilterState_clear(&state->Filter[i].Lp); ALfilterState_clear(&state->Filter[i].Hp); - - state->Mod.Delay[i].Mask = 0; - state->Mod.Delay[i].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->Delay.Mask = 0; state->Delay.Line = NULL; @@ -253,6 +241,12 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Coeff[i] = 0.0f; } + state->Mod.Index = 0; + state->Mod.Range = 1; + state->Mod.Depth = 0.0f; + state->Mod.Coeff = 0.0f; + state->Mod.Filter = 0.0f; + state->Late.DensityGain = 0.0f; for(i = 0;i < 4;i++) @@ -337,13 +331,12 @@ ALfloat ReverbBoost = 1.0f; */ ALboolean EmulateEAXReverb = AL_FALSE; -/* This coefficient is used to define the maximum frequency range controlled - * by the modulation depth. The current value of 0.025 will allow it to - * swing from 0.975x to 1.025x. This value must be below 1. At 1 it will - * cause the sampler to stall on the downswing, and above 1 it will cause it - * to sample backwards. +/* This coefficient is used to define the sinus depth according to the + * modulation depth property. This value must be below 1, which would cause the + * sampler to stall on the downswing, and above 1 it will cause it to sample + * backwards. */ -static const ALfloat MODULATION_DEPTH_COEFF = 0.025f; +static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 2048.0f; /* A filter is used to avoid the terrible distortion caused by changing * modulation time and/or depth. To be consistent across different sample @@ -540,16 +533,6 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) */ totalSamples = 0; - /* The modulator's line length is calculated from the maximum modulation - * time and depth coefficient, and halfed for the low-to-high frequency - * swing. An additional sample is added to keep it stable when there is no - * modulation. - */ - length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); - for(i = 0;i < 4;i++) - totalSamples += CalcLineLength(length, totalSamples, frequency, 1, - &State->Mod.Delay[i]); - /* The main delay length includes the maximum early reflection delay, the * largest early tap width, the maximum late reverb delay, and the * largest late tap width. Finally, it must also be extended by the @@ -591,11 +574,15 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) } /* The late delay lines are calculated from the larger of the maximum - * density line length or the maximum echo time. + * density line length or the maximum echo time, and includes the maximum + * modulation-related delay. The modulator's delay is calculated from the + * maximum modulation time and depth coefficient, and halved for the low- + * to-high frequency swing. */ for(i = 0;i < 4;i++) { - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i] * multiplier); + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i]*multiplier) + + AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay[i]); } @@ -617,8 +604,6 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) RealizeLineOffset(State->SampleBuffer, &State->Delay); for(i = 0;i < 4;i++) { - RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay[i]); - RealizeLineOffset(State->SampleBuffer, &State->Early.Ap[i].Delay); RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[i]); @@ -1069,7 +1054,8 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime * kind of vibrato is additive and not multiplicative as one may expect. The * downswing will sound stronger than the upswing. */ -static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, const ALuint frequency, ALreverbState *State) +static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, + const ALuint frequency, ALreverbState *State) { ALuint range; @@ -1372,10 +1358,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; } - /* Update the modulator line. */ - UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, - frequency, State); - /* Update the main effect delay and associated taps. */ UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, props->Reverb.Density, props->Reverb.DecayTime, frequency, @@ -1405,6 +1387,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); + /* Update the modulator line. */ + UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, + frequency, State); + /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, @@ -1441,7 +1427,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device **************************************/ /* Basic delay line input/output routines. */ -static inline ALfloat DelayLineOut(DelayLine *Delay, const ALsizei offset) +static inline ALfloat DelayLineOut(const DelayLine *Delay, const ALsizei offset) { return Delay->Line[offset&Delay->Mask]; } @@ -1449,7 +1435,7 @@ static inline ALfloat DelayLineOut(DelayLine *Delay, const ALsizei offset) /* Cross-faded delay line output routine. Instead of interpolating the * offsets, this interpolates (cross-fades) the outputs at each offset. */ -static inline ALfloat FadedDelayLineOut(DelayLine *Delay, const ALsizei off0, const ALsizei off1, const ALfloat mu) +static inline ALfloat FadedDelayLineOut(const DelayLine *Delay, const ALsizei off0, const ALsizei off1, const ALfloat mu) { return lerp(Delay->Line[off0&Delay->Mask], Delay->Line[off1&Delay->Mask], mu); } @@ -1461,12 +1447,6 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, const ALsizei offset, const A Delay->Line[offset&Delay->Mask] = in; } -static inline ALfloat DelayLineInOut(DelayLine *Delay, const ALsizei offset, const ALsizei outoffset, const ALfloat in) -{ - Delay->Line[offset&Delay->Mask] = in; - return Delay->Line[(offset-outoffset)&Delay->Mask]; -} - static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo) { ALfloat sinus, range; @@ -1498,37 +1478,6 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, State->Mod.Filter = range; } -/* Given some input samples, this function produces modulation for the late - * reverb. - */ -static void EAXModulation(DelayLine *ModDelay, ALsizei offset, const ALfloat *restrict delays, ALfloat*restrict dst, const ALfloat*restrict src, const ALsizei todo) -{ - ALfloat frac, fdelay; - ALfloat out0, out1; - ALsizei delay, i; - - for(i = 0;i < todo;i++) - { - /* Separate the integer offset and fraction between it and the next - * sample. - */ - frac = modff(delays[i], &fdelay); - delay = fastf2u(fdelay); - - /* Add the incoming sample to the delay line, and get the two samples - * crossed by the offset delay. - */ - out0 = DelayLineInOut(ModDelay, offset, delay, src[i]); - out1 = DelayLineOut(ModDelay, offset - delay - 1); - offset++; - - /* The output is obtained by linearly interpolating the two samples - * that were acquired above. - */ - dst[i] = lerp(out0, out1, frac); - } -} - /* Applies a scattering matrix to the 4-line (vector) input. This is used * for both the below vector all-pass model and to perform modal feed-back * delay network (FDN) mixing. @@ -1742,10 +1691,15 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ const ALfloat mixX = State->MixX; \ const ALfloat mixY = State->MixY; \ + ALfloat fdelay, frac; \ + ALsizei delay; \ ALsizei offset; \ ALsizei i, j; \ ALfloat f[4]; \ \ + /* Calculations modulation delays, uing the output as temp storage. */ \ + CalcModulationDelays(State, &out[0][0], todo); \ + \ offset = State->Offset; \ for(i = 0;i < todo;i++) \ { \ @@ -1755,10 +1709,29 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ (offset-State->LateDelayTap[j][1])*4 + j, fade \ ) * State->Late.DensityGain; \ \ + /* Separate the integer offset and fraction between it and the next \ + * sample. \ + */ \ + frac = modff(out[0][i], &fdelay); \ + delay = offset - fastf2i(fdelay); \ + \ for(j = 0;j < 4;j++) \ - f[j] += DELAY_OUT_##T(&State->Late.Delay[j], \ - offset-State->Late.Offset[j][0], \ - offset-State->Late.Offset[j][1], fade); \ + { \ + ALfloat out0, out1; \ + \ + /* Get the two samples crossed by the offset delay. */ \ + out0 = DELAY_OUT_##T(&State->Late.Delay[j], \ + delay-State->Late.Offset[j][0], \ + delay-State->Late.Offset[j][1], fade); \ + out1 = DELAY_OUT_##T(&State->Late.Delay[j], \ + delay-State->Late.Offset[j][0]-1, \ + delay-State->Late.Offset[j][1]-1, fade); \ + \ + /* The modulated result is obtained by linearly interpolating the \ + * two samples that were acquired above. \ + */ \ + f[j] += lerp(out0, out1, frac); \ + } \ \ for(j = 0;j < 4;j++) \ f[j] = LateT60Filter(j, f[j], State); \ @@ -1844,23 +1817,17 @@ static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fad { ALsizei i, c; - /* Perform any modulation on the input (use the early and late buffers as - * temp storage). - */ - CalcModulationDelays(State, &late[0][0], todo); for(c = 0;c < 4;c++) { - /* Apply modulation. */ - EAXModulation(&State->Mod.Delay[c], State->Offset, &late[0][0], - &early[0][0], input[c], todo); - - /* Band-pass the incoming samples. */ - ALfilterState_process(&State->Filter[c].Lp, &early[1][0], &early[0][0], todo); - ALfilterState_process(&State->Filter[c].Hp, &early[2][0], &early[1][0], todo); + /* Band-pass the incoming samples. Use the early output lines for temp + * storage. + */ + ALfilterState_process(&State->Filter[c].Lp, early[0], input[c], todo); + ALfilterState_process(&State->Filter[c].Hp, early[1], early[0], todo); /* Feed the initial delay line. */ for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[2][i]); + DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[1][i]); } if(fade < 1.0f) -- cgit v1.2.3 From 0b66b2bbe798f7e9bca3fb101ff72d06334124ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 May 2017 15:45:05 -0700 Subject: Replace 4 separate all-passes with one vector all-pass Each 4 related all-passes now share a structure with one delay line, which uses an interleaved sample history. Also fixes some potential rounding problems for delay lines with interleaved samples. --- Alc/effects/reverb.c | 100 ++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c1b0369b..92698bd4 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -67,10 +67,10 @@ typedef struct DelayLine { ALfloat *Line; } DelayLine; -typedef struct Allpass { +typedef struct VecAllpass { DelayLine Delay; - ALsizei Offset[2]; -} Allpass; + ALsizei Offset[4][2]; +} VecAllpass; typedef struct ALreverbState { DERIVE_FROM_TYPE(ALeffectState); @@ -112,7 +112,7 @@ typedef struct ALreverbState { * diffusion. The spread from this filter also helps smooth out the * reverb tail. */ - Allpass Ap[4]; + VecAllpass VecAp; /* Echo lines are used to complete the second half of the early * reflections. @@ -161,7 +161,7 @@ typedef struct ALreverbState { } Filters[4]; /* A Gerzon vector all-pass filter is used to simulate diffusion. */ - Allpass Ap[4]; + VecAllpass VecAp; /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; @@ -228,12 +228,12 @@ static void ALreverbState_Construct(ALreverbState *state) state->MixX = 0.0f; state->MixY = 0.0f; + state->Early.VecAp.Delay.Mask = 0; + state->Early.VecAp.Delay.Line = NULL; for(i = 0;i < 4;i++) { - state->Early.Ap[i].Delay.Mask = 0; - state->Early.Ap[i].Delay.Line = NULL; - state->Early.Ap[i].Offset[0] = 0; - state->Early.Ap[i].Offset[1] = 0; + state->Early.VecAp.Offset[i][0] = 0; + state->Early.VecAp.Offset[i][1] = 0; state->Early.Delay[i].Mask = 0; state->Early.Delay[i].Line = NULL; state->Early.Offset[i][0] = 0; @@ -249,12 +249,12 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.DensityGain = 0.0f; + state->Late.VecAp.Delay.Mask = 0; + state->Late.VecAp.Delay.Line = NULL; for(i = 0;i < 4;i++) { - state->Late.Ap[i].Delay.Mask = 0; - state->Late.Ap[i].Delay.Line = NULL; - state->Late.Ap[i].Offset[0] = 0; - state->Late.Ap[i].Offset[1] = 0; + state->Late.VecAp.Offset[i][0] = 0; + state->Late.VecAp.Offset[i][1] = 0; state->Late.Delay[i].Mask = 0; state->Late.Delay[i].Line = NULL; @@ -501,15 +501,15 @@ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) /* Calculate the length of a delay line and store its mask and offset. */ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, - const ALuint extra, DelayLine *Delay) + const ALuint extra, const ALuint splmult, DelayLine *Delay) { ALuint samples; - /* All line lengths are powers of 2, calculated from their lengths, with - * an additional sample in case of rounding errors. + /* All line lengths are powers of 2, calculated from their lengths in + * seconds, rounded up. */ - samples = fastf2u(length*frequency) + extra; - samples = NextPowerOf2(samples + 1); + samples = fastf2u(ceilf(length*frequency)); + samples = NextPowerOf2((samples+extra) * splmult); /* All lines share a single sample buffer. */ Delay->Mask = samples - 1; @@ -546,32 +546,28 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) /* Multiply length by 4, since we're storing 4 interleaved channels in the * main delay line. */ - totalSamples += CalcLineLength(length*4, totalSamples, frequency, - MAX_UPDATE_SAMPLES*4, &State->Delay); + totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, 4, + &State->Delay); - /* The early all-pass lines. */ - for(i = 0;i < 4;i++) - { - length = EARLY_ALLPASS_LENGTHS[i] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Early.Ap[i].Delay); - } + /* The early all-pass line. Multiply by 4, for 4 interleaved channels. */ + length = (EARLY_ALLPASS_LENGTHS[0]+EARLY_ALLPASS_LENGTHS[1]+ + EARLY_ALLPASS_LENGTHS[2]+EARLY_ALLPASS_LENGTHS[3]) * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + &State->Early.VecAp.Delay); /* The early reflection lines. */ for(i = 0;i < 4;i++) { length = EARLY_LINE_LENGTHS[i] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1, &State->Early.Delay[i]); } - /* The late vector all-pass lines. */ - for(i = 0;i < 4;i++) - { - length = LATE_ALLPASS_LENGTHS[i] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, - &State->Late.Ap[i].Delay); - } + /* The late vector all-pass line. Multiply by 4, for 4 interleaved channels. */ + length = (LATE_ALLPASS_LENGTHS[0]+LATE_ALLPASS_LENGTHS[1]+ + LATE_ALLPASS_LENGTHS[2]+LATE_ALLPASS_LENGTHS[3]) * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + &State->Late.VecAp.Delay); /* The late delay lines are calculated from the larger of the maximum * density line length or the maximum echo time, and includes the maximum @@ -583,7 +579,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) { length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i]*multiplier) + AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1, &State->Late.Delay[i]); } @@ -602,14 +598,12 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) /* Update all delays to reflect the new sample buffer. */ RealizeLineOffset(State->SampleBuffer, &State->Delay); + RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay); for(i = 0;i < 4;i++) - { - RealizeLineOffset(State->SampleBuffer, &State->Early.Ap[i].Delay); RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[i]); - - RealizeLineOffset(State->SampleBuffer, &State->Late.Ap[i].Delay); + RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay); + for(i = 0;i < 4;i++) RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[i]); - } /* Clear the sample buffer. */ for(i = 0;i < State->TotalSamples;i++) @@ -1129,7 +1123,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c length = EARLY_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - State->Early.Ap[i].Offset[1] = fastf2u(length * frequency); + State->Early.VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; @@ -1182,7 +1176,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - State->Late.Ap[i].Offset[1] = fastf2u(length * frequency); + State->Late.VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. This also * applies the echo transformation. As the EAX echo depth approaches @@ -1409,10 +1403,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device for(i = 0;i < 4;i++) { if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) || - (State->Early.Ap[i].Offset[1] != State->Early.Ap[i].Offset[0]) || + (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) || (State->Early.Offset[i][1] != State->Early.Offset[i][0]) || (State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) || - (State->Late.Ap[i].Offset[1] != State->Late.Ap[i].Offset[0]) || + (State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0]) || (State->Late.Offset[i][1] != State->Late.Offset[i][0])) { State->FadeCount = 0; @@ -1540,7 +1534,7 @@ static inline void VectorPartialScatter(ALfloat *restrict vec, const ALfloat xCo static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ const ALfloat feedCoeff, const ALfloat xCoeff, \ const ALfloat yCoeff, const ALfloat mu, \ - Allpass Ap[4]) \ + VecAllpass *Vap) \ { \ ALfloat input; \ ALfloat f[4]; \ @@ -1551,8 +1545,8 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ for(i = 0;i < 4;i++) \ { \ input = vec[i]; \ - vec[i] = DELAY_OUT_##T(&Ap[i].Delay, offset-Ap[i].Offset[0], \ - offset-Ap[i].Offset[1], mu) - \ + vec[i] = DELAY_OUT_##T(&Vap->Delay, (offset-Vap->Offset[i][0])*4 + i, \ + (offset-Vap->Offset[i][1])*4 + i, mu) - \ feedCoeff*input; \ f[i] = input + feedCoeff*vec[i]; \ } \ @@ -1560,7 +1554,7 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ VectorPartialScatter(f, xCoeff, yCoeff); \ \ for(i = 0;i < 4;i++) \ - DelayLineIn(&Ap[i].Delay, offset, f[i]); \ + DelayLineIn(&Vap->Delay, offset*4 + i, f[i]); \ } DECL_TEMPLATE(Unfaded) DECL_TEMPLATE(Faded) @@ -1617,7 +1611,7 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ ) * State->EarlyDelayCoeff[j]; \ \ VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ - State->Early.Ap); \ + &State->Early.VecAp); \ \ for(j = 0;j < 4;j++) \ DelayLineIn(&State->Early.Delay[j], offset, f[3 - j]); \ @@ -1737,7 +1731,7 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ f[j] = LateT60Filter(j, f[j], State); \ \ VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ - State->Late.Ap); \ + &State->Late.VecAp); \ \ for(j = 0;j < 4;j++) \ out[j][i] = f[j]; \ @@ -1889,10 +1883,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c for(c = 0;c < 4;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->Early.Ap[c].Offset[0] = State->Early.Ap[c].Offset[1]; + State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; State->Early.Offset[c][0] = State->Early.Offset[c][1]; State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.Ap[c].Offset[0] = State->Late.Ap[c].Offset[1]; + State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } } -- cgit v1.2.3 From 7cbce6806b5744669179140de8473a260caa654e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 May 2017 16:08:45 -0700 Subject: Update a couple comments about the reverb modulation --- Alc/effects/reverb.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 92698bd4..f00ee624 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1055,24 +1055,25 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, /* Modulation is calculated in two parts. * - * The modulation time effects the sinus applied to the change in - * frequency. An index out of the current time range (both in samples) - * is incremented each sample. The range is bound to a reasonable - * minimum (1 sample) and when the timing changes, the index is rescaled - * to the new range (to keep the sinus consistent). + * The modulation time effects the speed of the sinus. An index out of the + * current range (both in samples) is incremented each sample, so a longer + * time implies a larger range. The range is bound to a reasonable minimum + * (1 sample) and when the timing changes, the index is rescaled to the new + * range to keep the sinus consistent. */ range = maxu(fastf2u(modTime*frequency), 1); State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range / State->Mod.Range); State->Mod.Range = range; - /* The modulation depth effects the amount of frequency change over the - * range of the sinus. It needs to be scaled by the modulation time so - * that a given depth produces a consistent change in frequency over all - * ranges of time. Since the depth is applied to a sinus value, it needs - * to be halfed once for the sinus range and again for the sinus swing - * in time (half of it is spent decreasing the frequency, half is spent - * increasing it). + /* The modulation depth effects the scale of the sinus, which changes how + * much extra delay is added to the delay line. This delay changing over + * time changes the pitch, creating the modulation effect. The scale needs + * to be multiplied by the modulation time so that a given depth produces a + * consistent shift in frequency over all ranges of time. Since the depth + * is applied to a sinus value, it needs to be halved once for the sinus + * range (-1...+1 to 0...1) and again for the sinus swing in time (half of + * it is spent decreasing the frequency, half is spent increasing it). */ State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / 2.0f * frequency; -- cgit v1.2.3 From 232f05be93ff92dcc71d4d68a8b543c1f2a5bcdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 May 2017 19:52:37 -0700 Subject: Update ChangeLog for AL_SOFT_source_spatialize --- ChangeLog | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f3bb5f5c..87efeae7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,9 @@ openal-soft-1.18.0: - Implemented the AL_EXT_STEREO_ANGLES, AL_EXT_SOURCE_RADIUS, - AL_SOFT_gain_clamp_ex, and AL_SOFT_source_resampler extensions. + Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. + + Implemented the AL_SOFT_gain_clamp_ex, AL_SOFT_source_resampler, and + AL_SOFT_source_spatialize extensions. Implemented 3D processing for some effects. Currently implemented for Reverb, Compressor, Equalizer, and Ring Modulator. -- cgit v1.2.3 From cc1b774837ac3174244ec0af08882ea0098a2ab0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 May 2017 18:50:22 -0700 Subject: Don't enable NFC for a 0 reference delay --- Alc/panning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/panning.c b/Alc/panning.c index 4dcd607b..c00421c9 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -668,7 +668,7 @@ static void InitPanning(ALCdevice *device) ambiup_reset(device->AmbiUp, device); } - if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay)) + if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) { nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, -- cgit v1.2.3 From b2760baa6435546d295fa898ccbe6dbf4b7c6fde Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 May 2017 23:28:22 -0700 Subject: Make the reverb's early and late feedback lines interleaved --- Alc/effects/reverb.c | 89 +++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f00ee624..dd790ee0 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -117,7 +117,7 @@ typedef struct ALreverbState { /* Echo lines are used to complete the second half of the early * reflections. */ - DelayLine Delay[4]; + DelayLine Delay; ALsizei Offset[4][2]; ALfloat Coeff[4]; @@ -146,7 +146,7 @@ typedef struct ALreverbState { ALfloat DensityGain; /* Recursive delay lines are used fill in the reverb tail. */ - DelayLine Delay[4]; + DelayLine Delay; ALsizei Offset[4][2]; /* T60 decay filters are used to simulate absorption. */ @@ -228,14 +228,14 @@ static void ALreverbState_Construct(ALreverbState *state) state->MixX = 0.0f; state->MixY = 0.0f; + state->Early.Delay.Mask = 0; + state->Early.Delay.Line = NULL; state->Early.VecAp.Delay.Mask = 0; state->Early.VecAp.Delay.Line = NULL; for(i = 0;i < 4;i++) { state->Early.VecAp.Offset[i][0] = 0; state->Early.VecAp.Offset[i][1] = 0; - state->Early.Delay[i].Mask = 0; - state->Early.Delay[i].Line = NULL; state->Early.Offset[i][0] = 0; state->Early.Offset[i][1] = 0; state->Early.Coeff[i] = 0.0f; @@ -249,6 +249,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.DensityGain = 0.0f; + state->Late.Delay.Mask = 0; + state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; state->Late.VecAp.Delay.Line = NULL; for(i = 0;i < 4;i++) @@ -256,8 +258,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.VecAp.Offset[i][0] = 0; state->Late.VecAp.Offset[i][1] = 0; - state->Late.Delay[i].Mask = 0; - state->Late.Delay[i].Line = NULL; state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; @@ -556,12 +556,9 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) &State->Early.VecAp.Delay); /* The early reflection lines. */ - for(i = 0;i < 4;i++) - { - length = EARLY_LINE_LENGTHS[i] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1, - &State->Early.Delay[i]); - } + length = EARLY_LINE_LENGTHS[3] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + &State->Early.Delay); /* The late vector all-pass line. Multiply by 4, for 4 interleaved channels. */ length = (LATE_ALLPASS_LENGTHS[0]+LATE_ALLPASS_LENGTHS[1]+ @@ -575,13 +572,10 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) * maximum modulation time and depth coefficient, and halved for the low- * to-high frequency swing. */ - for(i = 0;i < 4;i++) - { - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[i]*multiplier) + - AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 1, - &State->Late.Delay[i]); - } + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) + + AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + &State->Late.Delay); if(totalSamples != State->TotalSamples) { @@ -599,11 +593,9 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) /* Update all delays to reflect the new sample buffer. */ RealizeLineOffset(State->SampleBuffer, &State->Delay); RealizeLineOffset(State->SampleBuffer, &State->Early.VecAp.Delay); - for(i = 0;i < 4;i++) - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[i]); + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay); RealizeLineOffset(State->SampleBuffer, &State->Late.VecAp.Delay); - for(i = 0;i < 4;i++) - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[i]); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay); /* Clear the sample buffer. */ for(i = 0;i < State->TotalSamples;i++) @@ -1442,6 +1434,22 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, const ALsizei offset, const A Delay->Line[offset&Delay->Mask] = in; } +static inline ALvoid DelayLineIn4(DelayLine *Delay, ALsizei offset, const ALfloat in[4]) +{ + ALsizei i; + offset = (offset*4) & Delay->Mask; + for(i = 0;i < 4;i++) + Delay->Line[offset+i] = in[i]; +} + +static inline ALvoid DelayLineIn4Rev(DelayLine *Delay, ALsizei offset, const ALfloat in[4]) +{ + ALsizei i; + offset = (offset*4) & Delay->Mask; + for(i = 0;i < 4;i++) + Delay->Line[offset+i] = in[3-i]; +} + static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo) { ALfloat sinus, range; @@ -1554,8 +1562,7 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ \ VectorPartialScatter(f, xCoeff, yCoeff); \ \ - for(i = 0;i < 4;i++) \ - DelayLineIn(&Vap->Delay, offset*4 + i, f[i]); \ + DelayLineIn4(&Vap->Delay, offset, f); \ } DECL_TEMPLATE(Unfaded) DECL_TEMPLATE(Faded) @@ -1614,14 +1621,13 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ &State->Early.VecAp); \ \ - for(j = 0;j < 4;j++) \ - DelayLineIn(&State->Early.Delay[j], offset, f[3 - j]); \ + DelayLineIn4Rev(&State->Early.Delay, offset, f); \ \ for(j = 0;j < 4;j++) \ - f[j] += DELAY_OUT_##T(&State->Early.Delay[j], \ - offset-State->Early.Offset[j][0], \ - offset-State->Early.Offset[j][1], fade) * \ - State->Early.Coeff[j]; \ + f[j] += DELAY_OUT_##T(&State->Early.Delay, \ + (offset-State->Early.Offset[j][0])*4 + j, \ + (offset-State->Early.Offset[j][1])*4 + j, fade \ + ) * State->Early.Coeff[j]; \ \ for(j = 0;j < 4;j++) \ out[j][i] = f[j]; \ @@ -1630,9 +1636,7 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ \ VectorPartialScatter(f, mixX, mixY); \ \ - for(j = 0;j < 4;j++) \ - DelayLineIn(&State->Delay, (offset-State->LateFeedTap)*4 + j, \ - f[j]); \ + DelayLineIn4(&State->Delay, offset-State->LateFeedTap, f); \ \ offset++; \ fade += FadeStep; \ @@ -1715,12 +1719,14 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ ALfloat out0, out1; \ \ /* Get the two samples crossed by the offset delay. */ \ - out0 = DELAY_OUT_##T(&State->Late.Delay[j], \ - delay-State->Late.Offset[j][0], \ - delay-State->Late.Offset[j][1], fade); \ - out1 = DELAY_OUT_##T(&State->Late.Delay[j], \ - delay-State->Late.Offset[j][0]-1, \ - delay-State->Late.Offset[j][1]-1, fade); \ + out0 = DELAY_OUT_##T(&State->Late.Delay, \ + (delay-State->Late.Offset[j][0])*4 + j, \ + (delay-State->Late.Offset[j][1])*4 + j, fade \ + ); \ + out1 = DELAY_OUT_##T(&State->Late.Delay, \ + (delay-State->Late.Offset[j][0]-1)*4 + j, \ + (delay-State->Late.Offset[j][1]-1)*4 + j, fade \ + ); \ \ /* The modulated result is obtained by linearly interpolating the \ * two samples that were acquired above. \ @@ -1741,8 +1747,7 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ \ VectorPartialScatter(f, mixX, mixY); \ \ - for(j = 0;j < 4;j++) \ - DelayLineIn(&State->Late.Delay[j], offset, f[j]); \ + DelayLineIn4(&State->Late.Delay, offset, f); \ \ offset++; \ fade += FadeStep; \ -- cgit v1.2.3 From 2aa620e58fb117b0c94b7c68cf67acce9654b838 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 May 2017 00:30:47 -0700 Subject: Make reverb delay line structs use interleaved floats --- Alc/effects/reverb.c | 141 ++++++++++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 68 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index dd790ee0..ac0c7392 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -59,16 +59,16 @@ static void init_mixfunc(void) MixRowSamples = SelectRowMixer(); } -typedef struct DelayLine { - /* The delay lines use sample lengths that are powers of 2 to allow the - * use of bit-masking instead of a modulus for wrapping. +typedef struct DelayLineI { + /* The delay lines use interleaved samples, with the lengths being powers + * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ ALsizei Mask; - ALfloat *Line; -} DelayLine; + ALfloat (*Line)[4]; +} DelayLineI; typedef struct VecAllpass { - DelayLine Delay; + DelayLineI Delay; ALsizei Offset[4][2]; } VecAllpass; @@ -90,7 +90,7 @@ typedef struct ALreverbState { } Filter[4]; /* Core delay line (early reflections and late reverb tap from this). */ - DelayLine Delay; + DelayLineI Delay; /* Tap points for early reflection delay. */ ALsizei EarlyDelayTap[4][2]; @@ -114,10 +114,10 @@ typedef struct ALreverbState { */ VecAllpass VecAp; - /* Echo lines are used to complete the second half of the early + /* An echo line is used to complete the second half of the early * reflections. */ - DelayLine Delay; + DelayLineI Delay; ALsizei Offset[4][2]; ALfloat Coeff[4]; @@ -145,8 +145,8 @@ typedef struct ALreverbState { */ ALfloat DensityGain; - /* Recursive delay lines are used fill in the reverb tail. */ - DelayLine Delay; + /* A recursive delay line is used fill in the reverb tail. */ + DelayLineI Delay; ALsizei Offset[4][2]; /* T60 decay filters are used to simulate absorption. */ @@ -228,10 +228,10 @@ static void ALreverbState_Construct(ALreverbState *state) state->MixX = 0.0f; state->MixY = 0.0f; - state->Early.Delay.Mask = 0; - state->Early.Delay.Line = NULL; state->Early.VecAp.Delay.Mask = 0; state->Early.VecAp.Delay.Line = NULL; + state->Early.Delay.Mask = 0; + state->Early.Delay.Line = NULL; for(i = 0;i < 4;i++) { state->Early.VecAp.Offset[i][0] = 0; @@ -255,12 +255,12 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.VecAp.Delay.Line = NULL; for(i = 0;i < 4;i++) { - state->Late.VecAp.Offset[i][0] = 0; - state->Late.VecAp.Offset[i][1] = 0; - state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; + state->Late.VecAp.Offset[i][0] = 0; + state->Late.VecAp.Offset[i][1] = 0; + for(j = 0;j < 3;j++) { state->Late.Filters[i].LFCoeffs[j] = 0.0f; @@ -494,14 +494,19 @@ static inline float hack_modff(float x, float *y) /* 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, DelayLineI *Delay) { - Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line]; + union { + ALfloat *f; + ALfloat (*f4)[4]; + } u; + u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * 4]; + Delay->Line = u.f4; } /* Calculate the length of a delay line and store its mask and offset. */ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const ALuint frequency, - const ALuint extra, const ALuint splmult, DelayLine *Delay) + const ALuint extra, DelayLineI *Delay) { ALuint samples; @@ -509,11 +514,11 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const * seconds, rounded up. */ samples = fastf2u(ceilf(length*frequency)); - samples = NextPowerOf2((samples+extra) * splmult); + samples = NextPowerOf2(samples + extra); /* All lines share a single sample buffer. */ Delay->Mask = samples - 1; - Delay->Line = (ALfloat*)offset; + Delay->Line = (ALfloat(*)[4])offset; /* Return the sample count for accumulation. */ return samples; @@ -533,37 +538,36 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) */ totalSamples = 0; + /* Multiplier for the maximum density value, i.e. density=1, which is + * actually the least density... + */ + multiplier = 1.0f + LINE_MULTIPLIER; + /* The main delay length includes the maximum early reflection delay, the * largest early tap width, the maximum late reverb delay, and the * largest late tap width. Finally, it must also be extended by the - * update size (MAX_UPDATE_SAMPLES*4) for block processing. + * update size (MAX_UPDATE_SAMPLES) for block processing. */ - multiplier = 1.0f + LINE_MULTIPLIER; length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[3]*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; - /* Multiply length by 4, since we're storing 4 interleaved channels in the - * main delay line. - */ - totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, 4, + totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Delay); - /* The early all-pass line. Multiply by 4, for 4 interleaved channels. */ - length = (EARLY_ALLPASS_LENGTHS[0]+EARLY_ALLPASS_LENGTHS[1]+ - EARLY_ALLPASS_LENGTHS[2]+EARLY_ALLPASS_LENGTHS[3]) * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + /* The early vector all-pass line. */ + length = EARLY_ALLPASS_LENGTHS[3] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.VecAp.Delay); - /* The early reflection lines. */ + /* The early reflection line. */ length = EARLY_LINE_LENGTHS[3] * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.Delay); - /* The late vector all-pass line. Multiply by 4, for 4 interleaved channels. */ - length = (LATE_ALLPASS_LENGTHS[0]+LATE_ALLPASS_LENGTHS[1]+ - LATE_ALLPASS_LENGTHS[2]+LATE_ALLPASS_LENGTHS[3]) * multiplier; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + /* The late vector all-pass line. */ + length = LATE_ALLPASS_LENGTHS[3] * multiplier; + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.VecAp.Delay); /* The late delay lines are calculated from the larger of the maximum @@ -574,15 +578,15 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) */ length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) + AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; - totalSamples += CalcLineLength(length, totalSamples, frequency, 0, 4, + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay); if(totalSamples != State->TotalSamples) { ALfloat *newBuffer; - TRACE("New reverb buffer length: %u samples\n", totalSamples); - newBuffer = al_calloc(16, sizeof(ALfloat) * totalSamples); + TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); + newBuffer = al_calloc(16, sizeof(ALfloat[4]) * totalSamples); if(!newBuffer) return AL_FALSE; al_free(State->SampleBuffer); @@ -1414,40 +1418,41 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device **************************************/ /* Basic delay line input/output routines. */ -static inline ALfloat DelayLineOut(const DelayLine *Delay, const ALsizei offset) +static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset, const ALsizei c) { - return Delay->Line[offset&Delay->Mask]; + return Delay->Line[offset&Delay->Mask][c]; } /* Cross-faded delay line output routine. Instead of interpolating the * offsets, this interpolates (cross-fades) the outputs at each offset. */ -static inline ALfloat FadedDelayLineOut(const DelayLine *Delay, const ALsizei off0, const ALsizei off1, const ALfloat mu) +static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, + const ALsizei off1, const ALsizei c, const ALfloat mu) { - return lerp(Delay->Line[off0&Delay->Mask], Delay->Line[off1&Delay->Mask], mu); + return lerp(Delay->Line[off0&Delay->Mask][c], Delay->Line[off1&Delay->Mask][c], mu); } -#define DELAY_OUT_Faded(d, o0, o1, mu) FadedDelayLineOut(d, o0, o1, mu) -#define DELAY_OUT_Unfaded(d, o0, o1, mu) DelayLineOut(d, o0) +#define DELAY_OUT_Faded(d, o0, o1, c, mu) FadedDelayLineOut(d, o0, o1, c, mu) +#define DELAY_OUT_Unfaded(d, o0, o1, c, mu) DelayLineOut(d, o0, c) -static inline ALvoid DelayLineIn(DelayLine *Delay, const ALsizei offset, const ALfloat in) +static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const ALsizei c, const ALfloat in) { - Delay->Line[offset&Delay->Mask] = in; + Delay->Line[offset&Delay->Mask][c] = in; } -static inline ALvoid DelayLineIn4(DelayLine *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) { ALsizei i; - offset = (offset*4) & Delay->Mask; + offset &= Delay->Mask; for(i = 0;i < 4;i++) - Delay->Line[offset+i] = in[i]; + Delay->Line[offset][i] = in[i]; } -static inline ALvoid DelayLineIn4Rev(DelayLine *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) { ALsizei i; - offset = (offset*4) & Delay->Mask; + offset &= Delay->Mask; for(i = 0;i < 4;i++) - Delay->Line[offset+i] = in[3-i]; + Delay->Line[offset][i] = in[3-i]; } static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo) @@ -1554,8 +1559,8 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ for(i = 0;i < 4;i++) \ { \ input = vec[i]; \ - vec[i] = DELAY_OUT_##T(&Vap->Delay, (offset-Vap->Offset[i][0])*4 + i, \ - (offset-Vap->Offset[i][1])*4 + i, mu) - \ + vec[i] = DELAY_OUT_##T(&Vap->Delay, offset-Vap->Offset[i][0], \ + offset-Vap->Offset[i][1], i, mu) - \ feedCoeff*input; \ f[i] = input + feedCoeff*vec[i]; \ } \ @@ -1614,8 +1619,8 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ { \ for(j = 0;j < 4;j++) \ f[j] = DELAY_OUT_##T(&State->Delay, \ - (offset-State->EarlyDelayTap[j][0])*4 + j, \ - (offset-State->EarlyDelayTap[j][1])*4 + j, fade \ + offset-State->EarlyDelayTap[j][0], \ + offset-State->EarlyDelayTap[j][1], j, fade \ ) * State->EarlyDelayCoeff[j]; \ \ VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ @@ -1625,8 +1630,8 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ \ for(j = 0;j < 4;j++) \ f[j] += DELAY_OUT_##T(&State->Early.Delay, \ - (offset-State->Early.Offset[j][0])*4 + j, \ - (offset-State->Early.Offset[j][1])*4 + j, fade \ + offset-State->Early.Offset[j][0], \ + offset-State->Early.Offset[j][1], j, fade \ ) * State->Early.Coeff[j]; \ \ for(j = 0;j < 4;j++) \ @@ -1704,8 +1709,8 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ { \ for(j = 0;j < 4;j++) \ f[j] = DELAY_OUT_##T(&State->Delay, \ - (offset-State->LateDelayTap[j][0])*4 + j, \ - (offset-State->LateDelayTap[j][1])*4 + j, fade \ + offset-State->LateDelayTap[j][0], \ + offset-State->LateDelayTap[j][1], j, fade \ ) * State->Late.DensityGain; \ \ /* Separate the integer offset and fraction between it and the next \ @@ -1720,12 +1725,12 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ \ /* Get the two samples crossed by the offset delay. */ \ out0 = DELAY_OUT_##T(&State->Late.Delay, \ - (delay-State->Late.Offset[j][0])*4 + j, \ - (delay-State->Late.Offset[j][1])*4 + j, fade \ + delay-State->Late.Offset[j][0], \ + delay-State->Late.Offset[j][1], j, fade \ ); \ out1 = DELAY_OUT_##T(&State->Late.Delay, \ - (delay-State->Late.Offset[j][0]-1)*4 + j, \ - (delay-State->Late.Offset[j][1]-1)*4 + j, fade \ + delay-State->Late.Offset[j][0]-1, \ + delay-State->Late.Offset[j][1]-1, j, fade \ ); \ \ /* The modulated result is obtained by linearly interpolating the \ @@ -1780,7 +1785,7 @@ static ALfloat VerbPass(ALreverbState *State, const ALsizei todo, ALfloat fade, /* Feed the initial delay line. */ for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[0][i]); + DelayLineIn(&State->Delay, State->Offset+i, c, early[0][i]); } if(fade < 1.0f) @@ -1827,7 +1832,7 @@ static ALfloat EAXVerbPass(ALreverbState *State, const ALsizei todo, ALfloat fad /* Feed the initial delay line. */ for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, (State->Offset+i)*4 + c, early[1][i]); + DelayLineIn(&State->Delay, State->Offset+i, c, early[1][i]); } if(fade < 1.0f) -- cgit v1.2.3 From fecf26318afe3c9a5c04919d5e9c444c606acb68 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 May 2017 17:13:05 -0700 Subject: Improve distance-related absorption and decay attenuation --- Alc/ALu.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e564ee00..a1c8bc70 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1068,6 +1068,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat WetGainLF[MAX_SENDS]; ALfloat dir[3]; ALfloat spread; + ALfloat meters; ALfloat Pitch; ALint i; @@ -1221,30 +1222,28 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Distance-based air absorption */ - if(props->AirAbsorptionFactor > 0.0f && ClampedDist > props->RefDistance) - { - ALfloat meters = (ClampedDist-props->RefDistance) * Listener->Params.MetersPerUnit; + meters = (ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener->Params.MetersPerUnit; + if(meters > 0.0f && props->AirAbsorptionFactor > 0.0f) DryGainHF *= powf(AIRABSORBGAINHF, props->AirAbsorptionFactor*meters); - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= powf(RoomAirAbsorption[i], props->AirAbsorptionFactor*meters); - } - if(props->WetGainAuto) + if(props->WetGainAuto && meters > 0.0f) { - ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f; - /* Apply a decay-time transformation to the wet path, based on the - * attenuation of the dry path. - * - * Using the apparent distance, based on the distance attenuation, the - * initial decay of the reverb effect is calculated and applied to the - * wet path. + * source distance in meters. The initial decay of the reverb effect is + * calculated and applied to the wet path. */ for(i = 0;i < NumSends;i++) { if(DecayDistance[i] > 0.0f) - WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]); + WetGain[i] *= powf(0.001f/*-60dB*/, meters/DecayDistance[i]); } + + /* Yes, the wet path's air absorption is applied with WetGainAuto on, + * rather than WetGainHFAuto. + */ + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= powf(RoomAirAbsorption[i], meters); } /* Calculate directional soundcones */ -- cgit v1.2.3 From 98392fbe904874254c8a9cbdcdbe4168f567705a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 May 2017 17:20:09 -0700 Subject: Limit the dry and wet path filter gains to -60dB --- Alc/ALu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index a1c8bc70..b3e0ee94 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -947,8 +947,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const { ALfloat hfScale = props->Direct.HFReference / Frequency; ALfloat lfScale = props->Direct.LFReference / Frequency; - ALfloat gainHF = maxf(DryGainHF, 0.0625f); /* Limit -24dB */ - ALfloat gainLF = maxf(DryGainLF, 0.0625f); + ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ + ALfloat gainLF = maxf(DryGainLF, 0.001f); for(c = 0;c < num_channels;c++) { voice->Direct.Params[c].FilterType = AF_None; @@ -968,8 +968,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const { ALfloat hfScale = props->Send[i].HFReference / Frequency; ALfloat lfScale = props->Send[i].LFReference / Frequency; - ALfloat gainHF = maxf(WetGainHF[i], 0.0625f); - ALfloat gainLF = maxf(WetGainLF[i], 0.0625f); + ALfloat gainHF = maxf(WetGainHF[i], 0.001f); + ALfloat gainLF = maxf(WetGainLF[i], 0.001f); for(c = 0;c < num_channels;c++) { voice->Send[i].Params[c].FilterType = AF_None; -- cgit v1.2.3 From 154e53b911f08b435f4d9579189400bd15fd5ee0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 May 2017 13:23:16 -0700 Subject: Reduce the main reverb filter gain limit to match the rest --- Alc/effects/reverb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ac0c7392..0d0ca277 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1324,14 +1324,14 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device /* Calculate the master filters */ hfScale = props->Reverb.HFReference / frequency; - /* Restrict the filter gains from going below -40dB to keep the I3DL2 - * model from killing most of the signal. + /* Restrict the filter gains from going below -60dB to keep the filter from + * killing most of the signal. */ - gainhf = maxf(props->Reverb.GainHF, 0.01f); + gainhf = maxf(props->Reverb.GainHF, 0.001f); ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, gainhf, hfScale, calc_rcpQ_from_slope(gainhf, 1.0f)); lfScale = props->Reverb.LFReference / frequency; - gainlf = maxf(props->Reverb.GainLF, 0.01f); + gainlf = maxf(props->Reverb.GainLF, 0.001f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < 4;i++) -- cgit v1.2.3 From a49e2ebbc56e8694a03a150e4210f4070203e43d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 May 2017 16:50:43 -0700 Subject: Add an env var to specify a default pulse device Some apps don't allow selecting an audio device, and due to problems with KDE, PulseAudio isn't allowed to move the stream after being created by default. --- Alc/backends/pulseaudio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 9e2d4f73..43761e23 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -764,6 +764,13 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_stream_state_t state; pa_stream *stream; + if(!device_name) + { + device_name = getenv("ALSOFT_PULSE_DEFAULT"); + if(device_name && !device_name[0]) + device_name = NULL; + } + stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter); if(!stream) { -- cgit v1.2.3 From efd797a6f67d291ef82dd95697b5a1beb17590cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 17 May 2017 22:49:34 -0700 Subject: Reorganize some code to have fewer temporaries --- Alc/ALu.c | 73 +++++++++++++++++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index b3e0ee94..0fca7a73 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1054,12 +1054,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop const ALlistener *Listener = ALContext->Listener; const ALsizei NumSends = Device->NumAuxSends; aluVector Position, Velocity, Direction, SourceToListener; - ALfloat Distance, ClampedDist; - ALfloat DopplerFactor; + ALfloat Distance, ClampedDist, DopplerFactor; ALfloat RoomAirAbsorption[MAX_SENDS]; ALeffectslot *SendSlots[MAX_SENDS]; - ALfloat Attenuation; - ALfloat RoomAttenuation[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; ALfloat DryGain, DryGainHF, DryGainLF; @@ -1072,11 +1069,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat Pitch; ALint i; - Pitch = 1.0f; - aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); - aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); - aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); - + /* Set mixing buffers and get send parameters. */ voice->Direct.Buffer = Device->Dry.Buffer; voice->Direct.Channels = Device->Dry.NumChannels; for(i = 0;i < NumSends;i++) @@ -1120,6 +1113,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Transform source to listener space (convert to head relative) */ + aluVectorSet(&Position, props->Position[0], props->Position[1], props->Position[2], 1.0f); + aluVectorSet(&Direction, props->Direction[0], props->Direction[1], props->Direction[2], 0.0f); + aluVectorSet(&Velocity, props->Velocity[0], props->Velocity[1], props->Velocity[2], 0.0f); if(props->HeadRelative == AL_FALSE) { const aluMatrixf *Matrix = &Listener->Params.Matrix; @@ -1144,12 +1140,20 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop SourceToListener.v[3] = 0.0f; Distance = aluNormalize(SourceToListener.v); + /* Initial source gain */ + DryGain = props->Gain; + DryGainHF = 1.0f; + DryGainLF = 1.0f; + for(i = 0;i < NumSends;i++) + { + WetGain[i] = props->Gain; + WetGainHF[i] = 1.0f; + WetGainLF[i] = 1.0f; + } + /* Calculate distance attenuation */ ClampedDist = Distance; - Attenuation = 1.0f; - for(i = 0;i < NumSends;i++) - RoomAttenuation[i] = 1.0f; switch(Listener->Params.SourceDistanceModel ? props->DistanceModel : Listener->Params.DistanceModel) { @@ -1162,11 +1166,11 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop if(props->RefDistance > 0.0f) { ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); - if(dist > 0.0f) Attenuation = props->RefDistance / dist; + if(dist > 0.0f) DryGain *= props->RefDistance / dist; for(i = 0;i < NumSends;i++) { dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]); - if(dist > 0.0f) RoomAttenuation[i] = props->RefDistance / dist; + if(dist > 0.0f) WetGain[i] *= props->RefDistance / dist; } } break; @@ -1179,14 +1183,14 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop case LinearDistance: if(props->MaxDistance != props->RefDistance) { - Attenuation = props->RolloffFactor * (ClampedDist-props->RefDistance) / + ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / (props->MaxDistance-props->RefDistance); - Attenuation = maxf(1.0f - Attenuation, 0.0f); + DryGain *= maxf(1.0f - attn, 0.0f); for(i = 0;i < NumSends;i++) { - RoomAttenuation[i] = RoomRolloff[i] * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); - RoomAttenuation[i] = maxf(1.0f - RoomAttenuation[i], 0.0f); + attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) / + (props->MaxDistance-props->RefDistance); + WetGain[i] *= maxf(1.0f - attn, 0.0f); } } break; @@ -1199,9 +1203,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop case ExponentDistance: if(ClampedDist > 0.0f && props->RefDistance > 0.0f) { - Attenuation = powf(ClampedDist/props->RefDistance, -props->RolloffFactor); + DryGain *= powf(ClampedDist/props->RefDistance, -props->RolloffFactor); for(i = 0;i < NumSends;i++) - RoomAttenuation[i] = powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); + WetGain[i] *= powf(ClampedDist/props->RefDistance, -RoomRolloff[i]); } break; @@ -1210,17 +1214,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop break; } - /* Source Gain + Attenuation */ - DryGain = props->Gain * Attenuation; - DryGainHF = 1.0f; - DryGainLF = 1.0f; - for(i = 0;i < NumSends;i++) - { - WetGain[i] = props->Gain * RoomAttenuation[i]; - WetGainHF[i] = 1.0f; - WetGainLF[i] = 1.0f; - } - /* Distance-based air absorption */ meters = (ClampedDist-props->RefDistance) * props->RolloffFactor * Listener->Params.MetersPerUnit; @@ -1294,19 +1287,21 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop /* Apply gain and frequency filters */ DryGain = clampf(DryGain, props->MinGain, props->MaxGain); - DryGain *= props->Direct.Gain * Listener->Params.Gain; - DryGain = minf(DryGain, GAIN_MIX_MAX); + DryGain = minf(DryGain*props->Direct.Gain*Listener->Params.Gain, GAIN_MIX_MAX); DryGainHF *= props->Direct.GainHF; DryGainLF *= props->Direct.GainLF; for(i = 0;i < NumSends;i++) { WetGain[i] = clampf(WetGain[i], props->MinGain, props->MaxGain); - WetGain[i] *= props->Send[i].Gain * Listener->Params.Gain; - WetGain[i] = minf(WetGain[i], GAIN_MIX_MAX); + WetGain[i] = minf(WetGain[i]*props->Send[i].Gain*Listener->Params.Gain, GAIN_MIX_MAX); WetGainHF[i] *= props->Send[i].GainHF; WetGainLF[i] *= props->Send[i].GainLF; } + + /* Initial source pitch */ + Pitch = props->Pitch; + /* Calculate velocity-based doppler effect */ DopplerFactor = props->DopplerFactor * Listener->Params.DopplerFactor; if(DopplerFactor > 0.0f) @@ -1328,10 +1323,10 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); } - /* Calculate fixed-point stepping value, based on the pitch, buffer - * frequency, and output frequency. + /* Adjust pitch based on the buffer and output frequencies, and calculate + * fixed-point stepping value. */ - Pitch *= (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency * props->Pitch; + Pitch *= (ALfloat)ALBuffer->Frequency/(ALfloat)Device->Frequency; if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH< Date: Fri, 19 May 2017 18:59:04 -0700 Subject: Apply more proper air absorption to the wet path This properly accounts for the room rolloff factor for normal air absorption (which makes it none by default, like distance attenuation), and uses the reverb's decay time, decay hf ratio, decay hf limit, and room air absorption properties to calculate an initial hf decay with the WetGainAuto flag. This mirrors the behavior of the initial distance decay. --- Alc/ALu.c | 74 +++++++++++++++++++++++++++----------- OpenAL32/Include/alAuxEffectSlot.h | 2 ++ OpenAL32/alAuxEffectSlot.c | 2 ++ 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 0fca7a73..32043cdd 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -337,13 +337,17 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) { slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; + slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; } else { slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; + slot->Params.DecayHFRatio = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; + slot->Params.DecayHFLimit = AL_FALSE; } /* Swap effect states. No need to play with the ref counts since they keep @@ -1059,13 +1063,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; + ALfloat DecayHFDistance[MAX_SENDS]; ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; ALfloat dir[3]; ALfloat spread; - ALfloat meters; ALfloat Pitch; ALint i; @@ -1082,14 +1086,22 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop SendSlots[i] = NULL; RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; RoomAirAbsorption[i] = 1.0f; } else if(SendSlots[i]->Params.AuxSendAuto) { RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; - DecayDistance[i] = SendSlots[i]->Params.DecayTime * - SPEEDOFSOUNDMETRESPERSEC; + DecayDistance[i] = SendSlots[i]->Params.DecayTime * SPEEDOFSOUNDMETRESPERSEC; + DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF; + if(SendSlots[i]->Params.DecayHFLimit && RoomAirAbsorption[i] < 1.0f) + { + ALfloat limitRatio = log10f(0.001f)/*-60 dB*/ / (log10f(RoomAirAbsorption[i]) * + DecayDistance[i]); + limitRatio = minf(limitRatio, SendSlots[i]->Params.DecayHFRatio); + DecayHFDistance[i] = minf(DecayHFDistance[i], limitRatio*DecayDistance[i]); + } } else { @@ -1097,6 +1109,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop * effect slot is the same as the dry path, sans filter effects */ RoomRolloff[i] = props->RolloffFactor; DecayDistance[i] = 0.0f; + DecayHFDistance[i] = 0.0f; RoomAirAbsorption[i] = AIRABSORBGAINHF; } @@ -1215,28 +1228,47 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Distance-based air absorption */ - meters = (ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener->Params.MetersPerUnit; - if(meters > 0.0f && props->AirAbsorptionFactor > 0.0f) - DryGainHF *= powf(AIRABSORBGAINHF, props->AirAbsorptionFactor*meters); - - if(props->WetGainAuto && meters > 0.0f) + if(ClampedDist > props->RefDistance) { - /* Apply a decay-time transformation to the wet path, based on the - * source distance in meters. The initial decay of the reverb effect is - * calculated and applied to the wet path. - */ - for(i = 0;i < NumSends;i++) + ALfloat meters_base = (ClampedDist-props->RefDistance) * Listener->Params.MetersPerUnit; + if(props->AirAbsorptionFactor > 0.0f) { - if(DecayDistance[i] > 0.0f) - WetGain[i] *= powf(0.001f/*-60dB*/, meters/DecayDistance[i]); + ALfloat absorb = props->AirAbsorptionFactor * meters_base; + DryGainHF *= powf(AIRABSORBGAINHF, absorb*props->RolloffFactor); + for(i = 0;i < NumSends;i++) + { + if(RoomRolloff[i] > 0.0f) + WetGainHF[i] *= powf(RoomAirAbsorption[i], absorb*RoomRolloff[i]); + } } - /* Yes, the wet path's air absorption is applied with WetGainAuto on, - * rather than WetGainHFAuto. - */ - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= powf(RoomAirAbsorption[i], meters); + if(props->WetGainAuto) + { + meters_base *= props->RolloffFactor; + + /* Apply a decay-time transformation to the wet path, based on the + * source distance in meters. The initial decay of the reverb + * effect is calculated and applied to the wet path. + */ + for(i = 0;i < NumSends;i++) + { + ALfloat gain; + + if(!(DecayDistance[i] > 0.0f)) + continue; + + gain = powf(0.001f/*-60dB*/, meters_base/DecayDistance[i]); + WetGain[i] *= gain; + /* Yes, the wet path's air absorption is applied with + * WetGainAuto on, rather than WetGainHFAuto. + */ + if(gain > 0.0f) + { + ALfloat gainhf = powf(0.001f/*-60dB*/, meters_base/DecayHFDistance[i]) / gain; + WetGainHF[i] *= minf(gainhf, 1.0f); + } + } + } } /* Calculate directional soundcones */ diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 4eb340a4..7126f8f5 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -121,7 +121,9 @@ typedef struct ALeffectslot { ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ ALfloat DecayTime; + ALfloat DecayHFRatio; ALfloat AirAbsorptionGainHF; + ALboolean DecayHFLimit; } Params; /* Self ID */ diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 5d110500..8a990584 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -615,7 +615,9 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.EffectState = slot->Effect.State; slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; + slot->Params.DecayHFRatio = 0.0f; slot->Params.AirAbsorptionGainHF = 1.0f; + slot->Params.DecayHFLimit = AL_FALSE; return AL_NO_ERROR; } -- cgit v1.2.3 From 492050b8168b04ef6df0030739969685a62d6929 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 May 2017 02:22:11 -0700 Subject: Restore spec-defined cone behavior for auxiliary sends --- Alc/ALu.c | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 32043cdd..dda3d575 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1068,6 +1068,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; + bool directional; ALfloat dir[3]; ALfloat spread; ALfloat Pitch; @@ -1146,7 +1147,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop Velocity.v[2] += lvelocity->v[2]; } - aluNormalize(Direction.v); + directional = aluNormalize(Direction.v) > FLT_EPSILON; SourceToListener.v[0] = -Position.v[0]; SourceToListener.v[1] = -Position.v[1]; SourceToListener.v[2] = -Position.v[2]; @@ -1272,46 +1273,42 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Calculate directional soundcones */ - if(props->InnerAngle < 360.0f) + if(directional && props->InnerAngle < 360.0f) { ALfloat ConeVolume; ALfloat ConeHF; ALfloat Angle; - ALfloat scale; - Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; - if(Angle > props->InnerAngle) + Angle = acosf(aluDotproduct(&Direction, &SourceToListener)); + Angle = RAD2DEG(Angle * ConeScale * 2.0f); + if(!(Angle > props->InnerAngle)) { - if(Angle < props->OuterAngle) - { - scale = (Angle-props->InnerAngle) / (props->OuterAngle-props->InnerAngle); - ConeVolume = lerp(1.0f, props->OuterGain, scale); - ConeHF = lerp(1.0f, props->OuterGainHF, scale); - } - else - { - ConeVolume = props->OuterGain; - ConeHF = props->OuterGainHF; - } - DryGain *= ConeVolume; - if(props->DryGainHFAuto) - DryGainHF *= ConeHF; + ConeVolume = 1.0f; + ConeHF = 1.0f; + } + else if(Angle < props->OuterAngle) + { + ALfloat scale = ( Angle-props->InnerAngle) / + (props->OuterAngle-props->InnerAngle); + ConeVolume = lerp(1.0f, props->OuterGain, scale); + ConeHF = lerp(1.0f, props->OuterGainHF, scale); + } + else + { + ConeVolume = props->OuterGain; + ConeHF = props->OuterGainHF; } - /* Wet path uses the total area of the cone emitter (the room will - * receive the same amount of sound regardless of its direction). - */ - scale = (asinf(maxf((props->OuterAngle-props->InnerAngle)/360.0f, 0.0f)) / F_PI) + - (props->InnerAngle/360.0f); + DryGain *= ConeVolume; + if(props->DryGainHFAuto) + DryGainHF *= ConeHF; if(props->WetGainAuto) { - ConeVolume = lerp(1.0f, props->OuterGain, scale); for(i = 0;i < NumSends;i++) WetGain[i] *= ConeVolume; } if(props->WetGainHFAuto) { - ConeHF = lerp(1.0f, props->OuterGainHF, scale); for(i = 0;i < NumSends;i++) WetGainHF[i] *= ConeHF; } -- cgit v1.2.3 From c234b25ac7ace092867cc3348e7ea2b2754a7284 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 May 2017 03:28:40 -0700 Subject: Use more correct doppler shift calculations --- Alc/ALu.c | 35 ++++++++++++++++++++++++----------- common/math_defs.h | 9 +++++++-- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index dda3d575..c27617f5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1336,20 +1336,33 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop if(DopplerFactor > 0.0f) { const aluVector *lvelocity = &Listener->Params.Velocity; - ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; - ALfloat VSS, VLS; + const ALfloat SpeedOfSound = Listener->Params.SpeedOfSound; + ALfloat vss, vls; - if(SpeedOfSound < 1.0f) + vss = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; + vls = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; + + if(!(vls < SpeedOfSound)) { - DopplerFactor *= 1.0f/SpeedOfSound; - SpeedOfSound = 1.0f; + /* Listener moving away from the source at the speed of sound. + * Sound waves can't catch it. + */ + Pitch = 0.0f; + } + else if(!(vss < SpeedOfSound)) + { + /* Source moving toward the listener at the speed of sound. Sound + * waves bunch up to extreme frequencies. + */ + Pitch = HUGE_VALF; + } + else + { + /* Source and listener movement is nominal. Calculate the proper + * doppler shift. + */ + Pitch *= (SpeedOfSound-vls) / (SpeedOfSound-vss); } - - VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; - VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; - - Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) / - clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); } /* Adjust pitch based on the buffer and output frequencies, and calculate diff --git a/common/math_defs.h b/common/math_defs.h index 149cf80b..8756488c 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -1,6 +1,7 @@ #ifndef AL_MATH_DEFS_H #define AL_MATH_DEFS_H +#include #ifdef HAVE_FLOAT_H #include #endif @@ -13,7 +14,11 @@ #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)) +#ifndef HUGE_VALF +#define HUGE_VALF (1.0f/0.0f) +#endif + +#define DEG2RAD(x) ((float)(x) * (F_PI/180.0f)) +#define RAD2DEG(x) ((float)(x) * (180.0f/F_PI)) #endif /* AL_MATH_DEFS_H */ -- cgit v1.2.3 From 0b2467ed54507f64509dc21f6ba9f2d346ef5628 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 May 2017 00:01:39 -0700 Subject: Use a macro to specify the decay target gain --- Alc/ALu.c | 10 +++++----- Alc/effects/reverb.c | 4 ++-- OpenAL32/Include/alu.h | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index c27617f5..22aca28a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1098,8 +1098,8 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF; if(SendSlots[i]->Params.DecayHFLimit && RoomAirAbsorption[i] < 1.0f) { - ALfloat limitRatio = log10f(0.001f)/*-60 dB*/ / (log10f(RoomAirAbsorption[i]) * - DecayDistance[i]); + ALfloat limitRatio = log10f(REVERB_DECAY_GAIN) / + (log10f(RoomAirAbsorption[i]) * DecayDistance[i]); limitRatio = minf(limitRatio, SendSlots[i]->Params.DecayHFRatio); DecayHFDistance[i] = minf(DecayHFDistance[i], limitRatio*DecayDistance[i]); } @@ -1258,15 +1258,15 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop if(!(DecayDistance[i] > 0.0f)) continue; - gain = powf(0.001f/*-60dB*/, meters_base/DecayDistance[i]); + gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); WetGain[i] *= gain; /* Yes, the wet path's air absorption is applied with * WetGainAuto on, rather than WetGainHFAuto. */ if(gain > 0.0f) { - ALfloat gainhf = powf(0.001f/*-60dB*/, meters_base/DecayHFDistance[i]) / gain; - WetGainHF[i] *= minf(gainhf, 1.0f); + ALfloat gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); + WetGainHF[i] *= minf(gainhf / gain, 1.0f); } } } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0d0ca277..39daff53 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -645,7 +645,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev */ static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTime) { - return powf(0.001f/*-60 dB*/, length/decayTime); + return powf(REVERB_DECAY_GAIN, length/decayTime); } /* Calculate a decay length from a coefficient and the time until the decay @@ -653,7 +653,7 @@ static inline ALfloat CalcDecayCoeff(const ALfloat length, const ALfloat decayTi */ static inline ALfloat CalcDecayLength(const ALfloat coeff, const ALfloat decayTime) { - return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; + return log10f(coeff) * decayTime / log10f(REVERB_DECAY_GAIN); } /* Calculate an attenuation to be applied to the input of any echo models to diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 30b245a5..c44f94d4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -348,6 +348,9 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict #define SPEEDOFSOUNDMETRESPERSEC (343.3f) #define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ +/* Target gain for the reverb decay feedback reaching the decay time. */ +#define REVERB_DECAY_GAIN (0.001f) /* -60 dB */ + #define FRACTIONBITS (12) #define FRACTIONONE (1< Date: Sun, 21 May 2017 02:42:44 -0700 Subject: Avoid unnecessary doubles --- Alc/effects/reverb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 39daff53..2c881512 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -992,8 +992,8 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime { if(mfGain < hfGain) { - double hg = mfGain / lfGain; - double lg = mfGain / hfGain; + ALfloat hg = mfGain / lfGain; + ALfloat lg = mfGain / hfGain; CalcHighShelfCoeffs(hg, lfW, lfcoeffs); CalcLowShelfCoeffs(lg, hfW, hfcoeffs); -- cgit v1.2.3 From 5691dceb38d7dfa6159c9c9b5358d094acc7e8a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 May 2017 03:31:44 -0700 Subject: Add a method to copy a filter's coefficients --- Alc/effects/equalizer.c | 32 ++++---------------------------- Alc/effects/reverb.c | 13 ++----------- OpenAL32/Include/alFilter.h | 9 +++++++++ OpenAL32/alFilter.c | 1 + 4 files changed, 16 insertions(+), 39 deletions(-) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 5e6a2a9a..030eacc9 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -145,13 +145,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - { - state->filter[0][i].b0 = state->filter[0][0].b0; - state->filter[0][i].b1 = state->filter[0][0].b1; - state->filter[0][i].b2 = state->filter[0][0].b2; - state->filter[0][i].a1 = state->filter[0][0].a1; - state->filter[0][i].a2 = state->filter[0][0].a2; - } + ALfilterState_copyParams(&state->filter[0][i], &state->filter[0][0]); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); freq_mult = props->Equalizer.Mid1Center/frequency; @@ -161,13 +155,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - { - state->filter[1][i].b0 = state->filter[1][0].b0; - state->filter[1][i].b1 = state->filter[1][0].b1; - state->filter[1][i].b2 = state->filter[1][0].b2; - state->filter[1][i].a1 = state->filter[1][0].a1; - state->filter[1][i].a2 = state->filter[1][0].a2; - } + ALfilterState_copyParams(&state->filter[1][i], &state->filter[1][0]); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); freq_mult = props->Equalizer.Mid2Center/frequency; @@ -177,13 +165,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * ) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - { - state->filter[2][i].b0 = state->filter[2][0].b0; - state->filter[2][i].b1 = state->filter[2][0].b1; - state->filter[2][i].b2 = state->filter[2][0].b2; - state->filter[2][i].a1 = state->filter[2][0].a1; - state->filter[2][i].a2 = state->filter[2][0].a2; - } + ALfilterState_copyParams(&state->filter[2][i], &state->filter[2][0]); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); freq_mult = props->Equalizer.HighCutoff/frequency; @@ -191,13 +173,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice * gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - { - state->filter[3][i].b0 = state->filter[3][0].b0; - state->filter[3][i].b1 = state->filter[3][0].b1; - state->filter[3][i].b2 = state->filter[3][0].b2; - state->filter[3][i].a1 = state->filter[3][0].a1; - state->filter[3][i].a2 = state->filter[3][0].a2; - } + ALfilterState_copyParams(&state->filter[3][i], &state->filter[3][0]); } static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 2c881512..f5d32d93 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1336,17 +1336,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCdevice *Device gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < 4;i++) { - State->Filter[i].Lp.b0 = State->Filter[0].Lp.b0; - State->Filter[i].Lp.b1 = State->Filter[0].Lp.b1; - State->Filter[i].Lp.b2 = State->Filter[0].Lp.b2; - State->Filter[i].Lp.a1 = State->Filter[0].Lp.a1; - State->Filter[i].Lp.a2 = State->Filter[0].Lp.a2; - - State->Filter[i].Hp.b0 = State->Filter[0].Hp.b0; - State->Filter[i].Hp.b1 = State->Filter[0].Hp.b1; - State->Filter[i].Hp.b2 = State->Filter[0].Hp.b2; - State->Filter[i].Hp.a1 = State->Filter[0].Hp.a1; - State->Filter[i].Hp.a2 = State->Filter[0].Hp.a2; + ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); + ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); } /* Update the main effect delay and associated taps. */ diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 019e40d3..227d50cf 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -77,6 +77,15 @@ inline void ALfilterState_clear(ALfilterState *filter) void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); +inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src) +{ + dst->b0 = src->b0; + dst->b1 = src->b1; + dst->b2 = src->b2; + dst->a1 = src->a1; + dst->a2 = src->a2; +} + void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 855a7c6b..2a2b9621 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -36,6 +36,7 @@ extern inline void UnlockFiltersWrite(ALCdevice *device); extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); +extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); -- cgit v1.2.3 From 95ea3fdd05d55020c056e549c74def62c508e761 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 May 2017 03:38:19 -0700 Subject: Avoid calculating the filter coefficients multiple times --- Alc/ALu.c | 60 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 22aca28a..28dfd7c1 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -953,19 +953,25 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat lfScale = props->Direct.LFReference / Frequency; ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ ALfloat gainLF = maxf(DryGainLF, 0.001f); - for(c = 0;c < num_channels;c++) + + voice->Direct.Params[0].FilterType = AF_None; + if(gainHF != 1.0f) voice->Direct.Params[0].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; + ALfilterState_setParams( + &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) + ); + ALfilterState_setParams( + &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) + ); + for(c = 1;c < num_channels;c++) { - voice->Direct.Params[c].FilterType = AF_None; - if(gainHF != 1.0f) voice->Direct.Params[c].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Direct.Params[c].FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Direct.Params[c].LowPass, ALfilterType_HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); - ALfilterState_setParams( - &voice->Direct.Params[c].HighPass, ALfilterType_LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); + voice->Direct.Params[c].FilterType = voice->Direct.Params[0].FilterType; + ALfilterState_copyParams(&voice->Direct.Params[c].LowPass, + &voice->Direct.Params[0].LowPass); + ALfilterState_copyParams(&voice->Direct.Params[c].HighPass, + &voice->Direct.Params[0].HighPass); } } for(i = 0;i < NumSends;i++) @@ -974,19 +980,25 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat lfScale = props->Send[i].LFReference / Frequency; ALfloat gainHF = maxf(WetGainHF[i], 0.001f); ALfloat gainLF = maxf(WetGainLF[i], 0.001f); - for(c = 0;c < num_channels;c++) + + voice->Send[i].Params[0].FilterType = AF_None; + if(gainHF != 1.0f) voice->Send[i].Params[0].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; + ALfilterState_setParams( + &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, + gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) + ); + ALfilterState_setParams( + &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, + gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) + ); + for(c = 1;c < num_channels;c++) { - voice->Send[i].Params[c].FilterType = AF_None; - if(gainHF != 1.0f) voice->Send[i].Params[c].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Send[i].Params[c].FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Send[i].Params[c].LowPass, ALfilterType_HighShelf, - gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) - ); - ALfilterState_setParams( - &voice->Send[i].Params[c].HighPass, ALfilterType_LowShelf, - gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) - ); + voice->Send[i].Params[c].FilterType = voice->Send[i].Params[0].FilterType; + ALfilterState_copyParams(&voice->Send[i].Params[c].LowPass, + &voice->Send[i].Params[0].LowPass); + ALfilterState_copyParams(&voice->Send[i].Params[c].HighPass, + &voice->Send[i].Params[0].HighPass); } } } -- cgit v1.2.3 From 49e5c535915f52b7888a884f4ed8925682336b28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 May 2017 03:47:52 -0700 Subject: Reduce the amount of variables that hold the same value --- Alc/ALu.c | 14 ++++++-------- Alc/mixer.c | 4 ++-- OpenAL32/Include/alu.h | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 28dfd7c1..7775d160 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -954,9 +954,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat gainHF = maxf(DryGainHF, 0.001f); /* Limit -60dB */ ALfloat gainLF = maxf(DryGainLF, 0.001f); - voice->Direct.Params[0].FilterType = AF_None; - if(gainHF != 1.0f) voice->Direct.Params[0].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Direct.Params[0].FilterType |= AF_HighPass; + voice->Direct.FilterType = AF_None; + if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) @@ -967,7 +967,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ); for(c = 1;c < num_channels;c++) { - voice->Direct.Params[c].FilterType = voice->Direct.Params[0].FilterType; ALfilterState_copyParams(&voice->Direct.Params[c].LowPass, &voice->Direct.Params[0].LowPass); ALfilterState_copyParams(&voice->Direct.Params[c].HighPass, @@ -981,9 +980,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat gainHF = maxf(WetGainHF[i], 0.001f); ALfloat gainLF = maxf(WetGainLF[i], 0.001f); - voice->Send[i].Params[0].FilterType = AF_None; - if(gainHF != 1.0f) voice->Send[i].Params[0].FilterType |= AF_LowPass; - if(gainLF != 1.0f) voice->Send[i].Params[0].FilterType |= AF_HighPass; + voice->Send[i].FilterType = AF_None; + if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; + if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; ALfilterState_setParams( &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) @@ -994,7 +993,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ); for(c = 1;c < num_channels;c++) { - voice->Send[i].Params[c].FilterType = voice->Send[i].Params[0].FilterType; ALfilterState_copyParams(&voice->Send[i].Params[c].LowPass, &voice->Send[i].Params[0].LowPass); ALfilterState_copyParams(&voice->Send[i].Params[c].HighPass, diff --git a/Alc/mixer.c b/Alc/mixer.c index 71714c70..56d65207 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -457,7 +457,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei samples = DoFilters( &parms->LowPass, &parms->HighPass, Device->FilteredData, - ResampledData, DstBufferSize, parms->FilterType + ResampledData, DstBufferSize, voice->Direct.FilterType ); if(!(voice->Flags&VOICE_HAS_HRTF)) { @@ -598,7 +598,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei samples = DoFilters( &parms->LowPass, &parms->HighPass, Device->FilteredData, - ResampledData, DstBufferSize, parms->FilterType + ResampledData, DstBufferSize, voice->Send[send].FilterType ); if(!Counter) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c44f94d4..72b3659c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -144,7 +144,6 @@ typedef struct MixHrtfParams { typedef struct DirectParams { - enum ActiveFilters FilterType; ALfilterState LowPass; ALfilterState HighPass; @@ -163,7 +162,6 @@ typedef struct DirectParams { } DirectParams; typedef struct SendParams { - enum ActiveFilters FilterType; ALfilterState LowPass; ALfilterState HighPass; @@ -279,6 +277,7 @@ typedef struct ALvoice { InterpState ResampleState; struct { + enum ActiveFilters FilterType; DirectParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; @@ -287,6 +286,7 @@ typedef struct ALvoice { } Direct; struct { + enum ActiveFilters FilterType; SendParams Params[MAX_INPUT_CHANNELS]; ALfloat (*Buffer)[BUFFERSIZE]; -- cgit v1.2.3 From e6be113903e9a92734b1885b1506c8940940705f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 May 2017 00:02:04 -0700 Subject: Add an option to dither 8- and 16-bit output --- Alc/ALc.c | 8 ++ Alc/ALu.c | 183 ++++++++++++++++++++++++++++++++++------------ OpenAL32/Include/alMain.h | 4 + OpenAL32/Include/alu.h | 3 + alsoftrc.sample | 6 ++ 5 files changed, 159 insertions(+), 45 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 75c0e957..0861fbb8 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2080,6 +2080,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateClockBase(device); + device->DitherSeed = DITHER_RNG_SEED; + /************************************************************************* * Update device format request if HRTF is requested */ @@ -4015,6 +4017,10 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ERR("Unsupported ambi-format: %s\n", fmt); } + device->DitherEnabled = GetConfigValueBool( + alstr_get_cstr(device->DeviceName), NULL, "dither", 1 + ); + if(DefaultEffect.type != AL_EFFECT_NULL) { device->DefaultSlot = (ALeffectslot*)device->_slot_mem; @@ -4433,6 +4439,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN // Open the "backend" V(device->Backend,open)("Loopback"); + device->DitherEnabled = GetConfigValueBool(NULL, NULL, "dither", 1); + { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { diff --git a/Alc/ALu.c b/Alc/ALu.c index 7775d160..a297292f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -151,6 +151,27 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) } +/* Prior to VS2013, MSVC lacks the round() family of functions. */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +static long lroundf(float val) +{ + if(val < 0.0) + return fastf2i(ceilf(val-0.5f)); + return fastf2i(floorf(val+0.5f)); +} +#endif + +/* This RNG method was created based on the math found in opusdec. It's quick, + * and starting with a seed value of 22222, is suitable for generating + * whitenoise. + */ +static inline ALuint dither_rng(ALuint *seed) +{ + *seed = (*seed * 96314165) + 907633515; + return *seed; +} + + static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) { outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; @@ -1544,37 +1565,57 @@ static void ApplyLimiter(struct OutputLimiter *Limiter, } } -static inline ALfloat aluF2F(ALfloat val) -{ return val; } -#define S25_MAX_NORM (16777215.0f/16777216.0f) -static inline ALint aluF2I(ALfloat val) +/* NOTE: Non-dithered conversions have unused extra parameters. */ +static inline ALfloat aluF2F(ALfloat val, ...) +{ return val; } +static inline ALint aluF2I(ALfloat val, ...) { /* Floats only have a 24-bit mantissa, so [-16777216, +16777216] is the max * integer range normalized floats can be safely converted to (a bit of the * exponent helps out, effectively giving 25 bits). */ - return fastf2i(clampf(val, -1.0f, S25_MAX_NORM)*16777216.0f)<<7; + return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; +} +static inline ALshort aluF2S(ALfloat val, ...) +{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } +static inline ALbyte aluF2B(ALfloat val, ...) +{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } + +/* Dithered conversion functions. Only applies to 8- and 16-bit output for now, + * as 32-bit int and float are at the limits of the rendered sample depth. This + * can change if the dithering bit depth becomes configurable (effectively + * quantizing to a lower bit depth than the output is capable of). + */ +static inline ALshort aluF2SDithered(ALfloat val, const ALfloat dither_val) +{ + val = val*32768.0f + dither_val; + return lroundf(clampf(val, -32768.0f, 32767.0f)); +} +static inline ALbyte aluF2BDithered(ALfloat val, const ALfloat dither_val) +{ + val = val*128.0f + dither_val; + return lroundf(clampf(val, -128.0f, 127.0f)); } -static inline ALuint aluF2UI(ALfloat val) -{ return aluF2I(val)+2147483648u; } - -#define S16_MAX_NORM (32767.0f/32768.0f) -static inline ALshort aluF2S(ALfloat val) -{ return fastf2i(clampf(val, -1.0f, S16_MAX_NORM)*32768.0f); } -static inline ALushort aluF2US(ALfloat val) -{ return aluF2S(val)+32768; } - -#define S8_MAX_NORM (127.0f/128.0f) -static inline ALbyte aluF2B(ALfloat val) -{ return fastf2i(clampf(val, -1.0f, S8_MAX_NORM)*128.0f); } -static inline ALubyte aluF2UB(ALfloat val) -{ return aluF2B(val)+128; } - -#define DECL_TEMPLATE(T, func) \ -static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - DistanceComp *distcomp, ALsizei SamplesToDo, \ - ALsizei numchans) \ + +/* Define unsigned output variations. */ +#define DECL_TEMPLATE(T, Name, func, O) \ +static inline T Name(ALfloat val, const ALfloat dither_val) \ +{ return func(val, dither_val)+O; } + +DECL_TEMPLATE(ALubyte, aluF2UB, aluF2B, 128) +DECL_TEMPLATE(ALushort, aluF2US, aluF2S, 32768) +DECL_TEMPLATE(ALuint, aluF2UI, aluF2I, 2147483648u) +DECL_TEMPLATE(ALubyte, aluF2UBDithered, aluF2BDithered, 128) +DECL_TEMPLATE(ALushort, aluF2USDithered, aluF2SDithered, 32768) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T, D, func) \ +static void Write##T##D(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ + DistanceComp *distcomp, \ + const ALfloat *restrict DitherValues, \ + ALsizei SamplesToDo, ALsizei numchans) \ { \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ @@ -1589,15 +1630,15 @@ static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ if(SamplesToDo >= base) \ { \ for(i = 0;i < base;i++) \ - out[i*numchans] = func(distbuf[i]*gain); \ + out[i*numchans] = func(distbuf[i]*gain, DitherValues[i]); \ for(;i < SamplesToDo;i++) \ - out[i*numchans] = func(in[i-base]*gain); \ + out[i*numchans] = func(in[i-base]*gain, DitherValues[i]); \ memcpy(distbuf, &in[SamplesToDo-base], base*sizeof(ALfloat)); \ } \ else \ { \ for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(distbuf[i]*gain); \ + out[i*numchans] = func(distbuf[i]*gain, DitherValues[i]); \ memmove(distbuf, distbuf+SamplesToDo, \ (base-SamplesToDo)*sizeof(ALfloat)); \ memcpy(distbuf+base-SamplesToDo, in, \ @@ -1605,17 +1646,22 @@ static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ } \ } \ else for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(in[i]); \ + out[i*numchans] = func(in[i], DitherValues[i]); \ } \ } -DECL_TEMPLATE(ALfloat, aluF2F) -DECL_TEMPLATE(ALuint, aluF2UI) -DECL_TEMPLATE(ALint, aluF2I) -DECL_TEMPLATE(ALushort, aluF2US) -DECL_TEMPLATE(ALshort, aluF2S) -DECL_TEMPLATE(ALubyte, aluF2UB) -DECL_TEMPLATE(ALbyte, aluF2B) +DECL_TEMPLATE(ALfloat, /*no dither*/, aluF2F) +DECL_TEMPLATE(ALuint, /*no dither*/, aluF2UI) +DECL_TEMPLATE(ALint, /*no dither*/, aluF2I) +DECL_TEMPLATE(ALushort, /*no dither*/, aluF2US) +DECL_TEMPLATE(ALshort, /*no dither*/, aluF2S) +DECL_TEMPLATE(ALubyte, /*no dither*/, aluF2UB) +DECL_TEMPLATE(ALbyte, /*no dither*/, aluF2B) + +DECL_TEMPLATE(ALushort, _Dithered, aluF2USDithered) +DECL_TEMPLATE(ALshort, _Dithered, aluF2SDithered) +DECL_TEMPLATE(ALubyte, _Dithered, aluF2UBDithered) +DECL_TEMPLATE(ALbyte, _Dithered, aluF2BDithered) #undef DECL_TEMPLATE @@ -1792,6 +1838,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALsizei OutChannels = device->RealOut.NumChannels; struct OutputLimiter *Limiter = device->Limiter; DistanceComp *DistComp; + ALfloat *DitherValues; if(Limiter) { @@ -1804,33 +1851,79 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ); } + /* Dithering. Step 1, generate whitenoise (uniform distribution of + * random values between -1 and +1). Use NFCtrlData for random + * value storage. Step 2 is to add the noise to the samples, before + * rounding and after scaling up to the desired quantization depth, + * which occurs in the sample conversion stage. + */ + if(!device->DitherEnabled) + memset(device->NFCtrlData, 0, SamplesToDo*sizeof(ALfloat)); + else + { + ALuint dither_seed = device->DitherSeed; + ALsizei i; + + for(i = 0;i < SamplesToDo;i++) + { + ALuint rng0 = dither_rng(&dither_seed); + ALuint rng1 = dither_rng(&dither_seed); + device->NFCtrlData[i] = (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); + } + device->DitherSeed = dither_seed; + } + DitherValues = device->NFCtrlData; + DistComp = device->ChannelDelay; -#define WRITE(T, a, b, c, d, e) do { \ - Write_##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \ - buffer = (T*)buffer + (d)*(e); \ +#define WRITE(T, D, a, b, c, d, e, f) do { \ + Write##T##D(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e), (f)); \ + buffer = (T*)buffer + (e)*(f); \ } while(0) switch(device->FmtType) { case DevFmtByte: - WRITE(ALbyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + if(device->DitherEnabled) + WRITE(ALbyte, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); + else + WRITE(ALbyte, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtUByte: - WRITE(ALubyte, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + if(device->DitherEnabled) + WRITE(ALubyte, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); + else + WRITE(ALubyte, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtShort: - WRITE(ALshort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + if(device->DitherEnabled) + WRITE(ALshort, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); + else + WRITE(ALshort, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtUShort: - WRITE(ALushort, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + if(device->DitherEnabled) + WRITE(ALushort, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); + else + WRITE(ALushort, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtInt: - WRITE(ALint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + WRITE(ALint, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtUInt: - WRITE(ALuint, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + WRITE(ALuint, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; case DevFmtFloat: - WRITE(ALfloat, OutBuffer, buffer, DistComp, SamplesToDo, OutChannels); + WRITE(ALfloat, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + SamplesToDo, OutChannels); break; } #undef WRITE diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ec65c8fc..bbc24f89 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -798,6 +798,10 @@ struct ALCdevice_struct /* Delay buffers used to compensate for speaker distances. */ DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; + /* Dithering control. */ + bool DitherEnabled; + ALuint DitherSeed; + /* Running count of the mixer invocations, in 31.1 fixed point. This * actually increments *twice* when mixing, first at the start and then at * the end, so the bottom bit indicates if the device is currently mixing diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 72b3659c..8a56ddb2 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -40,6 +40,9 @@ struct ALvoice; struct ALeffectslot; +#define DITHER_RNG_SEED 22222 + + enum SpatializeMode { SpatializeOff = AL_FALSE, SpatializeOn = AL_TRUE, diff --git a/alsoftrc.sample b/alsoftrc.sample index e8a28479..26d494f9 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -187,6 +187,12 @@ # noise. #output-limiter = true +## dither: +# Applies dithering on the final mix for 8- and 16-bit output. This replaces +# the distortion created by nearest-value quantization with low-level +# whitenoise. +#dither = true + ## volume-adjust: # A global volume adjustment for source output, expressed in decibels. The # value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will -- cgit v1.2.3 From dd6c5270b6e9dd041dd7560e4836d269482fa5b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 May 2017 01:12:49 -0700 Subject: Add a dithering option to alsoft-config --- utils/alsoft-config/mainwindow.cpp | 16 ++++++++++++++++ utils/alsoft-config/mainwindow.ui | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 4f16726f..a743ca6a 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -329,6 +329,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->stereoEncodingComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); connect(ui->outputLimiterCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->outputDitherCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -654,6 +655,13 @@ void MainWindow::loadConfig(const QString &fname) settings.value("output-limiter").toBool() ? Qt::Checked : Qt::Unchecked ); + if(settings.value("dither").isNull()) + ui->outputDitherCheckBox->setCheckState(Qt::PartiallyChecked); + else + ui->outputDitherCheckBox->setCheckState( + settings.value("dither").toBool() ? Qt::Checked : Qt::Unchecked + ); + QString stereopan = settings.value("stereo-encoding").toString(); ui->stereoEncodingComboBox->setCurrentIndex(0); if(stereopan.isEmpty() == false) @@ -917,6 +925,14 @@ void MainWindow::saveConfig(const QString &fname) const else if(limiter == Qt::Unchecked) settings.setValue("output-limiter", QString("false")); + Qt::CheckState dither = ui->outputDitherCheckBox->checkState(); + if(dither == Qt::PartiallyChecked) + settings.setValue("dither", QString()); + else if(dither == Qt::Checked) + settings.setValue("dither", QString("true")); + else if(dither == Qt::Unchecked) + settings.setValue("dither", QString("false")); + settings.setValue("decoder/hq-mode", ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) ); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 153bcc04..23d7573a 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -504,6 +504,27 @@ avoiding excessive clipping noise. true + + + + 270 + 160 + 261 + 21 + + + + Applies dithering on the final mix for 8- and 16-bit output. +This replaces the distortion created by nearest-value +quantization with low-level whitenoise. + + + Enable Dithering + + + true + + -- cgit v1.2.3 From 2266fb76b9c7e75d513a8eee871063b667f1d815 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 May 2017 18:12:45 -0700 Subject: Add a config option to specify custom ALSA devices --- Alc/backends/alsa.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 40b68779..79f2795a 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -277,10 +277,44 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); alstr_copy_cstr(&entry.name, alsaDevice); - alstr_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? - "device" : "capture", "default")); + alstr_copy_cstr(&entry.device_name, GetConfigValue( + NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default" + )); VECTOR_PUSH_BACK(*DeviceList, entry); + if(stream == SND_PCM_STREAM_PLAYBACK) + { + const char *customdevs, *sep, *next; + next = GetConfigValue(NULL, "alsa", "custom-devices", ""); + while((customdevs=next) != NULL && customdevs[0]) + { + next = strchr(customdevs, ';'); + sep = strchr(customdevs, '='); + if(!sep) + { + al_string spec = AL_STRING_INIT_STATIC(); + if(next) + alstr_copy_range(&spec, customdevs, next++); + else + alstr_copy_cstr(&spec, customdevs); + ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec)); + alstr_reset(&spec); + continue; + } + + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.device_name); + alstr_copy_range(&entry.name, customdevs, sep++); + if(next) + alstr_copy_range(&entry.device_name, sep, next++); + else + alstr_copy_cstr(&entry.device_name, sep); + TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), + alstr_get_cstr(entry.device_name)); + VECTOR_PUSH_BACK(*DeviceList, entry); + } + } + card = -1; if((err=snd_card_next(&card)) < 0) ERR("Failed to find a card: %s\n", snd_strerror(err)); @@ -325,7 +359,8 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) snd_pcm_info_set_device(pcminfo, dev); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); - if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { + if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) + { if(err != -ENOENT) ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); continue; @@ -337,9 +372,9 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) ConfigValueStr(NULL, "alsa", name, &device_prefix); snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", - cardname, devname, cardid, dev); + cardname, devname, cardid, dev); snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d", - device_prefix, cardid, dev); + device_prefix, cardid, dev); TRACE("Got device \"%s\", \"%s\"\n", name, device); AL_STRING_INIT(entry.name); -- cgit v1.2.3 From c68a537ae8fd358856170112938359a743f1899e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 May 2017 04:14:19 -0700 Subject: Update ChangeLog for the limiter and dithering --- ChangeLog | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87efeae7..716fbb13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,11 @@ openal-soft-1.18.0: Currently only applies when using the high-quality ambisonic decoder or ambisonic output, with appropriate config options. + Implemented an output limiter to reduce the amount of distortion from + clipping. + + Implemented dithering for 8-bit and 16-bit output. + Implemented a config option to select a preferred HRTF. Implemented a run-time check for NEON extensions using /proc/cpuinfo. @@ -71,9 +76,6 @@ openal-soft-1.18.0: Improved performance of certain filter uses. - Altered cone behavior for automatic auxiliary send gain and gainhf - management. Now better represents the energy the room receives. - Removed support for the AL_SOFT_buffer_samples and AL_SOFT_buffer_sub_data extensions. Due to conflicts with AL_EXT_SOURCE_RADIUS. -- cgit v1.2.3 From 9d4f601a8a71afbcc7b889a78e55fb9c714d289a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 May 2017 23:21:08 -0700 Subject: Apply distance compensation separately --- Alc/ALu.c | 109 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index a297292f..fec31b34 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1494,6 +1494,50 @@ static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray } +static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp *distcomp, + ALfloat *restrict Values, ALsizei SamplesToDo, ALsizei numchans) +{ + ALsizei i, c; + + Values = ASSUME_ALIGNED(Values, 16); + for(c = 0;c < numchans;c++) + { + ALfloat *restrict inout = ASSUME_ALIGNED(Samples[c], 16); + const ALfloat gain = distcomp[c].Gain; + const ALsizei base = distcomp[c].Length; + ALfloat *restrict distbuf = ASSUME_ALIGNED(distcomp[c].Buffer, 16); + + if(base == 0) + { + if(gain < 1.0f) + { + for(i = 0;i < SamplesToDo;i++) + inout[i] *= gain; + } + continue; + } + + if(SamplesToDo >= base) + { + for(i = 0;i < base;i++) + Values[i] = distbuf[i]; + for(;i < SamplesToDo;i++) + Values[i] = inout[i-base]; + memcpy(distbuf, &inout[SamplesToDo-base], base*sizeof(ALfloat)); + } + else + { + for(i = 0;i < SamplesToDo;i++) + Values[i] = distbuf[i]; + memmove(distbuf, distbuf+SamplesToDo, (base-SamplesToDo)*sizeof(ALfloat)); + memcpy(distbuf+base-SamplesToDo, inout, SamplesToDo*sizeof(ALfloat)); + } + for(i = 0;i < SamplesToDo;i++) + inout[i] = Values[i]*gain; + } +} + + static_assert(LIMITER_VALUE_MAX < (UINT_MAX/LIMITER_WINDOW_SIZE), "LIMITER_VALUE_MAX is too big"); static void ApplyLimiter(struct OutputLimiter *Limiter, @@ -1613,39 +1657,16 @@ DECL_TEMPLATE(ALushort, aluF2USDithered, aluF2SDithered, 32768) #define DECL_TEMPLATE(T, D, func) \ static void Write##T##D(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - DistanceComp *distcomp, \ - const ALfloat *restrict DitherValues, \ - ALsizei SamplesToDo, ALsizei numchans) \ + const ALfloat *restrict DitherValues, \ + ALsizei SamplesToDo, ALsizei numchans) \ { \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ { \ const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \ T *restrict out = (T*)OutBuffer + j; \ - const ALfloat gain = distcomp[j].Gain; \ - const ALsizei base = distcomp[j].Length; \ - ALfloat *restrict distbuf = ASSUME_ALIGNED(distcomp[j].Buffer, 16); \ - if(base > 0 || gain != 1.0f) \ - { \ - if(SamplesToDo >= base) \ - { \ - for(i = 0;i < base;i++) \ - out[i*numchans] = func(distbuf[i]*gain, DitherValues[i]); \ - for(;i < SamplesToDo;i++) \ - out[i*numchans] = func(in[i-base]*gain, DitherValues[i]); \ - memcpy(distbuf, &in[SamplesToDo-base], base*sizeof(ALfloat)); \ - } \ - else \ - { \ - for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(distbuf[i]*gain, DitherValues[i]); \ - memmove(distbuf, distbuf+SamplesToDo, \ - (base-SamplesToDo)*sizeof(ALfloat)); \ - memcpy(distbuf+base-SamplesToDo, in, \ - SamplesToDo*sizeof(ALfloat)); \ - } \ - } \ - else for(i = 0;i < SamplesToDo;i++) \ + \ + for(i = 0;i < SamplesToDo;i++) \ out[i*numchans] = func(in[i], DitherValues[i]); \ } \ } @@ -1837,9 +1858,12 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; struct OutputLimiter *Limiter = device->Limiter; - DistanceComp *DistComp; ALfloat *DitherValues; + /* Use NFCtrlData for temp value storage. */ + ApplyDistanceComp(OutBuffer, device->ChannelDelay, device->NFCtrlData, + SamplesToDo, OutChannels); + if(Limiter) { const ALfloat AttackRate = powf(0.0001f, 1.0f/(device->Frequency*Limiter->AttackRate)); @@ -1874,55 +1898,54 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) } DitherValues = device->NFCtrlData; - DistComp = device->ChannelDelay; -#define WRITE(T, D, a, b, c, d, e, f) do { \ - Write##T##D(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e), (f)); \ - buffer = (T*)buffer + (e)*(f); \ +#define WRITE(T, D, a, b, c, d, e) do { \ + Write##T##D(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \ + buffer = (T*)buffer + (d)*(e); \ } while(0) switch(device->FmtType) { case DevFmtByte: if(device->DitherEnabled) - WRITE(ALbyte, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALbyte, _Dithered, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); else - WRITE(ALbyte, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALbyte, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtUByte: if(device->DitherEnabled) - WRITE(ALubyte, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALubyte, _Dithered, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); else - WRITE(ALubyte, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALubyte, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtShort: if(device->DitherEnabled) - WRITE(ALshort, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALshort, _Dithered, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); else - WRITE(ALshort, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALshort, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtUShort: if(device->DitherEnabled) - WRITE(ALushort, _Dithered, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALushort, _Dithered, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); else - WRITE(ALushort, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALushort, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtInt: - WRITE(ALint, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALint, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtUInt: - WRITE(ALuint, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALuint, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; case DevFmtFloat: - WRITE(ALfloat, /*no dither*/, OutBuffer, buffer, DistComp, DitherValues, + WRITE(ALfloat, /*no dither*/, OutBuffer, buffer, DitherValues, SamplesToDo, OutChannels); break; } -- cgit v1.2.3 From db90dbe9f2136ddfab63e2145ae6914ccdc82cc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 May 2017 04:16:07 -0700 Subject: Finalize ALC_SOFT_output_limiter --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 5 ----- include/AL/alext.h | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0861fbb8..0e821b35 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -782,7 +782,7 @@ 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_SOFTX_device_clock ALC_SOFT_HRTF " - "ALC_SOFT_loopback ALC_SOFTX_output_limiter ALC_SOFT_pause_device"; + "ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device"; static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bbc24f89..2ce98745 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -139,11 +139,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif #endif -#ifndef ALC_SOFT_output_limiter -#define ALC_SOFT_output_limiter -#define ALC_OUTPUT_LIMITER_SOFT 0x199A -#endif - #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/include/AL/alext.h b/include/AL/alext.h index ac422e25..4b9a1553 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -454,6 +454,11 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #define AL_AUTO_SOFT 0x0002 #endif +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 59d016dfcded9211f8342f39b619502487228401 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 May 2017 04:17:09 -0700 Subject: Update ChangeLog about ALC_SOFT_output_limiter --- ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 716fbb13..c6646098 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,8 +2,8 @@ openal-soft-1.18.0: Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. - Implemented the AL_SOFT_gain_clamp_ex, AL_SOFT_source_resampler, and - AL_SOFT_source_spatialize extensions. + Implemented the AL_SOFT_gain_clamp_ex, AL_SOFT_source_resampler, + AL_SOFT_source_spatialize, and ALC_SOFT_output_limiter extensions. Implemented 3D processing for some effects. Currently implemented for Reverb, Compressor, Equalizer, and Ring Modulator. -- cgit v1.2.3 From 2b14c1d62389f3bb8fe52cac9b8d3cc97da0838f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 May 2017 08:40:32 -0700 Subject: Properly handle the chorus and flanger LFOs The effects' specified delay is the average delay time, meaning the delay offset should move between -n and +n relative to the delay, where n <= delay. --- Alc/effects/chorus.c | 27 +++++++++++++++------------ Alc/effects/flanger.c | 27 +++++++++++++++------------ 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index df8721b3..21db73f6 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -91,7 +91,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev ALsizei maxlen; ALsizei it; - maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1; + maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) @@ -131,9 +131,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device state->waveform = CWF_Sinusoid; break; } - state->depth = props->Chorus.Depth; state->feedback = props->Chorus.Feedback; state->delay = fastf2i(props->Chorus.Delay * frequency); + /* The LFO depth is scaled to be relative to the sample delay. */ + state->depth = props->Chorus.Depth * state->delay; /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); @@ -172,13 +173,13 @@ static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset { ALfloat lfo_value; - lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth * state->delay; + lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *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; + lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *delay_right = fastf2i(lfo_value) + state->delay; } @@ -186,13 +187,13 @@ static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset { ALfloat lfo_value; - lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth * state->delay; + lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *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; + lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *delay_right = fastf2i(lfo_value) + state->delay; } @@ -212,11 +213,13 @@ static void Process##Func(ALchorusState *state, const ALsizei SamplesToDo, \ ALint delay_left, delay_right; \ Func(&delay_left, &delay_right, offset, state); \ \ + leftbuf[offset&bufmask] = SamplesIn[it]; \ out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \ - leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \ + leftbuf[offset&bufmask] += out[it][0] * feedback; \ \ + rightbuf[offset&bufmask] = SamplesIn[it]; \ out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \ - rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \ + rightbuf[offset&bufmask] += out[it][1] * feedback; \ \ offset++; \ } \ diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 346478e4..5593d549 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -91,7 +91,7 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D ALsizei maxlen; ALsizei it; - maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1; + maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 2.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) @@ -131,9 +131,10 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi state->waveform = FWF_Sinusoid; break; } - state->depth = props->Flanger.Depth; state->feedback = props->Flanger.Feedback; state->delay = fastf2i(props->Flanger.Delay * frequency); + /* The LFO depth is scaled to be relative to the sample delay. */ + state->depth = props->Flanger.Depth * state->delay; /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); @@ -172,13 +173,13 @@ static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset { ALfloat lfo_value; - lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth * state->delay; + lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *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; + lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *delay_right = fastf2i(lfo_value) + state->delay; } @@ -186,13 +187,13 @@ static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset { ALfloat lfo_value; - lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth * state->delay; + lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *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; + lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); + lfo_value *= state->depth; *delay_right = fastf2i(lfo_value) + state->delay; } @@ -212,11 +213,13 @@ static void Process##Func(ALflangerState *state, const ALsizei SamplesToDo, \ ALint delay_left, delay_right; \ Func(&delay_left, &delay_right, offset, state); \ \ + leftbuf[offset&bufmask] = SamplesIn[it]; \ out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \ - leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback; \ + leftbuf[offset&bufmask] += out[it][0] * feedback; \ \ + rightbuf[offset&bufmask] = SamplesIn[it]; \ out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \ - rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback; \ + rightbuf[offset&bufmask] += out[it][1] * feedback; \ \ offset++; \ } \ -- cgit v1.2.3 From 653f0a1405b5dbceab6c2d8adc8fa246bdb5f607 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 May 2017 09:07:27 -0700 Subject: Fix handling chorus and flanger LFO displacement offset The phase offset is modulo-wrapped rather than masked, so it's best to avoid negative offsets. --- Alc/effects/chorus.c | 5 ++++- Alc/effects/flanger.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 21db73f6..62f2e531 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -165,7 +165,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device } /* Calculate lfo phase displacement */ - state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); + if(phase >= 0) + state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); + else + state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f)); } } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index 5593d549..d330511a 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -165,7 +165,10 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi } /* Calculate lfo phase displacement */ - state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); + if(phase >= 0) + state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f)); + else + state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f)); } } -- cgit v1.2.3 From c4ef7399f84f4085ceb77f9897f9c9502d2cfd0d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 May 2017 03:36:34 -0700 Subject: Add a new compressor/limiter This is just for the output limiter right now, but in the future can be used for the compressor EFX effect. The parameters are also hardcoded, but can be made configurable after 1.18. --- Alc/ALc.c | 21 +++- Alc/ALu.c | 95 +---------------- Alc/mastering.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alMain.h | 32 +++++- OpenAL32/Include/alu.h | 22 ---- 6 files changed, 305 insertions(+), 121 deletions(-) create mode 100644 Alc/mastering.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 0e821b35..dcda29c3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1738,6 +1738,12 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } +struct Compressor *CreateDeviceLimiter(const ALCdevice *device) +{ + return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_TRUE, 0.0f, 0.0f, 0.5f, 2.0f, + 0.0f, -0.5f, 3.0f, device->Frequency); +} + /* UpdateClockBase * * Updates the device's base clock time with however many samples have been @@ -2224,8 +2230,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ if(gainLimiter != ALC_FALSE) { - if(!device->Limiter) - device->Limiter = alloc_limiter(); + if(!device->Limiter || device->Frequency != GetCompressorSampleRate(device->Limiter)) + { + al_free(device->Limiter); + device->Limiter = CreateDeviceLimiter(device); + } } else { @@ -3845,7 +3854,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - device->Limiter = alloc_limiter(); + device->Limiter = NULL; device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); @@ -4021,6 +4030,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) alstr_get_cstr(device->DeviceName), NULL, "dither", 1 ); + device->Limiter = CreateDeviceLimiter(device); + if(DefaultEffect.type != AL_EFFECT_NULL) { device->DefaultSlot = (ALeffectslot*)device->_slot_mem; @@ -4378,7 +4389,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->FOAOut.NumChannels = 0; device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - device->Limiter = alloc_limiter(); + device->Limiter = NULL; device->AvgSpeakerDist = 0.0f; ATOMIC_INIT(&device->ContextList, NULL); @@ -4441,6 +4452,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->DitherEnabled = GetConfigValueBool(NULL, NULL, "dither", 1); + device->Limiter = CreateDeviceLimiter(device); + { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { diff --git a/Alc/ALu.c b/Alc/ALu.c index fec31b34..103d7962 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -100,17 +100,6 @@ const aluMatrixf IdentityMatrixf = {{ }}; -struct OutputLimiter *alloc_limiter(void) -{ - struct OutputLimiter *limiter = al_calloc(16, sizeof(*limiter)); - /* Limiter attack drops -80dB in 50ms. */ - limiter->AttackRate = 0.05f; - /* Limiter release raises +80dB in 1s. */ - limiter->ReleaseRate = 1.0f; - limiter->Gain = 1.0f; - return limiter; -} - void DeinitVoice(ALvoice *voice) { struct ALvoiceProps *props; @@ -1538,78 +1527,6 @@ static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp } -static_assert(LIMITER_VALUE_MAX < (UINT_MAX/LIMITER_WINDOW_SIZE), "LIMITER_VALUE_MAX is too big"); - -static void ApplyLimiter(struct OutputLimiter *Limiter, - ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALsizei NumChans, - const ALfloat AttackRate, const ALfloat ReleaseRate, - ALfloat *restrict Values, const ALsizei SamplesToDo) -{ - bool do_limit = false; - ALsizei c, i; - - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - Values = ASSUME_ALIGNED(Values, 16); - - for(i = 0;i < SamplesToDo;i++) - Values[i] = 0.0f; - - /* First, find the maximum amplitude (squared) for each sample position in each channel. */ - for(c = 0;c < NumChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - { - ALfloat amp = OutBuffer[c][i]; - Values[i] = maxf(Values[i], amp*amp); - } - } - - /* Next, calculate the gains needed to limit the output. */ - { - ALfloat lastgain = Limiter->Gain; - ALsizei wpos = Limiter->Pos; - ALuint sum = Limiter->SquaredSum; - ALfloat gain, rms; - - for(i = 0;i < SamplesToDo;i++) - { - sum -= Limiter->Window[wpos]; - Limiter->Window[wpos] = fastf2u(minf(Values[i]*65536.0f, LIMITER_VALUE_MAX)); - sum += Limiter->Window[wpos]; - - rms = sqrtf((ALfloat)sum / ((ALfloat)LIMITER_WINDOW_SIZE*65536.0f)); - - /* Clamp the minimum RMS to 0dB. The uint used for the squared sum - * inherently limits the maximum RMS to about 21dB, thus the gain - * ranges from 0dB to -21dB. - */ - gain = 1.0f / maxf(rms, 1.0f); - if(lastgain >= gain) - lastgain = maxf(lastgain*AttackRate, gain); - else - lastgain = minf(lastgain/ReleaseRate, gain); - do_limit |= (lastgain < 1.0f); - Values[i] = lastgain; - - wpos = (wpos+1)&LIMITER_WINDOW_MASK; - } - - Limiter->Gain = lastgain; - Limiter->Pos = wpos; - Limiter->SquaredSum = sum; - } - if(do_limit) - { - /* Finally, apply the gains to each channel. */ - for(c = 0;c < NumChans;c++) - { - for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= Values[i]; - } - } -} - - /* NOTE: Non-dithered conversions have unused extra parameters. */ static inline ALfloat aluF2F(ALfloat val, ...) { return val; } @@ -1857,7 +1774,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; - struct OutputLimiter *Limiter = device->Limiter; + struct Compressor *Limiter = device->Limiter; ALfloat *DitherValues; /* Use NFCtrlData for temp value storage. */ @@ -1865,15 +1782,7 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) SamplesToDo, OutChannels); if(Limiter) - { - const ALfloat AttackRate = powf(0.0001f, 1.0f/(device->Frequency*Limiter->AttackRate)); - const ALfloat ReleaseRate = powf(0.0001f, 1.0f/(device->Frequency*Limiter->ReleaseRate)); - - /* Use NFCtrlData for temp value storage. */ - ApplyLimiter(Limiter, OutBuffer, OutChannels, - AttackRate, ReleaseRate, device->NFCtrlData, SamplesToDo - ); - } + ApplyCompression(Limiter, OutChannels, SamplesToDo, OutBuffer); /* Dithering. Step 1, generate whitenoise (uniform distribution of * random values between -1 and +1). Use NFCtrlData for random diff --git a/Alc/mastering.c b/Alc/mastering.c new file mode 100644 index 00000000..c9f5bebd --- /dev/null +++ b/Alc/mastering.c @@ -0,0 +1,255 @@ +#include "config.h" + +#include + +#include "alu.h" +#include "almalloc.h" + +#define RMS_WINDOW_SIZE (1<<7) +#define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1) +#define RMS_VALUE_MAX (1<<24) + +#define LOOKAHEAD_SIZE (1<<13) +#define LOOKAHEAD_MASK (LOOKAHEAD_SIZE-1) + +static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big"); + +typedef struct Compressor { + ALfloat PreGain; + ALfloat PostGain; + ALboolean SummedLink; + ALfloat AttackMin; + ALfloat AttackMax; + ALfloat ReleaseMin; + ALfloat ReleaseMax; + ALfloat Ratio; + ALfloat Threshold; + ALfloat Knee; + ALuint SampleRate; + + ALuint RmsSum; + ALuint *RmsWindow; + ALsizei RmsIndex; + ALfloat Envelope[BUFFERSIZE]; + ALfloat EnvLast; +} Compressor; + +/* Multichannel compression is linked via one of two modes: + * + * Summed - Absolute sum of all channels. + * Maxed - Absolute maximum of any channel. + */ +static void SumChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, + ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +{ + ALsizei c, i; + + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] = 0.0f; + + for(c = 0;c < NumChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] += OutBuffer[c][i]; + } + + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] = fabsf(Comp->Envelope[i]); +} + +static void MaxChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, + ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +{ + ALsizei c, i; + + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] = 0.0f; + + for(c = 0;c < NumChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] = maxf(Comp->Envelope[i], fabsf(OutBuffer[c][i])); + } +} + +/* Envelope detection/sensing can be done via: + * + * RMS - Rectangular windowed root mean square of linking stage. + * Peak - Implicit output from linking stage. + */ +static void RmsDetection(Compressor *Comp, const ALsizei SamplesToDo) +{ + ALuint sum = Comp->RmsSum; + ALuint *window = Comp->RmsWindow; + ALsizei index = Comp->RmsIndex; + ALsizei i; + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat sig = Comp->Envelope[i]; + + sum -= window[index]; + window[index] = fastf2u(minf(sig * sig * 65536.0f, RMS_VALUE_MAX)); + sum += window[index]; + index = (index + 1) & RMS_WINDOW_MASK; + + Comp->Envelope[i] = sqrtf(sum / 65536.0f / RMS_WINDOW_SIZE); + } + + Comp->RmsSum = sum; + Comp->RmsIndex = index; +} + +/* This isn't a very sophisticated envelope follower, but it gets the job + * done. First, it operates at logarithmic scales to keep transitions + * appropriate for human hearing. Second, it can apply adaptive (automated) + * attack/release adjustments based on the signal. + */ +static void FollowEnvelope(Compressor *Comp, const ALsizei SamplesToDo) +{ + ALfloat attackMin = Comp->AttackMin; + ALfloat attackMax = Comp->AttackMax; + ALfloat releaseMin = Comp->ReleaseMin; + ALfloat releaseMax = Comp->ReleaseMax; + ALfloat last = Comp->EnvLast; + ALsizei i; + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat env = maxf(-6.0f, log10f(Comp->Envelope[i])); + ALfloat slope = minf(1.0f, fabsf(env - last) / 4.5f); + + if(env > last) + last = minf(env, last + lerp(attackMin, attackMax, 1.0f - (slope * slope))); + else + last = maxf(env, last + lerp(releaseMin, releaseMax, 1.0f - (slope * slope))); + + Comp->Envelope[i] = last; + } + + Comp->EnvLast = last; +} + +/* The envelope is converted to control gain with an optional soft knee. */ +static void EnvelopeGain(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat Slope) +{ + const ALfloat threshold = Comp->Threshold; + const ALfloat knee = Comp->Knee; + ALsizei i; + + if(!(knee > 0.0f)) + { + for(i = 0;i < SamplesToDo;i++) + { + ALfloat gain = Slope * (threshold - Comp->Envelope[i]); + Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain)); + } + } + else + { + const ALfloat lower = threshold - (0.5f * knee); + const ALfloat upper = threshold + (0.5f * knee); + const ALfloat m = 0.5f * Slope / knee; + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat env = Comp->Envelope[i]; + ALfloat gain; + + if(env > lower && env < upper) + gain = m * (env - lower) * (lower - env); + else + gain = Slope * (threshold - env); + + Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain)); + } + } +} + + +Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALboolean SummedLink, const ALboolean RmsSensing, + const ALfloat AttackTimeMin, const ALfloat AttackTimeMax, + const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, + const ALfloat Ratio, const ALfloat ThresholdDb, + const ALfloat KneeDb, const ALuint SampleRate) +{ + Compressor *Comp; + size_t size; + ALsizei i; + + size = sizeof(*Comp); + if(RmsSensing) + size += sizeof(Comp->RmsWindow[0]) * RMS_WINDOW_SIZE; + Comp = al_calloc(16, size); + + Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); + Comp->PostGain = powf(10.0f, PostGainDb / 20.0f); + Comp->SummedLink = SummedLink; + Comp->AttackMin = 1.0f / maxf(0.000001f, AttackTimeMin * SampleRate * logf(10.0f)); + Comp->AttackMax = 1.0f / maxf(0.000001f, AttackTimeMax * SampleRate * logf(10.0f)); + Comp->ReleaseMin = -1.0f / maxf(0.000001f, ReleaseTimeMin * SampleRate * logf(10.0f)); + Comp->ReleaseMax = -1.0f / maxf(0.000001f, ReleaseTimeMax * SampleRate * logf(10.0f)); + Comp->Ratio = Ratio; + Comp->Threshold = ThresholdDb / 20.0f; + Comp->Knee = maxf(0.0f, KneeDb / 20.0f); + Comp->SampleRate = SampleRate; + + Comp->RmsSum = 0; + if(RmsSensing) + Comp->RmsWindow = (ALuint*)(Comp+1); + else + Comp->RmsWindow = NULL; + Comp->RmsIndex = 0; + + for(i = 0;i < BUFFERSIZE;i++) + Comp->Envelope[i] = 0.0f; + Comp->EnvLast = -6.0f; + + return Comp; +} + +ALuint GetCompressorSampleRate(const Compressor *Comp) +{ + return Comp->SampleRate; +} + +void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, + ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +{ + ALsizei c, i; + + if(Comp->PreGain != 1.0f) + { + for(c = 0;c < NumChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[c][i] *= Comp->PreGain; + } + } + + if(Comp->SummedLink) + SumChannels(Comp, NumChans, SamplesToDo, OutBuffer); + else + MaxChannels(Comp, NumChans, SamplesToDo, OutBuffer); + + if(Comp->RmsWindow) + RmsDetection(Comp, SamplesToDo); + FollowEnvelope(Comp, SamplesToDo); + + if(Comp->Ratio > 0.0f) + EnvelopeGain(Comp, SamplesToDo, 1.0f - (1.0f / Comp->Ratio)); + else + EnvelopeGain(Comp, SamplesToDo, 1.0f); + + if(Comp->PostGain != 1.0f) + { + for(i = 0;i < SamplesToDo;i++) + Comp->Envelope[i] *= Comp->PostGain; + } + for(c = 0;c < NumChans;c++) + { + for(i = 0;i < SamplesToDo;i++) + OutBuffer[c][i] *= Comp->Envelope[i]; + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 66402624..15311bc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -694,6 +694,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/alcRing.c Alc/bs2b.c Alc/converter.c + Alc/mastering.c Alc/effects/chorus.c Alc/effects/compressor.c Alc/effects/dedicated.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2ce98745..6e17651f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -380,7 +380,7 @@ extern "C" { struct Hrtf; struct HrtfEntry; -struct OutputLimiter; +struct Compressor; #define DEFAULT_OUTPUT_RATE (44100) @@ -783,7 +783,7 @@ struct ALCdevice_struct ALsizei NumChannels; } RealOut; - struct OutputLimiter *Limiter; + struct Compressor *Limiter; /* The average speaker distance as determined by the ambdec configuration * (or alternatively, by the NFC-HOA reference delay). Only used for NFC. @@ -1047,6 +1047,34 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir); typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; typedef ALfloat ALfloat2[2]; + +/* The compressor requires the following information for proper + * initialization: + * + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Gain applied after compression (in dB). + * SummedLink - Whether to use summed (true) or maxed (false) linking. + * RmsSensing - Whether to use RMS (true) or Peak (false) sensing. + * AttackTimeMin - Minimum attack time (in seconds). + * AttackTimeMax - Maximum attack time. Automates when min != max. + * ReleaseTimeMin - Minimum release time (in seconds). + * ReleaseTimeMax - Maximum release time. Automates when min != max. + * Ratio - Compression ratio (x:1). Set to 0 for true limiter. + * ThresholdDb - Triggering threshold (in dB). + * KneeDb - Knee width (below threshold; in dB). + * SampleRate - Sample rate to process. + */ +struct Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin, + const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, + const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb, + const ALuint SampleRate); + +ALuint GetCompressorSampleRate(const struct Compressor *Comp); + +void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, + ALfloat (*restrict OutBuffer)[BUFFERSIZE]); + #ifdef __cplusplus } #endif diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8a56ddb2..0b3799c0 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -300,28 +300,6 @@ typedef struct ALvoice { void DeinitVoice(ALvoice *voice); -#define LIMITER_WINDOW_SIZE (1<<7) /* 128 */ -#define LIMITER_WINDOW_MASK (LIMITER_WINDOW_SIZE-1) -#define LIMITER_VALUE_MAX (1<<24) /* 16777216 */ -struct OutputLimiter { - /* RMS detection window, sum of values in the window, and the next write - * pos. Values are 16.16 fixed-point. - */ - ALuint Window[LIMITER_WINDOW_SIZE]; - ALuint SquaredSum; - ALsizei Pos; - - /* In milliseconds. */ - ALfloat AttackRate; - ALfloat ReleaseRate; - - /* The gain last used for limiting. */ - ALfloat Gain; -}; - -struct OutputLimiter *alloc_limiter(void); - - typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, -- cgit v1.2.3 From c51df897db79a9c3190b6571618c3f2010a36de5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 May 2017 03:40:52 -0700 Subject: Use normal air absorption for the sends Applies just for the normal air absorption which uses the air absorption factor, not the automated decay applied when WetGainAuto is enabled. --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 103d7962..7bf6f2ff 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1259,7 +1259,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop for(i = 0;i < NumSends;i++) { if(RoomRolloff[i] > 0.0f) - WetGainHF[i] *= powf(RoomAirAbsorption[i], absorb*RoomRolloff[i]); + WetGainHF[i] *= powf(AIRABSORBGAINHF, absorb*RoomRolloff[i]); } } -- cgit v1.2.3 From e9505b164e6587b1bb0d04b478ddc45033dfbac8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 May 2017 22:33:40 -0700 Subject: Fix source sends' initial HF absorption and decay calculation The HF absorption is applied given the source distance, as relative to the source's immediate environment, with additional absorption being applied given the room/reverb environment. This does double up the amount of absorption compared to the dry path, but it can be assumed the initial reflections travel a longer distance. --- Alc/ALu.c | 36 +++++++++++++++--------------------- OpenAL32/Include/alAuxEffectSlot.h | 2 +- OpenAL32/alAuxEffectSlot.c | 2 +- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 7bf6f2ff..d7a8a89b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -348,16 +348,16 @@ static ALboolean CalcEffectSlotParams(ALeffectslot *slot, ALCdevice *device) slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; slot->Params.DecayTime = props->Props.Reverb.DecayTime; slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; - slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; + slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; } else { slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; slot->Params.DecayHFRatio = 0.0f; - slot->Params.AirAbsorptionGainHF = 1.0f; slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; } /* Swap effect states. No need to play with the ref counts since they keep @@ -1079,7 +1079,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop const ALsizei NumSends = Device->NumAuxSends; aluVector Position, Velocity, Direction, SourceToListener; ALfloat Distance, ClampedDist, DopplerFactor; - ALfloat RoomAirAbsorption[MAX_SENDS]; ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; @@ -1108,20 +1107,20 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; DecayHFDistance[i] = 0.0f; - RoomAirAbsorption[i] = 1.0f; } else if(SendSlots[i]->Params.AuxSendAuto) { RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; DecayDistance[i] = SendSlots[i]->Params.DecayTime * SPEEDOFSOUNDMETRESPERSEC; DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; - RoomAirAbsorption[i] = SendSlots[i]->Params.AirAbsorptionGainHF; - if(SendSlots[i]->Params.DecayHFLimit && RoomAirAbsorption[i] < 1.0f) + if(SendSlots[i]->Params.DecayHFLimit) { - ALfloat limitRatio = log10f(REVERB_DECAY_GAIN) / - (log10f(RoomAirAbsorption[i]) * DecayDistance[i]); - limitRatio = minf(limitRatio, SendSlots[i]->Params.DecayHFRatio); - DecayHFDistance[i] = minf(DecayHFDistance[i], limitRatio*DecayDistance[i]); + ALfloat airAbsorption = SendSlots[i]->Params.AirAbsorptionGainHF; + if(airAbsorption < 1.0f) + { + ALfloat limitRatio = log10f(REVERB_DECAY_GAIN) / log10f(airAbsorption); + DecayHFDistance[i] = minf(limitRatio, DecayHFDistance[i]); + } } } else @@ -1131,7 +1130,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop RoomRolloff[i] = props->RolloffFactor; DecayDistance[i] = 0.0f; DecayHFDistance[i] = 0.0f; - RoomAirAbsorption[i] = AIRABSORBGAINHF; } if(!SendSlots[i]) @@ -1249,24 +1247,20 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop } /* Distance-based air absorption */ - if(ClampedDist > props->RefDistance) + if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) { - ALfloat meters_base = (ClampedDist-props->RefDistance) * Listener->Params.MetersPerUnit; + ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener->Params.MetersPerUnit; if(props->AirAbsorptionFactor > 0.0f) { - ALfloat absorb = props->AirAbsorptionFactor * meters_base; - DryGainHF *= powf(AIRABSORBGAINHF, absorb*props->RolloffFactor); + ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); + DryGainHF *= hfattn; for(i = 0;i < NumSends;i++) - { - if(RoomRolloff[i] > 0.0f) - WetGainHF[i] *= powf(AIRABSORBGAINHF, absorb*RoomRolloff[i]); - } + WetGainHF[i] *= hfattn; } if(props->WetGainAuto) { - meters_base *= props->RolloffFactor; - /* Apply a decay-time transformation to the wet path, based on the * source distance in meters. The initial decay of the reverb * effect is calculated and applied to the wet path. diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 7126f8f5..5be9ae7a 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -122,8 +122,8 @@ typedef struct ALeffectslot { ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ ALfloat DecayTime; ALfloat DecayHFRatio; - ALfloat AirAbsorptionGainHF; ALboolean DecayHFLimit; + ALfloat AirAbsorptionGainHF; } Params; /* Self ID */ diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 8a990584..cd2c1e09 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -616,8 +616,8 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; slot->Params.DecayHFRatio = 0.0f; - slot->Params.AirAbsorptionGainHF = 1.0f; slot->Params.DecayHFLimit = AL_FALSE; + slot->Params.AirAbsorptionGainHF = 1.0f; return AL_NO_ERROR; } -- cgit v1.2.3 From a79e8f3d95873ce2898bddaeb0973b255172e44d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 May 2017 22:47:40 -0700 Subject: Use peak limiting rather than RMS detection --- Alc/ALc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dcda29c3..a79f3ab3 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1740,7 +1740,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) struct Compressor *CreateDeviceLimiter(const ALCdevice *device) { - return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_TRUE, 0.0f, 0.0f, 0.5f, 2.0f, + return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_FALSE, 0.0f, 0.0f, 0.5f, 2.0f, 0.0f, -0.5f, 3.0f, device->Frequency); } -- cgit v1.2.3 From 07bb5f13223564bb7a1e8b0608dc24caa67fbae6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 May 2017 00:53:33 -0700 Subject: Add a missing include --- examples/alffplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 10870930..b2033b97 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include -- cgit v1.2.3 From 6d4adc6ad6f387dcde4e01099e33672c4a19fda6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 May 2017 03:38:27 -0700 Subject: Use an RMS limit of -3dB for the output limiter --- Alc/ALc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a79f3ab3..b31c4f08 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1740,8 +1740,8 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) struct Compressor *CreateDeviceLimiter(const ALCdevice *device) { - return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_FALSE, 0.0f, 0.0f, 0.5f, 2.0f, - 0.0f, -0.5f, 3.0f, device->Frequency); + return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_TRUE, 0.0f, 0.0f, 0.5f, 2.0f, + 0.0f, -3.0f, 3.0f, device->Frequency); } /* UpdateClockBase -- cgit v1.2.3 From e893211b659a5dbaf75aa437ab594aac87984b85 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 May 2017 05:13:54 -0700 Subject: Restrict ClampedDist to RefDistance for invalid distance attenuation --- Alc/ALu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d7a8a89b..11b3fd26 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1195,7 +1195,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop break; /*fall-through*/ case InverseDistance: - if(props->RefDistance > 0.0f) + if(!(props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else { ALfloat dist = lerp(props->RefDistance, ClampedDist, props->RolloffFactor); if(dist > 0.0f) DryGain *= props->RefDistance / dist; @@ -1213,10 +1215,12 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop break; /*fall-through*/ case LinearDistance: - if(props->MaxDistance != props->RefDistance) + if(!(props->MaxDistance != props->RefDistance)) + ClampedDist = props->RefDistance; + else { ALfloat attn = props->RolloffFactor * (ClampedDist-props->RefDistance) / - (props->MaxDistance-props->RefDistance); + (props->MaxDistance-props->RefDistance); DryGain *= maxf(1.0f - attn, 0.0f); for(i = 0;i < NumSends;i++) { @@ -1233,7 +1237,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop break; /*fall-through*/ case ExponentDistance: - if(ClampedDist > 0.0f && props->RefDistance > 0.0f) + if(!(ClampedDist > 0.0f && props->RefDistance > 0.0f)) + ClampedDist = props->RefDistance; + else { DryGain *= powf(ClampedDist/props->RefDistance, -props->RolloffFactor); for(i = 0;i < NumSends;i++) -- cgit v1.2.3 From f54946f9cb1b3293cc95cc77400625aa4c80c138 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 May 2017 09:58:06 -0700 Subject: Remove unused HIDDEN_DECL macro --- CMakeLists.txt | 2 -- config.h.in | 3 --- 2 files changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15311bc2..b7e459fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,7 +359,6 @@ int main() ENDIF() # Set visibility/export options if available -SET(HIDDEN_DECL "") IF(WIN32) SET(EXPORT_DECL "__declspec(dllexport)") IF(NOT MINGW) @@ -388,7 +387,6 @@ ELSE() CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_SWITCH) IF(HAVE_VISIBILITY_HIDDEN_SWITCH) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") - SET(HIDDEN_DECL "__attribute__((visibility(\"hidden\")))") ENDIF() ENDIF() diff --git a/config.h.in b/config.h.in index d46c69ac..a71b54fb 100644 --- a/config.h.in +++ b/config.h.in @@ -8,9 +8,6 @@ /* Define a built-in call indicating an aligned data pointer */ #define ASSUME_ALIGNED(x, y) ${ASSUME_ALIGNED_DECL} -/* Explicit hidden visibility attribute */ -#define HIDDEN_DECL ${HIDDEN_DECL} - /* Define if HRTF data is embedded in the library */ #cmakedefine ALSOFT_EMBED_HRTF_DATA -- cgit v1.2.3 From 1c04cbad0495380645c86339191ec27914e19b50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2017 04:06:08 -0700 Subject: Resample HRIRs prior to minimum phase reconstruction --- utils/makehrtf.c | 77 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 177e48c5..704bf622 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -1267,9 +1267,9 @@ static void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRat rs->mP = dstRate / gcd; rs->mQ = srcRate / gcd; /* The cutoff is adjusted by half the transition width, so the transition - * ends before the nyquist (0.5). Both are scaled by the downsampling - * factor. - */ + * ends before the nyquist (0.5). Both are scaled by the downsampling + * factor. + */ if(rs->mP > rs->mQ) { cutoff = 0.45 / rs->mP; @@ -1923,13 +1923,12 @@ static int StoreMhr(const HrirDataT *hData, const char *filename) // 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) +static void AverageHrirOnset(const double *hrir, const uint n, const double f, const uint ei, const uint ai, const HrirDataT *hData) { double mag; - uint n, i, j; + uint i, j; mag = 0.0; - n = hData->mIrPoints; for(i = 0;i < n;i++) mag = fmax(fabs(hrir[i]), mag); mag *= 0.15; @@ -1944,7 +1943,7 @@ static void AverageHrirOnset(const double *hrir, const double f, const uint ei, // 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) +static void AverageHrirMagnitude(const double *hrir, const uint npoints, const double f, const uint ei, const uint ai, const HrirDataT *hData) { double *re, *im; uint n, m, i, j; @@ -1952,7 +1951,7 @@ static void AverageHrirMagnitude(const double *hrir, const double f, const uint n = hData->mFftSize; re = CreateArray(n); im = CreateArray(n); - for(i = 0;i < hData->mIrPoints;i++) + for(i = 0;i < npoints;i++) { re[i] = hrir[i]; im[i] = 0.0; @@ -2108,23 +2107,6 @@ static void ReconstructHrirs(const HrirDataT *hData) DestroyArray (re); } -// Resamples the HRIRs for use at the given sampling rate. -static void ResampleHrirs(const uint rate, HrirDataT *hData) -{ - uint n, step, start, end, j; - ResamplerT rs; - - ResamplerSetup(&rs, hData->mIrRate, rate); - n = hData->mIrPoints; - step = hData->mIrSize; - start = hData->mEvOffset[hData->mEvStart] * step; - end = hData->mIrCount * step; - for(j = start;j < end;j += step) - ResamplerRun(&rs, n, &hData->mHrirs[j], n, &hData->mHrirs[j]); - ResamplerClear(&rs); - hData->mIrRate = rate; -} - /* Given an elevation index and an azimuth, calculate the indices of the two * HRIRs that bound the coordinate along with a factor for calculating the * continous HRIR using interpolation. @@ -2614,17 +2596,37 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src) } // Process the list of sources in the data set definition. -static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *hData) +static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReaderT *tr, HrirDataT *hData) { uint *setCount, *setFlag; uint line, col, ei, ai; + uint res_points; SourceRefT src; double factor; double *hrir; + ResamplerT rs; + + ResamplerSetup(&rs, hData->mIrRate, dstRate); + /* Scale the number of IR points for resampling. This could be improved by + * also including space for the resampler build-up and fall-off (rs.mL*2), + * instead of clipping them off, but that could affect the HRTDs. It's not + * a big deal to exclude them for sources that aren't already minimum- + * phase). + */ + res_points = (uint)(((uint64)hData->mIrPoints*dstRate + hData->mIrRate-1) / + hData->mIrRate); + /* Clamp to the IR size to prevent overflow, and don't go less than the + * original point count. + */ + if(res_points > hData->mIrSize) + res_points = hData->mIrSize; + else if(res_points < hData->mIrPoints) + res_points = hData->mIrPoints; setCount = (uint*)calloc(hData->mEvCount, sizeof(uint)); setFlag = (uint*)calloc(hData->mIrCount, sizeof(uint)); - hrir = CreateArray(hData->mIrPoints); + hrir = CreateArray(res_points); + while(TrIsOperator(tr, "[")) { TrIndication(tr, & line, & col); @@ -2649,9 +2651,13 @@ static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *h if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir)) goto error; + if(hData->mIrRate != dstRate) + ResamplerRun(&rs, hData->mIrPoints, hrir, + res_points, hrir); + if(model == HM_DATASET) - AverageHrirOnset(hrir, 1.0 / factor, ei, ai, hData); - AverageHrirMagnitude(hrir, 1.0 / factor, ei, ai, hData); + AverageHrirOnset(hrir, res_points, 1.0 / factor, ei, ai, hData); + AverageHrirMagnitude(hrir, res_points, 1.0 / factor, ei, ai, hData); factor += 1.0; if(!TrIsOperator(tr, "+")) break; @@ -2660,6 +2666,8 @@ static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *h setFlag[hData->mEvOffset[ei] + ai] = 1; setCount[ei]++; } + hData->mIrPoints = res_points; + hData->mIrRate = dstRate; ei = 0; while(ei < hData->mEvCount && setCount[ei] < 1) @@ -2673,6 +2681,7 @@ static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *h { if(!TrLoad(tr)) { + ResamplerClear(&rs); DestroyArray(hrir); free(setFlag); free(setCount); @@ -2687,6 +2696,7 @@ static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *h TrError(tr, "Missing source references.\n"); error: + ResamplerClear(&rs); DestroyArray(hrir); free(setFlag); free(setCount); @@ -2735,9 +2745,9 @@ static int ProcessDefinition(const char *inName, const uint outRate, const uint fclose(fp); return 0; } - hData.mHrirs = CreateArray(hData.mIrCount * hData . mIrSize); + hData.mHrirs = CreateArray(hData.mIrCount * hData.mIrSize); hData.mHrtds = CreateArray(hData.mIrCount); - if(!ProcessSources(model, &tr, &hData)) + if(!ProcessSources(model, outRate ? outRate : hData.mIrRate, &tr, &hData)) { DestroyArray(hData.mHrtds); DestroyArray(hData.mHrirs); @@ -2758,11 +2768,6 @@ static int ProcessDefinition(const char *inName, const uint outRate, const uint } fprintf(stdout, "Performing minimum phase reconstruction...\n"); ReconstructHrirs(&hData); - if(outRate != 0 && outRate != hData.mIrRate) - { - fprintf(stdout, "Resampling HRIRs...\n"); - ResampleHrirs(outRate, &hData); - } fprintf(stdout, "Truncating minimum-phase HRIRs...\n"); hData.mIrPoints = truncSize; fprintf(stdout, "Synthesizing missing elevations...\n"); -- cgit v1.2.3 From e1dcfa4b9b7ad66aed5c3cd11029dce9af7b1853 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Jun 2017 04:09:08 -0700 Subject: Update default 48khz HRTF dataset --- hrtf/default-48000.mhr | Bin 53853 -> 53853 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/hrtf/default-48000.mhr b/hrtf/default-48000.mhr index 0ad547ad..7addfa71 100644 Binary files a/hrtf/default-48000.mhr and b/hrtf/default-48000.mhr differ -- cgit v1.2.3 From 9222d89de253d3f0cc344b3ec73f33b195803f7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Jun 2017 05:44:08 -0700 Subject: Update ChangeLog about OpenSL capture support --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index c6646098..44afc3fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,8 @@ openal-soft-1.18.0: Implemented a run-time check for NEON extensions using /proc/cpuinfo. + Implemented experimental capture support for the OpenSL backend. + Fixed building on compilers with NEON support but don't default to having NEON enabled. -- cgit v1.2.3 From 61e43d4039277c538f3f6e0af7c988e7d71d8558 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Jun 2017 07:31:22 -0700 Subject: Release 1.18.0 --- CMakeLists.txt | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7e459fd..6fcdb964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,8 +97,8 @@ IF(NOT LIBTYPE) ENDIF() SET(LIB_MAJOR_VERSION "1") -SET(LIB_MINOR_VERSION "17") -SET(LIB_REVISION "2") +SET(LIB_MINOR_VERSION "18") +SET(LIB_REVISION "0") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") diff --git a/appveyor.yml b/appveyor.yml index 9ea05d4e..9c125358 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.17.2.{build} +version: 1.18.0.{build} environment: matrix: -- cgit v1.2.3 From 10ff6cba9cf538e534138ac716e57324e8f71d06 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Jun 2017 10:33:56 -0700 Subject: Make the late lines' delay the delay average for modulation Similar to the recent chorus and flanger changes, the modulation delay now swings between -n to +n, where n is less than the delay length. This brings up a slight issue with the linear interpolation, as modff doesn't produce the correct fraction value for interpolation (it's inverted, with 0 being closer to the next sample and 1 being closer to the base). So it's using nearest interpolation for now. --- Alc/effects/reverb.c | 95 ++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 59 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f5d32d93..e0c0831a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -331,21 +331,6 @@ ALfloat ReverbBoost = 1.0f; */ ALboolean EmulateEAXReverb = AL_FALSE; -/* This coefficient is used to define the sinus depth according to the - * modulation depth property. This value must be below 1, which would cause the - * sampler to stall on the downswing, and above 1 it will cause it to sample - * backwards. - */ -static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 2048.0f; - -/* A filter is used to avoid the terrible distortion caused by changing - * modulation time and/or depth. To be consistent across different sample - * rates, the coefficient must be raised to a constant divided by the sample - * rate: coeff^(constant / rate). - */ -static const ALfloat MODULATION_FILTER_COEFF = 0.048f; -static const ALfloat MODULATION_FILTER_CONST = 100000.0f; - /* The all-pass and delay lines have a variable length dependent on the * effect's density parameter. The resulting density multiplier is: * @@ -473,20 +458,33 @@ static const ALfloat LATE_LINE_LENGTHS[4] = 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f }; -/* HACK: Workaround for a modff bug in 32-bit Windows, which attempts to write - * a 64-bit double to the 32-bit float parameter. +/* This coefficient is used to define the sinus depth according to the + * modulation depth property. This value must be below half the shortest late + * line length (0.0097/2 = ~0.0048), otherwise with certain parameters (high + * mod time, low density) the downswing can sample before the input. */ -#if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM) -static inline float hack_modff(float x, float *y) +static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 4096.0f; + +/* A filter is used to avoid the terrible distortion caused by changing + * modulation time and/or depth. To be consistent across different sample + * rates, the coefficient must be raised to a constant divided by the sample + * rate: coeff^(constant / rate). + */ +static const ALfloat MODULATION_FILTER_COEFF = 0.048f; +static const ALfloat MODULATION_FILTER_CONST = 100000.0f; + + +/* Prior to VS2013, MSVC lacks the round() family of functions. */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +static inline long lroundf(float val) { - double di; - double df = modf((double)x, &di); - *y = (float)di; - return (float)df; + if(val < 0.0) + return fastf2i(ceilf(val-0.5f)); + return fastf2i(floorf(val+0.5f)); } -#define modff hack_modff #endif + /************************************** * Device Update * **************************************/ @@ -1067,12 +1065,12 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, * time changes the pitch, creating the modulation effect. The scale needs * to be multiplied by the modulation time so that a given depth produces a * consistent shift in frequency over all ranges of time. Since the depth - * is applied to a sinus value, it needs to be halved once for the sinus - * range (-1...+1 to 0...1) and again for the sinus swing in time (half of - * it is spent decreasing the frequency, half is spent increasing it). + * is applied to a sinus value, it needs to be halved for the sinus swing + * in time (half of it is spent decreasing the frequency, half is spent + * increasing it). */ - State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / - 2.0f * frequency; + State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f * + frequency; } /* Update the offsets for the main effect delay line. */ @@ -1446,7 +1444,7 @@ static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const AL Delay->Line[offset][i] = in[3-i]; } -static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo) +static void CalcModulationDelays(ALreverbState *State, ALint *restrict delays, const ALsizei todo) { ALfloat sinus, range; ALsizei index, i; @@ -1456,10 +1454,9 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, for(i = 0;i < todo;i++) { /* Calculate the sinus rhythm (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. + * sampling rate). */ - sinus = 1.0f - cosf(F_TAU * index / State->Mod.Range); + sinus = sinf(F_TAU * index / State->Mod.Range); /* Step the modulation index forward, keeping it bound to its range. */ index = (index+1) % State->Mod.Range; @@ -1470,8 +1467,8 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, */ range = lerp(range, State->Mod.Depth, State->Mod.Coeff); - /* Calculate the read offset with fraction. */ - delays[i] = range*sinus; + /* Calculate the read offset. */ + delays[i] = lroundf(range*sinus); } State->Mod.Index = index; State->Mod.Filter = range; @@ -1686,14 +1683,13 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ const ALfloat mixX = State->MixX; \ const ALfloat mixY = State->MixY; \ - ALfloat fdelay, frac; \ + ALint moddelay[MAX_UPDATE_SAMPLES]; \ ALsizei delay; \ ALsizei offset; \ ALsizei i, j; \ ALfloat f[4]; \ \ - /* Calculations modulation delays, uing the output as temp storage. */ \ - CalcModulationDelays(State, &out[0][0], todo); \ + CalcModulationDelays(State, moddelay, todo); \ \ offset = State->Offset; \ for(i = 0;i < todo;i++) \ @@ -1704,31 +1700,12 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \ offset-State->LateDelayTap[j][1], j, fade \ ) * State->Late.DensityGain; \ \ - /* Separate the integer offset and fraction between it and the next \ - * sample. \ - */ \ - frac = modff(out[0][i], &fdelay); \ - delay = offset - fastf2i(fdelay); \ - \ + delay = offset - moddelay[i]; \ for(j = 0;j < 4;j++) \ - { \ - ALfloat out0, out1; \ - \ - /* Get the two samples crossed by the offset delay. */ \ - out0 = DELAY_OUT_##T(&State->Late.Delay, \ + f[j] += DELAY_OUT_##T(&State->Late.Delay, \ delay-State->Late.Offset[j][0], \ delay-State->Late.Offset[j][1], j, fade \ ); \ - out1 = DELAY_OUT_##T(&State->Late.Delay, \ - delay-State->Late.Offset[j][0]-1, \ - delay-State->Late.Offset[j][1]-1, j, fade \ - ); \ - \ - /* The modulated result is obtained by linearly interpolating the \ - * two samples that were acquired above. \ - */ \ - f[j] += lerp(out0, out1, frac); \ - } \ \ for(j = 0;j < 4;j++) \ f[j] = LateT60Filter(j, f[j], State); \ -- cgit v1.2.3 From b4aea294c3eaf592fb392c12976c592c233a3a2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 7 Jun 2017 12:42:54 -0700 Subject: Calculate chorus and flanger mod delays separately from feedback --- Alc/effects/chorus.c | 126 +++++++++++++++++++++++-------------------------- Alc/effects/flanger.c | 127 +++++++++++++++++++++++--------------------------- 2 files changed, 118 insertions(+), 135 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 62f2e531..5ef82cb4 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -172,107 +172,99 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device } } -static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state) +static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) { - ALfloat lfo_value; - - lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_left = fastf2i(lfo_value) + state->delay; - - offset += state->lfo_disp; - lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_right = fastf2i(lfo_value) + state->delay; + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; + offset = (offset+1)%lfo_range; + } } -static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state) +static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) { - ALfloat lfo_value; - - lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_left = fastf2i(lfo_value) + state->delay; - - offset += state->lfo_disp; - lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -#define DECL_TEMPLATE(Func) \ -static void Process##Func(ALchorusState *state, const ALsizei SamplesToDo, \ - const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \ -{ \ - const ALsizei bufmask = state->BufferLength-1; \ - ALfloat *restrict leftbuf = state->SampleBuffer[0]; \ - ALfloat *restrict rightbuf = state->SampleBuffer[1]; \ - ALsizei offset = state->offset; \ - const ALfloat feedback = state->feedback; \ - ALsizei it; \ - \ - for(it = 0;it < SamplesToDo;it++) \ - { \ - ALint delay_left, delay_right; \ - Func(&delay_left, &delay_right, offset, state); \ - \ - leftbuf[offset&bufmask] = SamplesIn[it]; \ - out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \ - leftbuf[offset&bufmask] += out[it][0] * feedback; \ - \ - rightbuf[offset&bufmask] = SamplesIn[it]; \ - out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \ - rightbuf[offset&bufmask] += out[it][1] * feedback; \ - \ - offset++; \ - } \ - state->offset = offset; \ + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; + offset = (offset+1)%lfo_range; + } } -DECL_TEMPLATE(Triangle) -DECL_TEMPLATE(Sinusoid) - -#undef DECL_TEMPLATE static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALsizei it, kt; + ALfloat *restrict leftbuf = state->SampleBuffer[0]; + ALfloat *restrict rightbuf = state->SampleBuffer[1]; + const ALsizei bufmask = state->BufferLength-1; + const ALfloat feedback = state->feedback; + ALsizei offset = state->offset; + ALsizei i, c; ALsizei base; for(base = 0;base < SamplesToDo;) { + const ALsizei todo = mini(128, SamplesToDo-base); ALfloat temps[128][2]; - ALsizei td = mini(128, SamplesToDo-base); + ALint moddelays[2][128]; switch(state->waveform) { case CWF_Triangle: - ProcessTriangle(state, td, SamplesIn[0]+base, temps); + GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range, + state->lfo_scale, state->depth, state->delay, todo); + GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); break; case CWF_Sinusoid: - ProcessSinusoid(state, td, SamplesIn[0]+base, temps); + GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range, + state->lfo_scale, state->depth, state->delay, todo); + GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); break; } - for(kt = 0;kt < NumChannels;kt++) + for(i = 0;i < todo;i++) + { + leftbuf[offset&bufmask] = SamplesIn[0][base+i]; + temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback; + leftbuf[offset&bufmask] += temps[i][0]; + + rightbuf[offset&bufmask] = SamplesIn[0][base+i]; + temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback; + rightbuf[offset&bufmask] += temps[i][1]; + + offset++; + } + + for(c = 0;c < NumChannels;c++) { - ALfloat gain = state->Gain[0][kt]; + ALfloat gain = state->Gain[0][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { - for(it = 0;it < td;it++) - SamplesOut[kt][it+base] += temps[it][0] * gain; + for(i = 0;i < todo;i++) + SamplesOut[c][i+base] += temps[i][0] * gain; } - gain = state->Gain[1][kt]; + gain = state->Gain[1][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { - for(it = 0;it < td;it++) - SamplesOut[kt][it+base] += temps[it][1] * gain; + for(i = 0;i < todo;i++) + SamplesOut[c][i+base] += temps[i][1] * gain; } } - base += td; + base += todo; } + + state->offset = offset; } diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c index d330511a..b25b95cc 100644 --- a/Alc/effects/flanger.c +++ b/Alc/effects/flanger.c @@ -172,107 +172,98 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi } } -static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state) +static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) { - ALfloat lfo_value; - - lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_left = fastf2i(lfo_value) + state->delay; - - offset += state->lfo_disp; - lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_right = fastf2i(lfo_value) + state->delay; + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; + offset = (offset+1)%lfo_range; + } } -static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state) +static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, + const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, + const ALsizei todo) { - ALfloat lfo_value; - - lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_left = fastf2i(lfo_value) + state->delay; - - offset += state->lfo_disp; - lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range)); - lfo_value *= state->depth; - *delay_right = fastf2i(lfo_value) + state->delay; -} - -#define DECL_TEMPLATE(Func) \ -static void Process##Func(ALflangerState *state, const ALsizei SamplesToDo, \ - const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \ -{ \ - const ALsizei bufmask = state->BufferLength-1; \ - ALfloat *restrict leftbuf = state->SampleBuffer[0]; \ - ALfloat *restrict rightbuf = state->SampleBuffer[1]; \ - ALsizei offset = state->offset; \ - const ALfloat feedback = state->feedback; \ - ALsizei it; \ - \ - for(it = 0;it < SamplesToDo;it++) \ - { \ - ALint delay_left, delay_right; \ - Func(&delay_left, &delay_right, offset, state); \ - \ - leftbuf[offset&bufmask] = SamplesIn[it]; \ - out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \ - leftbuf[offset&bufmask] += out[it][0] * feedback; \ - \ - rightbuf[offset&bufmask] = SamplesIn[it]; \ - out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \ - rightbuf[offset&bufmask] += out[it][1] * feedback; \ - \ - offset++; \ - } \ - state->offset = offset; \ + ALsizei i; + for(i = 0;i < todo;i++) + { + delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; + offset = (offset+1)%lfo_range; + } } -DECL_TEMPLATE(Triangle) -DECL_TEMPLATE(Sinusoid) - -#undef DECL_TEMPLATE - static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALsizei it, kt; + ALfloat *restrict leftbuf = state->SampleBuffer[0]; + ALfloat *restrict rightbuf = state->SampleBuffer[1]; + const ALsizei bufmask = state->BufferLength-1; + const ALfloat feedback = state->feedback; + ALsizei offset = state->offset; + ALsizei i, c; ALsizei base; for(base = 0;base < SamplesToDo;) { + const ALsizei todo = mini(128, SamplesToDo-base); ALfloat temps[128][2]; - ALsizei td = mini(128, SamplesToDo-base); + ALint moddelays[2][128]; switch(state->waveform) { case FWF_Triangle: - ProcessTriangle(state, td, SamplesIn[0]+base, temps); + GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range, + state->lfo_scale, state->depth, state->delay, todo); + GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); break; case FWF_Sinusoid: - ProcessSinusoid(state, td, SamplesIn[0]+base, temps); + GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range, + state->lfo_scale, state->depth, state->delay, todo); + GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range, + state->lfo_range, state->lfo_scale, state->depth, state->delay, + todo); break; } - for(kt = 0;kt < NumChannels;kt++) + for(i = 0;i < todo;i++) { - ALfloat gain = state->Gain[0][kt]; + leftbuf[offset&bufmask] = SamplesIn[0][base+i]; + temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback; + leftbuf[offset&bufmask] += temps[i][0]; + + rightbuf[offset&bufmask] = SamplesIn[0][base+i]; + temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback; + rightbuf[offset&bufmask] += temps[i][1]; + + offset++; + } + + for(c = 0;c < NumChannels;c++) + { + ALfloat gain = state->Gain[0][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { - for(it = 0;it < td;it++) - SamplesOut[kt][it+base] += temps[it][0] * gain; + for(i = 0;i < todo;i++) + SamplesOut[c][i+base] += temps[i][0] * gain; } - gain = state->Gain[1][kt]; + gain = state->Gain[1][c]; if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { - for(it = 0;it < td;it++) - SamplesOut[kt][it+base] += temps[it][1] * gain; + for(i = 0;i < todo;i++) + SamplesOut[c][i+base] += temps[i][1] * gain; } } - base += td; + base += todo; } + + state->offset = offset; } -- cgit v1.2.3 From 39e4756b376225e35b7e082be70797ec27a42cdd Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 9 Jun 2017 15:08:47 +0200 Subject: Implement GetProcPath for FreeBSD --- Alc/helpers.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 8e685c75..f1cd1f66 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -40,6 +40,10 @@ #include #endif +#ifdef __FreeBSD__ +#include +#endif + #ifndef AL_NO_UID_DEFS #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) #define INITGUID @@ -707,9 +711,22 @@ void UnmapFileMem(const struct FileMapping *mapping) al_string GetProcPath(void) { al_string ret = AL_STRING_INIT_STATIC(); - const char *fname; char *pathname, *sep; size_t pathlen; + +#ifdef __FreeBSD__ + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + mib[3] = getpid(); + if (sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) { + WARN("Failed to sysctl kern.proc.pathname.%d: %s\n", mib[3], strerror(errno)); + return ret; + } + + pathname = malloc(pathlen + 1); + sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + pathname[pathlen] = 0; +#else + const char *fname; ssize_t len; pathlen = 256; @@ -738,6 +755,8 @@ al_string GetProcPath(void) } pathname[len] = 0; +#endif + sep = strrchr(pathname, '/'); if(sep) alstr_copy_range(&ret, pathname, sep); -- cgit v1.2.3 From a35b9bbd3eac75771ca90d5755068cf88d5406aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Jun 2017 13:32:34 -0700 Subject: Don't force a fade-in when resuming a paused source This needs to be handled more automatically by the mixer to work correctly. Otherwise, requiring a property update on resume can put the source into a playing state with the mixer never playing it, due to not having valid mixing parameters and the mixing parameters not getting calculated because no updates are specified by the app (and forcing an update can break deferred updates). --- OpenAL32/alSource.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 46f23a75..be191fdb 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2502,17 +2502,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) case AL_PAUSED: assert(voice != NULL); - /* A source that's paused simply resumes. Clear its mixing - * parameters and mark it as 'fading' so it fades in from - * silence. - */ - voice->Step = 0; - voice->Flags |= VOICE_IS_FADING; - memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])* - voice->NumChannels); - for(s = 0;s < device->NumAuxSends;s++) - memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])* - voice->NumChannels); + /* A source that's paused simply resumes. */ ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); goto finish_play; -- cgit v1.2.3 From 1e8feeff038ab0b2449a7b1b689a6c2500c0a4d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Jun 2017 16:38:51 -0700 Subject: Update ChangeLog with recent fixes --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 44afc3fc..112c3858 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +openal-soft-1.18.1: + + Fixed an issue where resuming a source might not restart playing it. + + Added correct retrieval of the executable's path on FreeBSD. + openal-soft-1.18.0: Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. -- cgit v1.2.3 From d4f3490a880f779f460332689a396ade69840f50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Jun 2017 21:39:09 -0700 Subject: Limit device buffer based on PulseAudio's tlength Unfortunately PulseAudio has a habit of limiting tlength, and trying to calculate the device's buffer length to write regardless of tlength could result in some amount always being writable. --- Alc/backends/pulseaudio.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 43761e23..8c5469b2 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -817,7 +817,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr) pa_threaded_mainloop_lock(self->loop); frame_size = pa_frame_size(&self->spec); - buffer_size = device->UpdateSize * device->NumUpdates * frame_size; while(!self->killNow && device->Connected) { @@ -830,15 +829,17 @@ static int ALCpulsePlayback_mixerProc(void *ptr) } /* Make sure we're going to write at least 2 'periods' (minreqs), in - * case the server increased it since starting playback. + * case the server increased it since starting playback. Also round up + * the number of writable periods if it's not an integer count. */ - buffer_size = maxu(buffer_size, self->attr.minreq*2); + buffer_size = maxu((self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2) * + self->attr.minreq; /* NOTE: This assumes pa_stream_writable_size returns between 0 and * tlength, else there will be more latency than intended. */ len = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size; - if(len < self->attr.minreq) + if(len < (int32_t)self->attr.minreq) { if(pa_stream_is_corked(self->stream)) { @@ -968,7 +969,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) const char *mapname = NULL; pa_channel_map chanmap; pa_operation *o; - ALuint len; pa_threaded_mainloop_lock(self->loop); @@ -1107,11 +1107,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self); ALCpulsePlayback_bufferAttrCallback(self->stream, self); - len = self->attr.minreq / pa_frame_size(&self->spec); - device->NumUpdates = (ALuint)clampd( - (ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5, 2.0, 16.0 + device->NumUpdates = (ALuint)clampu64( + (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16 ); - device->UpdateSize = len; + device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec); /* HACK: prebuf should be 0 as that's what we set it to. However on some * systems it comes back as non-0, so we have to make sure the device will @@ -1121,7 +1120,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) */ if(self->attr.prebuf != 0) { - len = self->attr.prebuf / pa_frame_size(&self->spec); + ALuint len = self->attr.prebuf / pa_frame_size(&self->spec); if(len <= device->UpdateSize*device->NumUpdates) ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n", len, self->attr.prebuf, device->UpdateSize*device->NumUpdates); -- cgit v1.2.3 From e18f7ca3e401fc8d0ad56eeed3cc03b81697853f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Jun 2017 23:13:25 -0700 Subject: Update ChangeLog with the PulseAudio fix --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 112c3858..6d79fde0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ openal-soft-1.18.1: Fixed an issue where resuming a source might not restart playing it. + Fixed PulseAudio playback when the configured stream length is much less + than the requested length. + Added correct retrieval of the executable's path on FreeBSD. openal-soft-1.18.0: -- cgit v1.2.3 From 879b79740f0566bf56d7e8a7f636ce404c1a692d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Jun 2017 19:00:00 -0700 Subject: Round the B-Format HRTF response where the multiple is defined --- Alc/hrtf.c | 4 +++- Alc/panning.c | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3017113d..9e401573 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -284,8 +284,10 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize } } } - TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); + /* Round up to the next IR size multiple. */ + max_length = RoundUp(max_length, MOD_IR_SIZE); + TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); return max_length; #undef NUM_BANDS } diff --git a/Alc/panning.c b/Alc/panning.c index c00421c9..a5cddcb2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -963,9 +963,6 @@ static void InitHrtfPanning(ALCdevice *device) device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints) ); - - /* Round up to the nearest multiple of 8 */ - device->Hrtf->IrSize = (device->Hrtf->IrSize+7)&~7; } static void InitUhjPanning(ALCdevice *device) -- cgit v1.2.3 From 9fc01934c2038e6ff97060f6b236a7ae9ebcc47b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Jun 2017 22:58:13 -0700 Subject: Use helpers to get data from byte streams --- Alc/hrtf.c | 102 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9e401573..47015dc3 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -362,6 +362,41 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount return Hrtf; } +static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len) +{ + ALubyte ret = (*data)[0]; + *data += 1; *len -= 1; + return ret; +} + +static ALshort GetLE_ALshort(const ALubyte **data, size_t *len) +{ + ALshort ret = (*data)[0] | ((*data)[1]<<8); + *data += 2; *len -= 2; + return ret; +} + +static ALushort GetLE_ALushort(const ALubyte **data, size_t *len) +{ + ALushort ret = (*data)[0] | ((*data)[1]<<8); + *data += 2; *len -= 2; + return ret; +} + +static ALint GetLE_ALuint(const ALubyte **data, size_t *len) +{ + ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24); + *data += 4; *len -= 4; + return ret; +} + +static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size) +{ + const ALubyte *ret = *data; + *data += size; *len -= size; + return ret; +} + static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; @@ -383,22 +418,13 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * return NULL; } - rate = *(data++); - rate |= *(data++)<<8; - rate |= *(data++)<<16; - rate |= *(data++)<<24; - datalen -= 4; + rate = GetLE_ALuint(&data, &datalen); - irCount = *(data++); - irCount |= *(data++)<<8; - datalen -= 2; + irCount = GetLE_ALushort(&data, &datalen); - irSize = *(data++); - irSize |= *(data++)<<8; - datalen -= 2; + irSize = GetLE_ALushort(&data, &datalen); - evCount = *(data++); - datalen -= 1; + evCount = GetLE_ALubyte(&data, &datalen); if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -431,14 +457,10 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * if(!failed) { - evOffset[0] = *(data++); - evOffset[0] |= *(data++)<<8; - datalen -= 2; + evOffset[0] = GetLE_ALushort(&data, &datalen); for(i = 1;i < evCount;i++) { - evOffset[i] = *(data++); - evOffset[i] |= *(data++)<<8; - datalen -= 2; + evOffset[i] = GetLE_ALushort(&data, &datalen); if(evOffset[i] <= evOffset[i-1]) { ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", @@ -494,22 +516,15 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char * if(!failed) { - for(i = 0;i < irCount*irSize;i+=irSize) + for(i = 0;i < irCount;i++) { for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = *(data++); - coeff |= *(data++)<<8; - datalen -= 2; - coeffs[i+j][0] = coeff / 32768.0f; - } + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; } for(i = 0;i < irCount;i++) { - delays[i][0] = *(data++); - datalen -= 1; + delays[i][0] = GetLE_ALubyte(&data, &datalen); if(delays[i][0] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay); @@ -569,17 +584,11 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * return NULL; } - rate = *(data++); - rate |= *(data++)<<8; - rate |= *(data++)<<16; - rate |= *(data++)<<24; - datalen -= 4; + rate = GetLE_ALuint(&data, &datalen); - irSize = *(data++); - datalen -= 1; + irSize = GetLE_ALubyte(&data, &datalen); - evCount = *(data++); - datalen -= 1; + evCount = GetLE_ALubyte(&data, &datalen); if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -602,9 +611,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * return NULL; } - azCount = data; - data += evCount; - datalen -= evCount; + azCount = Get_ALubytePtr(&data, &datalen, evCount); evOffset = malloc(sizeof(evOffset[0])*evCount); if(azCount == NULL || evOffset == NULL) @@ -658,22 +665,15 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char * if(!failed) { - for(i = 0;i < irCount*irSize;i+=irSize) + for(i = 0;i < irCount;i++) { for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = *(data++); - coeff |= *(data++)<<8; - datalen -= 2; - coeffs[i+j][0] = coeff / 32768.0f; - } + coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f; } for(i = 0;i < irCount;i++) { - delays[i][0] = *(data++); - datalen -= 1; + delays[i][0] = GetLE_ALubyte(&data, &datalen); if(delays[i][0] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay); -- cgit v1.2.3 From e3a825b37c5f43593467f2df3cd225904a259cf8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Jun 2017 01:11:21 -0700 Subject: Apply dither separately from output --- Alc/ALu.c | 166 +++++++++++++++++++++++++------------------------------------- 1 file changed, 68 insertions(+), 98 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 11b3fd26..c398dc2b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -142,11 +142,11 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) /* Prior to VS2013, MSVC lacks the round() family of functions. */ #if defined(_MSC_VER) && _MSC_VER < 1800 -static long lroundf(float val) +static float roundf(float val) { - if(val < 0.0) - return fastf2i(ceilf(val-0.5f)); - return fastf2i(floorf(val+0.5f)); + if(val < 0.0f) + return ceilf(val-0.5f); + return floorf(val+0.5f); } #endif @@ -1527,10 +1527,37 @@ static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp } -/* NOTE: Non-dithered conversions have unused extra parameters. */ -static inline ALfloat aluF2F(ALfloat val, ...) +static void ApplyDither(ALfloatBUFFERSIZE *restrict Samples, ALuint *dither_seed, + const ALfloat quant_scale, const ALsizei SamplesToDo, + const ALsizei numchans) +{ + const ALfloat invscale = 1.0f / quant_scale; + ALuint seed = *dither_seed; + ALsizei c, i; + + /* Dithering. Step 1, generate whitenoise (uniform distribution of random + * values between -1 and +1). Step 2 is to add the noise to the samples, + * before rounding and after scaling up to the desired quantization depth. + */ + for(c = 0;c < numchans;c++) + { + ALfloat *restrict samples = Samples[c]; + for(i = 0;i < SamplesToDo;i++) + { + ALfloat val = samples[i] * quant_scale; + ALuint rng0 = dither_rng(&seed); + ALuint rng1 = dither_rng(&seed); + val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); + samples[i] = roundf(val) * invscale; + } + } + *dither_seed = seed; +} + + +static inline ALfloat aluF2F(ALfloat val) { return val; } -static inline ALint aluF2I(ALfloat val, ...) +static inline ALint aluF2I(ALfloat val) { /* Floats only have a 24-bit mantissa, so [-16777216, +16777216] is the max * integer range normalized floats can be safely converted to (a bit of the @@ -1538,44 +1565,25 @@ static inline ALint aluF2I(ALfloat val, ...) */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; } -static inline ALshort aluF2S(ALfloat val, ...) +static inline ALshort aluF2S(ALfloat val) { return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); } -static inline ALbyte aluF2B(ALfloat val, ...) +static inline ALbyte aluF2B(ALfloat val) { return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); } -/* Dithered conversion functions. Only applies to 8- and 16-bit output for now, - * as 32-bit int and float are at the limits of the rendered sample depth. This - * can change if the dithering bit depth becomes configurable (effectively - * quantizing to a lower bit depth than the output is capable of). - */ -static inline ALshort aluF2SDithered(ALfloat val, const ALfloat dither_val) -{ - val = val*32768.0f + dither_val; - return lroundf(clampf(val, -32768.0f, 32767.0f)); -} -static inline ALbyte aluF2BDithered(ALfloat val, const ALfloat dither_val) -{ - val = val*128.0f + dither_val; - return lroundf(clampf(val, -128.0f, 127.0f)); -} - /* Define unsigned output variations. */ #define DECL_TEMPLATE(T, Name, func, O) \ -static inline T Name(ALfloat val, const ALfloat dither_val) \ -{ return func(val, dither_val)+O; } +static inline T Name(ALfloat val) \ +{ return func(val)+O; } DECL_TEMPLATE(ALubyte, aluF2UB, aluF2B, 128) DECL_TEMPLATE(ALushort, aluF2US, aluF2S, 32768) DECL_TEMPLATE(ALuint, aluF2UI, aluF2I, 2147483648u) -DECL_TEMPLATE(ALubyte, aluF2UBDithered, aluF2BDithered, 128) -DECL_TEMPLATE(ALushort, aluF2USDithered, aluF2SDithered, 32768) #undef DECL_TEMPLATE -#define DECL_TEMPLATE(T, D, func) \ -static void Write##T##D(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - const ALfloat *restrict DitherValues, \ - ALsizei SamplesToDo, ALsizei numchans) \ +#define DECL_TEMPLATE(T, func) \ +static void Write##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ + ALsizei SamplesToDo, ALsizei numchans) \ { \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ @@ -1584,22 +1592,17 @@ static void Write##T##D(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ T *restrict out = (T*)OutBuffer + j; \ \ for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(in[i], DitherValues[i]); \ + out[i*numchans] = func(in[i]); \ } \ } -DECL_TEMPLATE(ALfloat, /*no dither*/, aluF2F) -DECL_TEMPLATE(ALuint, /*no dither*/, aluF2UI) -DECL_TEMPLATE(ALint, /*no dither*/, aluF2I) -DECL_TEMPLATE(ALushort, /*no dither*/, aluF2US) -DECL_TEMPLATE(ALshort, /*no dither*/, aluF2S) -DECL_TEMPLATE(ALubyte, /*no dither*/, aluF2UB) -DECL_TEMPLATE(ALbyte, /*no dither*/, aluF2B) - -DECL_TEMPLATE(ALushort, _Dithered, aluF2USDithered) -DECL_TEMPLATE(ALshort, _Dithered, aluF2SDithered) -DECL_TEMPLATE(ALubyte, _Dithered, aluF2UBDithered) -DECL_TEMPLATE(ALbyte, _Dithered, aluF2BDithered) +DECL_TEMPLATE(ALfloat, aluF2F) +DECL_TEMPLATE(ALuint, aluF2UI) +DECL_TEMPLATE(ALint, aluF2I) +DECL_TEMPLATE(ALushort, aluF2US) +DECL_TEMPLATE(ALshort, aluF2S) +DECL_TEMPLATE(ALubyte, aluF2UB) +DECL_TEMPLATE(ALbyte, aluF2B) #undef DECL_TEMPLATE @@ -1775,7 +1778,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; struct Compressor *Limiter = device->Limiter; - ALfloat *DitherValues; /* Use NFCtrlData for temp value storage. */ ApplyDistanceComp(OutBuffer, device->ChannelDelay, device->NFCtrlData, @@ -1784,78 +1786,46 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(Limiter) ApplyCompression(Limiter, OutChannels, SamplesToDo, OutBuffer); - /* Dithering. Step 1, generate whitenoise (uniform distribution of - * random values between -1 and +1). Use NFCtrlData for random - * value storage. Step 2 is to add the noise to the samples, before - * rounding and after scaling up to the desired quantization depth, - * which occurs in the sample conversion stage. + /* Dither only applies to 8- and 16-bit output for now, as 32-bit + * int and float are at the limits of the rendered sample depth. + * This can change if the dithering bit depth becomes configurable + * (effectively quantizing to a lower bit depth than the output is + * capable of). */ - if(!device->DitherEnabled) - memset(device->NFCtrlData, 0, SamplesToDo*sizeof(ALfloat)); - else - { - ALuint dither_seed = device->DitherSeed; - ALsizei i; - - for(i = 0;i < SamplesToDo;i++) - { - ALuint rng0 = dither_rng(&dither_seed); - ALuint rng1 = dither_rng(&dither_seed); - device->NFCtrlData[i] = (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - } - device->DitherSeed = dither_seed; - } - DitherValues = device->NFCtrlData; - -#define WRITE(T, D, a, b, c, d, e) do { \ - Write##T##D(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \ - buffer = (T*)buffer + (d)*(e); \ +#define WRITE(T, a, b, c, d) do { \ + Write##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d)); \ + buffer = (T*)buffer + (c)*(d); \ } while(0) switch(device->FmtType) { case DevFmtByte: if(device->DitherEnabled) - WRITE(ALbyte, _Dithered, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); - else - WRITE(ALbyte, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + ApplyDither(OutBuffer, &device->DitherSeed, 128.0f, SamplesToDo, OutChannels); + WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUByte: if(device->DitherEnabled) - WRITE(ALubyte, _Dithered, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); - else - WRITE(ALubyte, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + ApplyDither(OutBuffer, &device->DitherSeed, 128.0f, SamplesToDo, OutChannels); + WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtShort: if(device->DitherEnabled) - WRITE(ALshort, _Dithered, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); - else - WRITE(ALshort, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + ApplyDither(OutBuffer, &device->DitherSeed, 32768.0f, SamplesToDo, OutChannels); + WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUShort: if(device->DitherEnabled) - WRITE(ALushort, _Dithered, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); - else - WRITE(ALushort, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + ApplyDither(OutBuffer, &device->DitherSeed, 32768.0f, SamplesToDo, OutChannels); + WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtInt: - WRITE(ALint, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUInt: - WRITE(ALuint, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtFloat: - WRITE(ALfloat, /*no dither*/, OutBuffer, buffer, DitherValues, - SamplesToDo, OutChannels); + WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels); break; } #undef WRITE -- cgit v1.2.3 From 2b013fc54e8cf9be2184e20a6cd17c4696401ca9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Jun 2017 23:09:51 -0700 Subject: Make the dithering depth configurable --- Alc/ALc.c | 35 +++++++++++++++++++++++++++++------ Alc/ALu.c | 18 ++++-------------- OpenAL32/Include/alMain.h | 2 +- alsoftrc.sample | 13 ++++++++++--- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index b31c4f08..7f6cf279 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2222,6 +2222,35 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->SourcesMax, device->NumMonoSources, device->NumStereoSources, device->AuxiliaryEffectSlotMax, device->NumAuxSends); + if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "dither", 1)) + device->DitherDepth = 0.0f; + else + { + ALint depth = 0; + ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "dither-depth", &depth); + if(depth <= 0) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + depth = 8; + break; + case DevFmtShort: + case DevFmtUShort: + depth = 16; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; + } + } + else if(depth > 24) + depth = 24; + device->DitherDepth = (depth > 0) ? powf(2.0f, (ALfloat)(depth-1)) : 0.0f; + } + if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) gainLimiter = val ? ALC_TRUE : ALC_FALSE; /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and @@ -4026,10 +4055,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ERR("Unsupported ambi-format: %s\n", fmt); } - device->DitherEnabled = GetConfigValueBool( - alstr_get_cstr(device->DeviceName), NULL, "dither", 1 - ); - device->Limiter = CreateDeviceLimiter(device); if(DefaultEffect.type != AL_EFFECT_NULL) @@ -4450,8 +4475,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN // Open the "backend" V(device->Backend,open)("Loopback"); - device->DitherEnabled = GetConfigValueBool(NULL, NULL, "dither", 1); - device->Limiter = CreateDeviceLimiter(device); { diff --git a/Alc/ALu.c b/Alc/ALu.c index c398dc2b..f6e5cb12 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1786,12 +1786,10 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) if(Limiter) ApplyCompression(Limiter, OutChannels, SamplesToDo, OutBuffer); - /* Dither only applies to 8- and 16-bit output for now, as 32-bit - * int and float are at the limits of the rendered sample depth. - * This can change if the dithering bit depth becomes configurable - * (effectively quantizing to a lower bit depth than the output is - * capable of). - */ + if(device->DitherDepth > 0.0f) + ApplyDither(OutBuffer, &device->DitherSeed, device->DitherDepth, SamplesToDo, + OutChannels); + #define WRITE(T, a, b, c, d) do { \ Write##T(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d)); \ buffer = (T*)buffer + (c)*(d); \ @@ -1799,23 +1797,15 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) switch(device->FmtType) { case DevFmtByte: - if(device->DitherEnabled) - ApplyDither(OutBuffer, &device->DitherSeed, 128.0f, SamplesToDo, OutChannels); WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUByte: - if(device->DitherEnabled) - ApplyDither(OutBuffer, &device->DitherSeed, 128.0f, SamplesToDo, OutChannels); WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtShort: - if(device->DitherEnabled) - ApplyDither(OutBuffer, &device->DitherSeed, 32768.0f, SamplesToDo, OutChannels); WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUShort: - if(device->DitherEnabled) - ApplyDither(OutBuffer, &device->DitherSeed, 32768.0f, SamplesToDo, OutChannels); WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtInt: diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6e17651f..e5dd8c26 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -794,7 +794,7 @@ struct ALCdevice_struct DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS]; /* Dithering control. */ - bool DitherEnabled; + ALfloat DitherDepth; ALuint DitherSeed; /* Running count of the mixer invocations, in 31.1 fixed point. This diff --git a/alsoftrc.sample b/alsoftrc.sample index 26d494f9..3e7d0eec 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -188,11 +188,18 @@ #output-limiter = true ## dither: -# Applies dithering on the final mix for 8- and 16-bit output. This replaces -# the distortion created by nearest-value quantization with low-level -# whitenoise. +# Applies dithering on the final mix, for 8- and 16-bit output by default. +# This replaces the distortion created by nearest-value quantization with low- +# level whitenoise. #dither = true +## dither-depth: +# Quantization bit-depth for dithered output. A value of 0 (or less) will +# match the output sample depth. For int32, uint32, and float32 output, 0 will +# disable dithering because they're at or beyond the rendered precision. The +# maximum dither depth is 24. +#dither-depth = 0 + ## volume-adjust: # A global volume adjustment for source output, expressed in decibels. The # value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will -- cgit v1.2.3 From 0a361fa9e27b9d9533dffe34663efc3669205b86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Jun 2017 03:07:02 -0700 Subject: "Convert" the QSA backend to the new API I say "convert" because it takes the lazy way and essentially just embeds the wrappers into the backend. It's done this way because I lack the means to check any changes, even syntactically. This also means the device's ExtraData field is still needed. However, this does mean all the backends are now using the new API. Code related to the old interface can now be removed. --- Alc/ALc.c | 109 ++++++++------------------- Alc/backends/base.c | 154 -------------------------------------- Alc/backends/base.h | 3 +- Alc/backends/qsa.c | 185 +++++++++++++++++++++++++++++++++++++++++----- OpenAL32/Include/alMain.h | 19 ----- 5 files changed, 201 insertions(+), 269 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7f6cf279..6642c334 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -54,57 +54,52 @@ 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 } static struct BackendInfo BackendList[] = { #ifdef HAVE_JACK - { "jack", ALCjackBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "jack", ALCjackBackendFactory_getFactory }, #endif #ifdef HAVE_PULSEAUDIO - { "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "pulse", ALCpulseBackendFactory_getFactory }, #endif #ifdef HAVE_ALSA - { "alsa", ALCalsaBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "alsa", ALCalsaBackendFactory_getFactory }, #endif #ifdef HAVE_COREAUDIO - { "core", ALCcoreAudioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "core", ALCcoreAudioBackendFactory_getFactory }, #endif #ifdef HAVE_OSS - { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "oss", ALCossBackendFactory_getFactory }, #endif #ifdef HAVE_SOLARIS - { "solaris", ALCsolarisBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "solaris", ALCsolarisBackendFactory_getFactory }, #endif #ifdef HAVE_SNDIO - { "sndio", ALCsndioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "sndio", ALCsndioBackendFactory_getFactory }, #endif #ifdef HAVE_QSA - { "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs }, + { "qsa", ALCqsaBackendFactory_getFactory }, #endif #ifdef HAVE_MMDEVAPI - { "mmdevapi", ALCmmdevBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "mmdevapi", ALCmmdevBackendFactory_getFactory }, #endif #ifdef HAVE_DSOUND - { "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "dsound", ALCdsoundBackendFactory_getFactory }, #endif #ifdef HAVE_WINMM - { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "winmm", ALCwinmmBackendFactory_getFactory }, #endif #ifdef HAVE_PORTAUDIO - { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "port", ALCportBackendFactory_getFactory }, #endif #ifdef HAVE_OPENSL - { "opensl", ALCopenslBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "opensl", ALCopenslBackendFactory_getFactory }, #endif - { "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "null", ALCnullBackendFactory_getFactory }, #ifdef HAVE_WAVE - { "wave", ALCwaveBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, + { "wave", ALCwaveBackendFactory_getFactory }, #endif }; static ALsizei BackendListSize = COUNTOF(BackendList); @@ -1091,43 +1086,20 @@ static void alc_initconfig(void) for(i = 0;i < BackendListSize && (!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)) + 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(BackendList[i].Funcs.OpenPlayback && !PlaybackBackend.name) + if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback)) { PlaybackBackend = BackendList[i]; TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); } - if(BackendList[i].Funcs.OpenCapture && !CaptureBackend.name) + if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture)) { CaptureBackend = BackendList[i]; TRACE("Added \"%s\" for capture\n", CaptureBackend.name); @@ -1299,13 +1271,8 @@ static void alc_deinit(void) for(i = 0;i < BackendListSize;i++) { - if(!BackendList[i].getFactory) - BackendList[i].Deinit(); - else - { - ALCbackendFactory *factory = BackendList[i].getFactory(); - V0(factory,deinit)(); - } + ALCbackendFactory *factory = BackendList[i].getFactory(); + V0(factory,deinit)(); } { ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); @@ -1321,18 +1288,16 @@ static void alc_deinit(void) ************************************************/ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type) { + ALCbackendFactory *factory; + DO_INITCONFIG(); LockLists(); alstr_clear(list); - if(backendinfo->Probe) - backendinfo->Probe(type); - else if(backendinfo->getFactory) - { - ALCbackendFactory *factory = backendinfo->getFactory(); - V(factory,probe)(type); - } + factory = backendinfo->getFactory(); + V(factory,probe)(type); + UnlockLists(); } static void ProbeAllDevicesList(void) @@ -3830,6 +3795,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) */ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { + ALCbackendFactory *factory; const ALCchar *fmt; ALCdevice *device; ALCenum err; @@ -3916,14 +3882,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumUpdates = 3; device->UpdateSize = 1024; - if(!PlaybackBackend.getFactory) - device->Backend = create_backend_wrapper(device, &PlaybackBackend.Funcs, - ALCbackend_Playback); - else - { - ALCbackendFactory *factory = PlaybackBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); - } + factory = PlaybackBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); if(!device->Backend) { al_free(device); @@ -4151,6 +4111,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ************************************************/ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) { + ALCbackendFactory *factory; ALCdevice *device = NULL; ALCenum err; ALCsizei i; @@ -4208,14 +4169,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->ChannelDelay[i].Buffer = NULL; } - if(!CaptureBackend.getFactory) - device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs, - ALCbackend_Capture); - else - { - ALCbackendFactory *factory = CaptureBackend.getFactory(); - device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); - } + factory = CaptureBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); if(!device->Backend) { al_free(device); diff --git a/Alc/backends/base.c b/Alc/backends/base.c index 902c4310..5f568d8e 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -79,157 +79,3 @@ void ALCbackend_unlock(ALCbackend *self) void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self)) { } - - -/* Wrappers to use an old-style backend with the new interface. */ -typedef struct PlaybackWrapper { - DERIVE_FROM_TYPE(ALCbackend); - - const BackendFuncs *Funcs; -} PlaybackWrapper; - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs); -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 DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) -DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(PlaybackWrapper, ALCbackend, self); - - self->Funcs = funcs; -} - -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->OpenPlayback(device, name); -} - -static void PlaybackWrapper_close(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->ClosePlayback(device); -} - -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->ResetPlayback(device); -} - -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->StartPlayback(device); -} - -static void PlaybackWrapper_stop(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->StopPlayback(device); -} - - -typedef struct CaptureWrapper { - DERIVE_FROM_TYPE(ALCbackend); - - const BackendFuncs *Funcs; -} CaptureWrapper; - -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs); -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 DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) -DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); - -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(CaptureWrapper, ALCbackend, self); - - self->Funcs = funcs; -} - -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->OpenCapture(device, name); -} - -static void CaptureWrapper_close(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->CloseCapture(device); -} - -static ALCboolean CaptureWrapper_start(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->StartCapture(device); - return ALC_TRUE; -} - -static void CaptureWrapper_stop(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->StopCapture(device); -} - -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->CaptureSamples(device, buffer, samples); -} - -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->AvailableSamples(device); -} - - -ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - PlaybackWrapper *backend; - - NEW_OBJ(backend, PlaybackWrapper)(device, funcs); - if(!backend) return NULL; - - return STATIC_CAST(ALCbackend, backend); - } - - if(type == ALCbackend_Capture) - { - CaptureWrapper *backend; - - NEW_OBJ(backend, CaptureWrapper)(device, funcs); - if(!backend) return NULL; - - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 961a4d1a..8464fdee 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -142,6 +142,7 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); +ALCbackendFactory *ALCqsaBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); @@ -151,6 +152,4 @@ ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); -ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type); - #endif /* AL_BACKENDS_BASE_H */ diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 9da55b59..15c264aa 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -853,27 +853,145 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s return ALC_NO_ERROR; } -static const 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 -}; -ALCboolean alc_qsa_init(BackendFuncs* func_list) +/* 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 DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) +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 qsa_open_playback(device, name); +} + +static void PlaybackWrapper_close(PlaybackWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + qsa_close_playback(device); +} + +static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return qsa_reset_playback(device); +} + +static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return qsa_start_playback(device); +} + +static void PlaybackWrapper_stop(PlaybackWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + qsa_stop_playback(device); +} + + +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 DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) +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) { - *func_list = qsa_funcs; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return qsa_open_capture(device, name); +} + +static void CaptureWrapper_close(CaptureWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + qsa_close_capture(device); +} + +static ALCboolean CaptureWrapper_start(CaptureWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + qsa_start_capture(device); return ALC_TRUE; } -void alc_qsa_deinit(void) +static void CaptureWrapper_stop(CaptureWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + qsa_stop_capture(device); +} + +static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return qsa_capture_samples(device, buffer, samples); +} + +static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + return qsa_available_samples(device); +} + + +typedef struct ALCqsaBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCqsaBackendFactory; +#define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); +static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); +static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type); +static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); + +static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)) { #define FREE_NAME(iter) free((iter)->name) VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); @@ -884,7 +1002,14 @@ void alc_qsa_deinit(void) #undef FREE_NAME } -void alc_qsa_probe(enum DevProbe type) +static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type) { switch (type) { @@ -913,3 +1038,29 @@ void alc_qsa_probe(enum DevProbe type) break; } } + +static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + PlaybackWrapper *backend; + NEW_OBJ(backend, PlaybackWrapper)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + CaptureWrapper *backend; + NEW_OBJ(backend, CaptureWrapper)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCqsaBackendFactory_getFactory(void) +{ + static ALCqsaBackendFactory factory = ALCQSABACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e5dd8c26..8cedee94 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -436,25 +436,6 @@ enum DevProbe { CAPTURE_DEVICE_PROBE }; -typedef struct { - ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*); - void (*ClosePlayback)(ALCdevice*); - ALCboolean (*ResetPlayback)(ALCdevice*); - ALCboolean (*StartPlayback)(ALCdevice*); - void (*StopPlayback)(ALCdevice*); - - ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*); - void (*CloseCapture)(ALCdevice*); - void (*StartCapture)(ALCdevice*); - void (*StopCapture)(ALCdevice*); - ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint); - ALCuint (*AvailableSamples)(ALCdevice*); -} BackendFuncs; - -ALCboolean alc_qsa_init(BackendFuncs *func_list); -void alc_qsa_deinit(void); -void alc_qsa_probe(enum DevProbe type); - struct ALCbackend; -- cgit v1.2.3 From 36edd80073e2f009362b323a6cf8844cb65f35ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Jun 2017 04:14:56 -0700 Subject: Update ChangeLog for the dither-depth config option --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6d79fde0..258060cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,8 @@ openal-soft-1.18.1: Added correct retrieval of the executable's path on FreeBSD. + Added a config option to specify the dithering depth. + openal-soft-1.18.0: Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions. -- cgit v1.2.3 From e09468cdcab86de2d41d50b1d9530a970b83e65b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Jun 2017 00:17:11 -0700 Subject: Trace if dithering is enabled --- Alc/ALc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 6642c334..1121b631 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2187,9 +2187,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->SourcesMax, device->NumMonoSources, device->NumStereoSources, device->AuxiliaryEffectSlotMax, device->NumAuxSends); - if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "dither", 1)) - device->DitherDepth = 0.0f; - else + device->DitherDepth = 0.0f; + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "dither", 1)) { ALint depth = 0; ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "dither-depth", &depth); @@ -2215,6 +2214,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) depth = 24; device->DitherDepth = (depth > 0) ? powf(2.0f, (ALfloat)(depth-1)) : 0.0f; } + if(!(device->DitherDepth > 0.0f)) + TRACE("Dithering disabled\n"); + else + TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f, + device->DitherDepth); if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) gainLimiter = val ? ALC_TRUE : ALC_FALSE; -- cgit v1.2.3 From 6fcbb7c73838ffd910df7dcdc85096937ee9e327 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Jun 2017 11:34:26 -0700 Subject: Remove an unnecessary variable --- Alc/ALu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f6e5cb12..fb10d7f2 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1777,14 +1777,13 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei OutChannels = device->RealOut.NumChannels; - struct Compressor *Limiter = device->Limiter; /* Use NFCtrlData for temp value storage. */ ApplyDistanceComp(OutBuffer, device->ChannelDelay, device->NFCtrlData, SamplesToDo, OutChannels); - if(Limiter) - ApplyCompression(Limiter, OutChannels, SamplesToDo, OutBuffer); + if(device->Limiter) + ApplyCompression(device->Limiter, OutChannels, SamplesToDo, OutBuffer); if(device->DitherDepth > 0.0f) ApplyDither(OutBuffer, &device->DitherSeed, device->DitherDepth, SamplesToDo, -- cgit v1.2.3 From 552d3a85aff6290c5bc06e4093c7c7ebfd486456 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Jun 2017 23:05:11 -0700 Subject: Workaround log2f missing on Android --- Alc/ALc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1121b631..6d5454f5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1214,6 +1214,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void* UNUSED(reserved)) return JNI_VERSION_1_4; } +/* Android doesn't have log2f, really? */ +#define log2f(x) (logf(x) / logf(2.0f)) #endif -- cgit v1.2.3 From 31b02e044f689e9d586a935c924e4a989371823e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Jun 2017 13:58:32 -0700 Subject: Trace the capture converter formats for mmdevapi --- Alc/backends/mmdevapi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 43d8429d..875a3e4d 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1744,6 +1744,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) ERR("Failed to create stereo-to-mono converter\n"); return E_FAIL; } + TRACE("Created stereo-to-mono converter\n"); /* The channel converter always outputs float, so change the input type * for the resampler/type-converter. */ @@ -1758,6 +1759,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) ERR("Failed to create mono-to-stereo converter\n"); return E_FAIL; } + TRACE("Created mono-to-stereo converter\n"); srcType = DevFmtFloat; } @@ -1775,6 +1777,10 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) OutputType.Format.nSamplesPerSec); return E_FAIL; } + TRACE("Created converter for format, dst: %s %s %uhz, src: %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, OutputType.Format.wBitsPerSample, + OutputType.Format.nSamplesPerSec); } hr = IAudioClient_Initialize(self->client, -- cgit v1.2.3 From d1077795deb8367d8e6fc39ecfc5f51b3c39d9e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Jun 2017 15:07:24 -0700 Subject: Stop conversion when no more source samples are available --- Alc/converter.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index f1a3a96b..bc9d5087 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -219,7 +219,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs const ALsizei increment = converter->mIncrement; ALsizei pos = 0; - while(pos < dstframes) + while(pos < dstframes && *srcframes > 0) { ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16); ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16); @@ -241,7 +241,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs } *src = (const ALbyte*)*src + SrcFrameSize*-prepcount; *srcframes += prepcount; - prepcount = 0; + converter->mSrcPrepCount = 0; + continue; } toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES)); @@ -253,7 +254,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs */ for(chan = 0;chan < converter->mNumChannels;chan++) LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount], - (const ALbyte*)src + converter->mSrcTypeSize*chan, + (const ALbyte*)*src + converter->mSrcTypeSize*chan, converter->mNumChannels, converter->mSrcType, toread ); -- cgit v1.2.3 From e07166e93cf392e3dac0a8ee71696a8d6d5114fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Jun 2017 05:19:24 -0700 Subject: Add a recording example app --- CMakeLists.txt | 14 ++ examples/alrecord.c | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 examples/alrecord.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fcdb964..f8f10fe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1409,6 +1409,20 @@ IF(ALSOFT_TESTS) ENDIF() IF(ALSOFT_EXAMPLES) + ADD_EXECUTABLE(alrecord examples/alrecord.c ${COMMON_OBJS}) + TARGET_LINK_LIBRARIES(alrecord OpenAL) + SET_PROPERTY(TARGET alrecord APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + + IF(ALSOFT_INSTALL) + INSTALL(TARGETS alrecord + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + ENDIF() + + MESSAGE(STATUS "Building example programs") + IF(SDL2_FOUND) IF(SDL_SOUND_FOUND) SET(EX_COMMON_OBJS examples/common/alhelpers.c) diff --git a/examples/alrecord.c b/examples/alrecord.c new file mode 100644 index 00000000..da8d20ce --- /dev/null +++ b/examples/alrecord.c @@ -0,0 +1,363 @@ +/* + * OpenAL Recording Example + * + * Copyright (c) 2017 by Chris Robinson + * + * 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 a relatively simple recorder. */ + +#include +#include +#include +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#include "common/alhelpers.h" + + +#if defined(_WIN64) +#define SZFMT "%I64u" +#elif defined(_WIN32) +#define SZFMT "%u" +#else +#define SZFMT "%zu" +#endif + + +static void fwrite16le(ALushort val, FILE *f) +{ + ALubyte data[2] = { val&0xff, (val>>8)&0xff }; + fwrite(data, 1, 2, f); +} + +static void fwrite32le(ALuint val, FILE *f) +{ + ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff }; + fwrite(data, 1, 4, f); +} + + +typedef struct Recorder { + ALCdevice *mDevice; + + FILE *mFile; + long mDataSizeOffset; + size_t mDataSize; + float mRecTime; + + int mChannels; + int mBits; + int mSampleRate; + size_t mFrameSize; + ALbyte *mBuffer; + ALsizei mBufferSize; +} Recorder; + +int main(int argc, char **argv) +{ + static const char optlist[] = +" --channels/-c Set channel count (1 or 2)\n" +" --bits/-b Set channel count (8 or 16)\n" +" --rate/-r Set sample rate (8000 to 96000)\n" +" --time/-t + + 0 + Playback @@ -128,7 +131,7 @@ to stereo output. 380 20 - 91 + 93 29 @@ -1924,27 +1927,6 @@ be useful for preventing those extensions from being used. Effects - - - - 10 - 60 - 161 - 21 - - - - Uses a simpler reverb method to emulate the EAX reverb -effect. This may slightly improve performance at the cost of -some quality. - - - Qt::RightToLeft - - - Emulate EAX Reverb: - - @@ -2148,7 +2130,7 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 123 + 125 29 -- cgit v1.2.3 From 9e2eb5dc231d835bf78a7225b6b0def74d0220ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Jan 2018 22:01:46 -0800 Subject: Rename the device's temp buffer storage to be more generic --- Alc/ALu.c | 3 +-- Alc/mixer.c | 15 ++++++++++----- OpenAL32/Include/alMain.h | 7 ++----- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e5c44a96..7c5c676c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1814,8 +1814,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesToDo, Channels); } - /* Use NFCtrlData for temp value storage. */ - ApplyDistanceComp(Buffer, device->ChannelDelay, device->NFCtrlData, + ApplyDistanceComp(Buffer, device->ChannelDelay, device->TempBuffer[0], SamplesToDo, Channels); if(device->Limiter) diff --git a/Alc/mixer.c b/Alc/mixer.c index a7f0f302..4a1230a7 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -268,6 +268,11 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter } +/* This function uses these device temp buffers. */ +#define SOURCE_DATA_BUF 0 +#define RESAMPLED_BUF 1 +#define FILTERED_BUF 2 +#define NFC_DATA_BUF 3 ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) { ALbufferlistitem *BufferListItem; @@ -337,7 +342,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei for(chan = 0;chan < NumChannels;chan++) { const ALfloat *ResampledData; - ALfloat *SrcData = Device->SourceData; + ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; ALsizei FilledAmt; /* Load the previous samples into the source data first, and clear the rest. */ @@ -489,14 +494,14 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei /* Now resample, then filter and mix to the appropriate outputs. */ ResampledData = Resample(&voice->ResampleState, &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment, - Device->ResampledData, DstBufferSize + Device->TempBuffer[RESAMPLED_BUF], DstBufferSize ); { DirectParams *parms = &voice->Direct.Params[chan]; const ALfloat *samples; samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->FilteredData, + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, voice->Direct.FilterType ); if(!(voice->Flags&VOICE_HAS_HRTF)) @@ -511,7 +516,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ); else { - ALfloat *nfcsamples = Device->NFCtrlData; + ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; ALsizei chanoffset = 0; MixSamples(samples, @@ -635,7 +640,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei continue; samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->FilteredData, + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], ResampledData, DstBufferSize, voice->Send[send].FilterType ); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 37baabed..74b01b09 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -748,11 +748,8 @@ struct ALCdevice_struct ALuint64 ClockBase; ALuint SamplesDone; - /* Temp storage used for each source when mixing. */ - alignas(16) ALfloat SourceData[BUFFERSIZE]; - alignas(16) ALfloat ResampledData[BUFFERSIZE]; - alignas(16) ALfloat FilteredData[BUFFERSIZE]; - alignas(16) ALfloat NFCtrlData[BUFFERSIZE]; + /* Temp storage used for mixer processing. */ + alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; /* The "dry" path corresponds to the main output. */ struct { -- cgit v1.2.3 From de8c5b18248ee5d121cbd4b34b9af94f5e16df35 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Jan 2018 23:21:16 -0800 Subject: Combine the chorus and flanger processing functions Given that they're nearly identical, it should be relatively simple to use the same effect state to process either of them, similar to the reverbs. The big differences seem to be the delay range (much shorter with flanger) and the defaults. --- Alc/effects/chorus.c | 180 +++++++++++++++++-- Alc/effects/flanger.c | 420 -------------------------------------------- CMakeLists.txt | 1 - OpenAL32/Include/alEffect.h | 11 +- OpenAL32/alEffect.c | 12 +- 5 files changed, 171 insertions(+), 453 deletions(-) delete mode 100644 Alc/effects/flanger.c diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index caea6e93..d028dbb0 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -30,9 +30,12 @@ #include "alu.h" -enum ChorusWaveForm { - CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE, - CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID +static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); +static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch"); + +enum WaveForm { + WF_Sinusoid, + WF_Triangle }; typedef struct ALchorusState { @@ -54,7 +57,7 @@ typedef struct ALchorusState { } Gains[2]; /* effect parameters */ - enum ChorusWaveForm waveform; + enum WaveForm waveform; ALint delay; ALfloat depth; ALfloat feedback; @@ -79,7 +82,7 @@ static void ALchorusState_Construct(ALchorusState *state) state->offset = 0; state->lfo_offset = 0; state->lfo_range = 1; - state->waveform = CWF_Triangle; + state->waveform = WF_Triangle; } static ALvoid ALchorusState_Destruct(ALchorusState *state) @@ -92,9 +95,10 @@ static ALvoid ALchorusState_Destruct(ALchorusState *state) static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device) { + const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); ALsizei maxlen; - maxlen = fastf2i(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1; + maxlen = fastf2i(max_delay * 2.0f * Device->Frequency) + 1; maxlen = NextPowerOf2(maxlen); if(maxlen != state->BufferLength) @@ -126,10 +130,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte switch(props->Chorus.Waveform) { case AL_CHORUS_WAVEFORM_TRIANGLE: - state->waveform = CWF_Triangle; + state->waveform = WF_Triangle; break; case AL_CHORUS_WAVEFORM_SINUSOID: - state->waveform = CWF_Sinusoid; + state->waveform = WF_Sinusoid; break; } @@ -169,10 +173,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte state->lfo_range = lfo_range; switch(state->waveform) { - case CWF_Triangle: + case WF_Triangle: state->lfo_scale = 4.0f / state->lfo_range; break; - case CWF_Sinusoid: + case WF_Sinusoid: state->lfo_scale = F_TAU / state->lfo_range; break; } @@ -224,19 +228,19 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c ALint moddelays[2][256]; ALfloat temps[2][256]; - if(state->waveform == CWF_Triangle) + if(state->waveform == WF_Sinusoid) { - GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, + GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, state->depth, state->delay, todo); - GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, + GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, state->lfo_range, state->lfo_scale, state->depth, state->delay, todo); } - else /*if(state->waveform == CWF_Sinusoid)*/ + else /*if(state->waveform == WF_Triangle)*/ { - GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, + GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, state->depth, state->delay, todo); - GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, + GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, state->lfo_range, state->lfo_scale, state->depth, state->delay, todo); } @@ -420,3 +424,147 @@ void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum par } DEFINE_ALEFFECT_VTABLE(ALchorus); + + +/* Flanger is basically a chorus with a really short delay. They can both use + * the same processing functions, so piggyback flanger on the chorus functions. + */ +typedef struct ALflangerStateFactory { + DERIVE_FROM_TYPE(ALeffectStateFactory); +} ALflangerStateFactory; + +ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory)) +{ + ALchorusState *state; + + NEW_OBJ0(state, ALchorusState)(); + if(!state) return NULL; + + 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->Chorus.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->Chorus.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->Chorus.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->Chorus.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->Chorus.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->Chorus.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->Chorus.Waveform; + break; + + case AL_FLANGER_PHASE: + *val = props->Chorus.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->Chorus.Rate; + break; + + case AL_FLANGER_DEPTH: + *val = props->Chorus.Depth; + break; + + case AL_FLANGER_FEEDBACK: + *val = props->Chorus.Feedback; + break; + + case AL_FLANGER_DELAY: + *val = props->Chorus.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/flanger.c b/Alc/effects/flanger.c deleted file mode 100644 index b1fd2fda..00000000 --- a/Alc/effects/flanger.c +++ /dev/null @@ -1,420 +0,0 @@ -/** - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - - -enum FlangerWaveForm { - FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE, - FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID -}; - -typedef struct ALflangerState { - DERIVE_FROM_TYPE(ALeffectState); - - ALfloat *SampleBuffer; - ALsizei BufferLength; - ALsizei offset; - - ALsizei lfo_offset; - ALsizei lfo_range; - ALfloat lfo_scale; - ALint lfo_disp; - - /* Gains for left and right sides */ - struct { - ALfloat Current[MAX_OUTPUT_CHANNELS]; - ALfloat Target[MAX_OUTPUT_CHANNELS]; - } Gains[2]; - - /* effect parameters */ - enum FlangerWaveForm waveform; - ALint delay; - ALfloat depth; - ALfloat feedback; -} ALflangerState; - -static ALvoid ALflangerState_Destruct(ALflangerState *state); -static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device); -static ALvoid ALflangerState_update(ALflangerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALflangerState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState); - - -static void ALflangerState_Construct(ALflangerState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALflangerState, ALeffectState, state); - - state->BufferLength = 0; - state->SampleBuffer = NULL; - state->offset = 0; - state->lfo_offset = 0; - state->lfo_range = 1; - state->waveform = FWF_Triangle; -} - -static ALvoid ALflangerState_Destruct(ALflangerState *state) -{ - al_free(state->SampleBuffer); - state->SampleBuffer = NULL; - - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device) -{ - ALsizei maxlen; - - maxlen = fastf2i(AL_FLANGER_MAX_DELAY * 2.0f * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); - - if(maxlen != state->BufferLength) - { - void *temp = al_calloc(16, maxlen * sizeof(ALfloat)); - if(!temp) return AL_FALSE; - - al_free(state->SampleBuffer); - state->SampleBuffer = temp; - - state->BufferLength = maxlen; - } - - memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat)); - memset(state->Gains, 0, sizeof(state->Gains)); - - return AL_TRUE; -} - -static ALvoid ALflangerState_update(ALflangerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALsizei mindelay = maxi(MAX_PRE_SAMPLES, MAX_POST_SAMPLES) << FRACTIONBITS; - const ALCdevice *device = context->Device; - ALfloat frequency = (ALfloat)device->Frequency; - ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat rate; - ALint phase; - - switch(props->Flanger.Waveform) - { - case AL_FLANGER_WAVEFORM_TRIANGLE: - state->waveform = FWF_Triangle; - break; - case AL_FLANGER_WAVEFORM_SINUSOID: - state->waveform = FWF_Sinusoid; - break; - } - - /* The LFO depth is scaled to be relative to the sample delay. Clamp the - * delay and depth to allow enough padding for resampling. - */ - state->delay = maxi(fastf2i(props->Flanger.Delay*frequency*FRACTIONONE + 0.5f), - mindelay); - state->depth = minf(props->Flanger.Depth * state->delay, state->delay - mindelay); - - state->feedback = props->Flanger.Feedback; - - /* Gains for left and right sides */ - CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); - CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); - - phase = props->Flanger.Phase; - rate = props->Flanger.Rate; - if(!(rate > 0.0f)) - { - state->lfo_offset = 0; - state->lfo_range = 1; - state->lfo_scale = 0.0f; - state->lfo_disp = 0; - } - else - { - /* Calculate LFO coefficient (number of samples per cycle). Limit the - * max range to avoid overflow when calculating the displacement. - */ - ALsizei lfo_range = mini(fastf2i(frequency/rate + 0.5f), INT_MAX/360 - 180); - - state->lfo_offset = fastf2i((ALfloat)state->lfo_offset/state->lfo_range* - lfo_range + 0.5f) % lfo_range; - state->lfo_range = lfo_range; - switch(state->waveform) - { - case FWF_Triangle: - state->lfo_scale = 4.0f / state->lfo_range; - break; - case FWF_Sinusoid: - state->lfo_scale = F_TAU / state->lfo_range; - break; - } - - /* Calculate lfo phase displacement */ - if(phase < 0) phase = 360 + phase; - state->lfo_disp = (state->lfo_range*phase + 180) / 360; - } -} - -static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range, - const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay, - const ALsizei todo) -{ - ALsizei i; - for(i = 0;i < todo;i++) - { - delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay; - offset = (offset+1)%lfo_range; - } -} - -static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - const ALsizei bufmask = state->BufferLength-1; - const ALfloat feedback = state->feedback; - const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS; - ALfloat *restrict delaybuf = state->SampleBuffer; - ALsizei offset = state->offset; - ALsizei i, c; - ALsizei base; - - for(base = 0;base < SamplesToDo;) - { - const ALsizei todo = mini(256, SamplesToDo-base); - ALint moddelays[2][256]; - ALfloat temps[2][256]; - - if(state->waveform == FWF_Triangle) - { - GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - else /*if(state->waveform == FWF_Sinusoid)*/ - { - GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale, - state->depth, state->delay, todo); - GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range, - state->lfo_range, state->lfo_scale, state->depth, state->delay, - todo); - } - state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range; - - for(i = 0;i < todo;i++) - { - ALint delay; - ALfloat mu; - - // Feed the buffer's input first (necessary for delays < 1). - delaybuf[offset&bufmask] = SamplesIn[0][base+i]; - - // Tap for the left output. - delay = offset - (moddelays[0][i]>>FRACTIONBITS); - mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Tap for the right output. - delay = offset - (moddelays[1][i]>>FRACTIONBITS); - mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE); - temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay ) & bufmask], - delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask], - mu); - - // Accumulate feedback from the average delay. - delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback; - offset++; - } - - for(c = 0;c < 2;c++) - MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current, - state->Gains[c].Target, 0, base, todo); - - base += todo; - } - - state->offset = offset; -} - - -typedef struct ALflangerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALflangerStateFactory; - -ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory)) -{ - ALflangerState *state; - - NEW_OBJ0(state, ALflangerState)(); - if(!state) return NULL; - - 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/CMakeLists.txt b/CMakeLists.txt index eebba3f7..95b73c25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -724,7 +724,6 @@ SET(ALC_OBJS Alc/ALc.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 diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index af488aab..bec50f7d 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -97,7 +97,7 @@ typedef union ALeffectProps { ALfloat Depth; ALfloat Feedback; ALfloat Delay; - } Chorus; + } Chorus; /* Also Flanger */ struct { ALboolean OnOff; @@ -134,15 +134,6 @@ typedef union ALeffectProps { ALfloat HighGain; } Equalizer; - struct { - ALint Waveform; - ALint Phase; - ALfloat Rate; - ALfloat Depth; - ALfloat Feedback; - ALfloat Delay; - } Flanger; - struct { ALfloat Frequency; ALfloat HighPassCutoff; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 6761e661..0dac429a 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -493,12 +493,12 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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; + effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; + effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE; + effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE; + effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; + effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; + effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; SET_VTABLE1(ALflanger, effect); break; case AL_EFFECT_RING_MODULATOR: -- cgit v1.2.3 From ef63ec3fe9364d2036878fa871f49ee60f84482b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Jan 2018 23:55:59 -0800 Subject: Use one macro to handle both resample padding sizes --- Alc/converter.c | 22 +++++++++++----------- Alc/converter.h | 2 +- Alc/effects/chorus.c | 2 +- Alc/mixer.c | 18 +++++++++--------- OpenAL32/Include/alu.h | 11 +++++------ 5 files changed, 27 insertions(+), 28 deletions(-) diff --git a/Alc/converter.c b/Alc/converter.c index 56dbc79e..8cba04a1 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -205,8 +205,8 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe return 0; } - if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES && - MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= srcframes) + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes) { /* Not enough input samples to generate an output sample. */ return 0; @@ -214,7 +214,7 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe DataSize64 = prepcount; DataSize64 += srcframes; - DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; @@ -256,10 +256,10 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs converter->mSrcPrepCount = 0; continue; } - toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES)); + toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2); - if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES && - MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= toread) + if(prepcount < MAX_RESAMPLE_PADDING*2 && + MAX_RESAMPLE_PADDING*2 - prepcount >= toread) { /* Not enough input samples to generate an output sample. Store * what we're given for later. @@ -277,7 +277,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs DataSize64 = prepcount; DataSize64 += toread; - DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; @@ -310,7 +310,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs sizeof(converter->Chan[chan].mPrevSamples)); else { - size_t len = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, prepcount+toread-SrcDataEnd); + size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd); memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd], len*sizeof(ALfloat)); memset(converter->Chan[chan].mPrevSamples+len, 0, @@ -319,7 +319,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs /* Now resample, and store the result in the output buffer. */ ResampledData = converter->mResample(&converter->mState, - SrcData+MAX_PRE_SAMPLES, DataPosFrac, increment, + SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment, DstData, DstSize ); @@ -331,8 +331,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs * fractional offset. */ DataPosFrac += increment*DstSize; - converter->mSrcPrepCount = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, - prepcount+toread-(DataPosFrac>>FRACTIONBITS)); + converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS), + MAX_RESAMPLE_PADDING*2); converter->mFracOffset = DataPosFrac & FRACTIONMASK; /* Update the src and dst pointers in case there's still more to do. */ diff --git a/Alc/converter.h b/Alc/converter.h index 9934fa4b..b58fd831 100644 --- a/Alc/converter.h +++ b/Alc/converter.h @@ -26,7 +26,7 @@ typedef struct SampleConverter { alignas(16) ALfloat mDstSamples[BUFFERSIZE]; struct { - alignas(16) ALfloat mPrevSamples[MAX_PRE_SAMPLES+MAX_POST_SAMPLES]; + alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2]; } Chan[]; } SampleConverter; diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index d028dbb0..65d2225b 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -120,7 +120,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { - const ALsizei mindelay = maxi(MAX_PRE_SAMPLES, MAX_POST_SAMPLES) << FRACTIONBITS; + const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS; const ALCdevice *device = Context->Device; ALfloat frequency = (ALfloat)device->Frequency; ALfloat coeffs[MAX_AMBI_COEFFS]; diff --git a/Alc/mixer.c b/Alc/mixer.c index 4a1230a7..e6459fce 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -45,8 +45,7 @@ extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(MAX_PRE_SAMPLES >= 23, "MAX_PRE_SAMPLES must be at least 23!"); -static_assert(MAX_POST_SAMPLES >= 24, "MAX_POST_SAMPLES must be at least 24!"); +static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); enum Resampler ResamplerDefault = LinearResampler; @@ -320,12 +319,12 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei DataSize64 *= increment; DataSize64 += DataPosFrac+FRACTIONMASK; DataSize64 >>= FRACTIONBITS; - DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 += MAX_RESAMPLE_PADDING*2; SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); /* Figure out how many samples we can actually mix from this. */ DataSize64 = SrcBufferSize; - DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; + DataSize64 -= MAX_RESAMPLE_PADDING*2; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, @@ -346,9 +345,10 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei FilledAmt; /* Load the previous samples into the source data first, and clear the rest. */ - memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat)); - memset(SrcData+MAX_PRE_SAMPLES, 0, (SrcBufferSize-MAX_PRE_SAMPLES)*sizeof(ALfloat)); - FilledAmt = MAX_PRE_SAMPLES; + memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); + memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* + sizeof(ALfloat)); + FilledAmt = MAX_RESAMPLE_PADDING; if(isstatic) { @@ -488,12 +488,12 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei /* Store the last source samples used for next time. */ memcpy(voice->PrevSamples[chan], &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - MAX_PRE_SAMPLES*sizeof(ALfloat) + MAX_RESAMPLE_PADDING*sizeof(ALfloat) ); /* Now resample, then filter and mix to the appropriate outputs. */ ResampledData = Resample(&voice->ResampleState, - &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment, + &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, Device->TempBuffer[RESAMPLED_BUF], DstBufferSize ); { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 3fc677b2..fe1b19e9 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -23,11 +23,10 @@ #define MAX_PITCH (255) -/* Maximum number of buffer samples before the current pos needed for resampling. */ -#define MAX_PRE_SAMPLES 24 - -/* Maximum number of buffer samples after the current pos needed for resampling. */ -#define MAX_POST_SAMPLES 24 +/* Maximum number of samples to pad on either end of a buffer for resampling. + * Note that both the beginning and end need padding! + */ +#define MAX_RESAMPLE_PADDING 24 #ifdef __cplusplus @@ -282,7 +281,7 @@ typedef struct ALvoice { ALuint Offset; /* Number of output samples mixed since starting. */ - alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING]; InterpState ResampleState; -- cgit v1.2.3 From ea6b384980cc04eb6c17d22354f9ce4d0280d5a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jan 2018 19:13:41 -0800 Subject: Make a function pointer static --- Alc/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index e6459fce..01586f7c 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -52,7 +52,7 @@ enum Resampler ResamplerDefault = LinearResampler; MixerFunc MixSamples = Mix_C; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; -HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; +static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; static MixerFunc SelectMixer(void) { -- cgit v1.2.3 From 279799ad7020360e59763cbd80af82e202357c51 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Jan 2018 19:20:58 -0800 Subject: Don't return whether the bsinc filter cuts or not --- Alc/ALu.c | 30 ++++++++---------------------- OpenAL32/Include/alu.h | 2 +- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 7c5c676c..25aa5c03 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -208,34 +208,21 @@ void aluInit(void) * modified for use with an interpolated increment for buttery-smooth pitch * changes. */ -ALboolean BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) +void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) { - ALboolean uncut = AL_TRUE; ALfloat sf; ALsizei si; if(increment > FRACTIONONE) { sf = (ALfloat)FRACTIONONE / increment; - if(sf < table->scaleBase) - { - /* Signal has been completely cut. The return result can be used - * to skip the filter (and output zeros) as an optimization. - */ - sf = 0.0f; - si = 0; - uncut = AL_FALSE; - } - else - { - sf = (BSINC_SCALE_COUNT - 1) * (sf - table->scaleBase) * table->scaleRange; - si = fastf2i(sf); - /* The interpolation factor is fit to this diagonally-symmetric - * curve to reduce the transition ripple caused by interpolating - * different scales of the sinc function. - */ - sf = 1.0f - cosf(asinf(sf - si)); - } + sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); + si = fastf2i(sf); + /* The interpolation factor is fit to this diagonally-symmetric curve + * to reduce the transition ripple caused by interpolating different + * scales of the sinc function. + */ + sf = 1.0f - cosf(asinf(sf - si)); } else { @@ -247,7 +234,6 @@ ALboolean BsincPrepare(const ALuint increment, BsincState *state, const BSincTab state->m = table->m[si]; state->l = -((state->m/2) - 1); state->filter = table->Tab + table->filterOffset[si]; - return uncut; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index fe1b19e9..6600e4e9 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -92,7 +92,7 @@ typedef const ALfloat* (*ResamplerFunc)(const InterpState *state, ALfloat *restrict dst, ALsizei dstlen ); -ALboolean BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); +void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table); extern const struct BSincTable bsinc12; extern const struct BSincTable bsinc24; -- cgit v1.2.3 From 15f9d15ba006fab67a3ace8b2560c3397e75b1aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 03:45:23 -0800 Subject: Avoid using macros to access anonymous structures --- Alc/ALc.c | 1 + Alc/ALu.c | 34 +++++++++++----------- Alc/bformatdec.c | 2 +- Alc/effects/chorus.c | 4 +-- Alc/effects/compressor.c | 2 +- Alc/effects/dedicated.c | 6 ++-- Alc/effects/distortion.c | 2 +- Alc/effects/echo.c | 4 +-- Alc/effects/equalizer.c | 2 +- Alc/effects/modulator.c | 2 +- Alc/effects/reverb.c | 6 ++-- Alc/mixer.c | 4 +-- Alc/panning.c | 29 ++++++++++--------- OpenAL32/Include/alMain.h | 73 ++++++++++++++++++++++++++--------------------- OpenAL32/Include/alu.h | 55 +++++++++++++++++++---------------- 15 files changed, 122 insertions(+), 104 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a5bf731b..cca88a8f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1637,6 +1637,7 @@ void SetDefaultChannelOrder(ALCdevice *device) } extern inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan); +extern inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan); /* ALCcontext_DeferUpdates diff --git a/Alc/ALu.c b/Alc/ALu.c index 25aa5c03..a4e9c1a4 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -520,8 +520,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const CalcDirectionCoeffs(Dir, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ - ComputePanningGains(Device->Dry, coeffs, DryGain*1.414213562f, - voice->Direct.Params[0].Gains.Target); + ComputeDryPanGains(&Device->Dry, coeffs, DryGain*1.414213562f, + voice->Direct.Params[0].Gains.Target); for(c = 1;c < num_channels;c++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) @@ -602,7 +602,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const voice->Direct.Buffer = Device->FOAOut.Buffer; voice->Direct.Channels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain, + ComputeFirstOrderGains(&Device->FOAOut, matrix.m[c], DryGain, voice->Direct.Params[c].Gains.Target); for(i = 0;i < NumSends;i++) { @@ -636,7 +636,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const int idx; for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) voice->Direct.Params[c].Gains.Target[j] = 0.0f; - if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1) + if((idx=GetChannelIdxByName(&Device->RealOut, chans[c].channel)) != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } @@ -830,13 +830,13 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const voice->Direct.Params[c].Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } continue; } - ComputePanningGains(Device->Dry, + ComputeDryPanGains(&Device->Dry, coeffs, DryGain * downmix_gain, voice->Direct.Params[c].Gains.Target ); } @@ -902,7 +902,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const voice->Direct.Params[c].Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { - int idx = GetChannelIdxByName(Device->RealOut, chans[c].channel); + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } @@ -918,7 +918,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); else CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - ComputePanningGains(Device->Dry, + ComputeDryPanGains(&Device->Dry, coeffs, DryGain, voice->Direct.Params[c].Gains.Target ); @@ -1725,8 +1725,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo ); - lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(device->RealOut, FrontRight); + lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); state = device->Hrtf; @@ -1761,8 +1761,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) } else if(device->Uhj_Encoder) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); if(lidx != -1 && ridx != -1) { /* Encode to stereo-compatible 2-channel UHJ output. */ @@ -1774,8 +1774,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) } else if(device->Bs2b) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); if(lidx != -1 && ridx != -1) { /* Apply binaural/crossfeed filter */ @@ -1791,9 +1791,9 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(device->Stablizer) { - int lidx = GetChannelIdxByName(device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(device->RealOut, FrontRight); - int cidx = GetChannelIdxByName(device->RealOut, FrontCenter); + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); assert(lidx >= 0 && ridx >= 0 && cidx >= 0); ApplyStablizer(device->Stablizer, Buffer, lidx, ridx, cidx, diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index ba6daac5..3efdfba9 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -549,7 +549,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, 1.0f, encgains[i]); + ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[i]); } /* Combine the matrices that do the in->virt and virt->out conversions diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 65d2225b..9be69f92 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -148,9 +148,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); + ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputePanningGains(device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); + ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); phase = props->Chorus.Phase; rate = props->Chorus.Rate; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 81f3c31b..4ae2acdb 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -86,7 +86,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontex STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i], + ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); } diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 32e5b49e..af8dc954 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -78,7 +78,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { int idx; - if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1) + if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1) { STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; @@ -90,7 +90,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext int idx; /* Dialog goes to the front-center speaker if it exists, otherwise it * plays from the front-center location. */ - if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1) + if((idx=GetChannelIdxByName(&device->RealOut, FrontCenter)) != -1) { STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; @@ -103,7 +103,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - ComputePanningGains(device->Dry, coeffs, Gain, state->gains); + ComputeDryPanGains(&device->Dry, coeffs, Gain, state->gains); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 546750d2..56931646 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -104,7 +104,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(device->Dry, slot->Params.Gain, state->Gain); + ComputeAmbientGains(&device->Dry, slot->Params.Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 97a70eea..3d538d9d 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -139,11 +139,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); /* Second tap panning */ CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputePanningGains(device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); } static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index f2428e95..8be689d2 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -132,7 +132,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i], + ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); /* Calculate coefficients for the each type of filter. Note that the shelf diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index af64448d..70751d87 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -148,7 +148,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i], + ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 711b4372..f6cd2b04 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1264,13 +1264,15 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection MATRIX_MULT(transform, rot, A2B); memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*earlyGain, State->Early.PanGain[i]); + ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], gain*earlyGain, + State->Early.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); MATRIX_MULT(transform, rot, A2B); memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(Device->FOAOut, transform.m[i], gain*lateGain, State->Late.PanGain[i]); + ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], gain*lateGain, + State->Late.PanGain[i]); #undef MATRIX_MULT } diff --git a/Alc/mixer.c b/Alc/mixer.c index 01586f7c..d99a4a8f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -548,8 +548,8 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALsizei fademix = 0; int lidx, ridx; - lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(Device->RealOut, FrontRight); + lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); assert(lidx != -1 && ridx != -1); if(!Counter) diff --git a/Alc/panning.c b/Alc/panning.c index aaae6bbd..37bf3ac9 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -37,6 +37,9 @@ extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline void ComputeAmbientGains(const DryMixParams *dry, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { @@ -382,41 +385,41 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp * and vice-versa. */ if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) - c = GetChannelIdxByName(device->RealOut, FrontLeft); + c = GetChannelIdxByName(&device->RealOut, FrontLeft); else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) - c = GetChannelIdxByName(device->RealOut, FrontRight); + c = GetChannelIdxByName(&device->RealOut, FrontRight); else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) - c = GetChannelIdxByName(device->RealOut, FrontCenter); + c = GetChannelIdxByName(&device->RealOut, FrontCenter); else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) { if(device->FmtChans == DevFmtX51Rear) - c = GetChannelIdxByName(device->RealOut, BackLeft); + c = GetChannelIdxByName(&device->RealOut, BackLeft); else - c = GetChannelIdxByName(device->RealOut, SideLeft); + c = GetChannelIdxByName(&device->RealOut, SideLeft); } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) { if(device->FmtChans == DevFmtX51Rear) - c = GetChannelIdxByName(device->RealOut, BackRight); + c = GetChannelIdxByName(&device->RealOut, BackRight); else - c = GetChannelIdxByName(device->RealOut, SideRight); + c = GetChannelIdxByName(&device->RealOut, SideRight); } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) { if(device->FmtChans == DevFmtX51) - c = GetChannelIdxByName(device->RealOut, SideLeft); + c = GetChannelIdxByName(&device->RealOut, SideLeft); else - c = GetChannelIdxByName(device->RealOut, BackLeft); + c = GetChannelIdxByName(&device->RealOut, BackLeft); } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) { if(device->FmtChans == DevFmtX51) - c = GetChannelIdxByName(device->RealOut, SideRight); + c = GetChannelIdxByName(&device->RealOut, SideRight); else - c = GetChannelIdxByName(device->RealOut, BackRight); + c = GetChannelIdxByName(&device->RealOut, BackRight); } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) - c = GetChannelIdxByName(device->RealOut, BackCenter); + c = GetChannelIdxByName(&device->RealOut, BackCenter); else { const char *name = alstr_get_cstr(conf->Speakers[i].Name); @@ -424,7 +427,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp char ch; if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16) - c = GetChannelIdxByName(device->RealOut, Aux0+n); + c = GetChannelIdxByName(&device->RealOut, Aux0+n); else { ERR("AmbDec speaker label \"%s\" not recognized\n", name); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 74b01b09..52f409ac 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -678,6 +678,35 @@ typedef struct DistanceComp { */ #define BUFFERSIZE 2048 +typedef struct DryMixParams { + AmbiConfig Ambi; + /* Number of coefficients in each Ambi.Coeffs to mix together (4 for first- + * order, 9 for second-order, etc). If the count is 0, Ambi.Map is used + * instead to map each output to a coefficient index. + */ + ALsizei CoeffCount; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei NumChannels; + ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; +} DryMixParams; + +typedef struct BFMixParams { + AmbiConfig Ambi; + /* Will only be 4 or 0. */ + ALsizei CoeffCount; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei NumChannels; +} BFMixParams; + +typedef struct RealMixParams { + enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; + + ALfloat (*Buffer)[BUFFERSIZE]; + ALsizei NumChannels; +} RealMixParams; + struct ALCdevice_struct { RefCount ref; @@ -752,38 +781,15 @@ struct ALCdevice_struct alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; /* The "dry" path corresponds to the main output. */ - struct { - AmbiConfig Ambi; - /* Number of coefficients in each Ambi.Coeffs to mix together (4 for - * first-order, 9 for second-order, etc). If the count is 0, Ambi.Map - * is used instead to map each output to a coefficient index. - */ - ALsizei CoeffCount; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; - ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; - } Dry; + DryMixParams Dry; /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ - struct { - AmbiConfig Ambi; - /* Will only be 4 or 0. */ - ALsizei CoeffCount; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; - } FOAOut; + BFMixParams FOAOut; /* "Real" output, which will be written to the device buffer. May alias the * dry buffer. */ - struct { - enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; - } RealOut; + RealMixParams RealOut; struct FrontStablizer *Stablizer; @@ -984,12 +990,6 @@ void SetDefaultWFXChannelOrder(ALCdevice *device); const ALCchar *DevFmtTypeString(enum DevFmtType type); const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); -/** - * GetChannelIdxByName - * - * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it - * doesn't exist. - */ inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum Channel chan) { ALint i; @@ -1000,7 +1000,14 @@ inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum } return -1; } -#define GetChannelIdxByName(x, c) GetChannelIndex((x).ChannelName, (c)) +/** + * GetChannelIdxByName + * + * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it + * doesn't exist. + */ +inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) +{ return GetChannelIndex(real->ChannelName, chan); } extern FILE *LogFile; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6600e4e9..e450d68e 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -459,35 +459,41 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, */ void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeAmbientGains * * Computes channel gains for ambient, omni-directional sounds. */ -#define ComputeAmbientGains(b, g, o) do { \ - if((b).CoeffCount > 0) \ - ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o); \ - else \ - ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o); \ -} while (0) -void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void ComputeAmbientGains(const DryMixParams *dry, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + if(dry->CoeffCount > 0) + ComputeAmbientGainsMC(dry->Ambi.Coeffs, dry->NumChannels, ingain, gains); + else + ComputeAmbientGainsBF(dry->Ambi.Map, dry->NumChannels, ingain, gains); +} + +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** - * ComputePanningGains + * ComputeDryPanGains * * Computes panning gains using the given channel decoder coefficients and the * pre-calculated direction or angle coefficients. */ -#define ComputePanningGains(b, c, g, o) do { \ - if((b).CoeffCount > 0) \ - ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\ - else \ - ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o); \ -} while (0) -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + if(dry->CoeffCount > 0) + ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, + coeffs, ingain, gains); + else + ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains); +} +void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeFirstOrderGains * @@ -495,14 +501,13 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con * a 1x4 'slice' of a transform matrix for the input channel, used to scale and * orient the sound samples. */ -#define ComputeFirstOrderGains(b, m, g, o) do { \ - if((b).CoeffCount > 0) \ - ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o); \ - else \ - ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o); \ -} while (0) -void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + if(foa->CoeffCount > 0) + ComputeFirstOrderGainsMC(foa->Ambi.Coeffs, foa->NumChannels, mtx, ingain, gains); + else + ComputeFirstOrderGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains); +} ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo); -- cgit v1.2.3 From 2c8e4467c3671aa0e5d77bbada1296ad1c44e624 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 03:53:25 -0800 Subject: Move some HRTF structures to hrtf.h --- Alc/hrtf.h | 31 +++++++++++++++++++++++++++++++ OpenAL32/Include/alMain.h | 32 ++------------------------------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 4fd774a7..aaee4a8d 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -15,6 +15,15 @@ #define HRTF_AMBI_MAX_CHANNELS 16 +#define HRTF_HISTORY_BITS (6) +#define HRTF_HISTORY_LENGTH (1< Date: Thu, 11 Jan 2018 04:34:51 -0800 Subject: Apply the distortion gain to the mixing gains --- Alc/effects/distortion.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 56931646..837e4d3b 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -79,9 +79,6 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex ALfloat cutoff; ALfloat edge; - /* Store distorted signal attenuation settings. */ - state->attenuation = props->Distortion.Gain; - /* Store waveshaper edge settings. */ edge = sinf(props->Distortion.Edge * (F_PI_2)); edge = minf(edge, 0.99f); @@ -104,7 +101,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(&device->Dry, slot->Params.Gain, state->Gain); + ComputeAmbientGains(&device->Dry, slot->Params.Gain * props->Distortion.Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) @@ -165,9 +162,9 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample for(kt = 0;kt < NumChannels;kt++) { /* Fourth step, final, do attenuation and perform decimation, - * store only one sample out of 4. + * storing only one sample out of four. */ - ALfloat gain = state->Gain[kt] * state->attenuation; + ALfloat gain = state->Gain[kt]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; -- cgit v1.2.3 From 9c33f4aea8c573a239050c3e93f784eb6a70e841 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 04:48:18 -0800 Subject: Use MixSamples for the dedicated and ring modulator effect output --- Alc/effects/dedicated.c | 38 +++++++++++-------------------- Alc/effects/modulator.c | 59 ++++++++++++++++++++++--------------------------- 2 files changed, 40 insertions(+), 57 deletions(-) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index af8dc954..7dc2545b 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -32,7 +32,8 @@ typedef struct ALdedicatedState { DERIVE_FROM_TYPE(ALeffectState); - ALfloat gains[MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; } ALdedicatedState; static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state); @@ -46,13 +47,8 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState); static void ALdedicatedState_Construct(ALdedicatedState *state) { - ALsizei s; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALdedicatedState, ALeffectState, state); - - for(s = 0;s < MAX_OUTPUT_CHANNELS;s++) - state->gains[s] = 0.0f; } static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) @@ -60,8 +56,11 @@ static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state) ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } -static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device)) +static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device)) { + ALsizei i; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + state->CurrentGains[i] = 0.0f; return AL_TRUE; } @@ -69,10 +68,10 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext { const ALCdevice *device = context->Device; ALfloat Gain; - ALuint i; + ALsizei i; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - state->gains[i] = 0.0f; + state->TargetGains[i] = 0.0f; Gain = slot->Params.Gain * props->Dedicated.Gain; if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) @@ -82,7 +81,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext { STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->gains[idx] = Gain; + state->TargetGains[idx] = Gain; } } else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE) @@ -94,7 +93,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext { STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels; - state->gains[idx] = Gain; + state->TargetGains[idx] = Gain; } else { @@ -103,26 +102,15 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - ComputeDryPanGains(&device->Dry, coeffs, Gain, state->gains); + ComputeDryPanGains(&device->Dry, coeffs, Gain, state->TargetGains); } } } static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALsizei i, c; - - SamplesIn = ASSUME_ALIGNED(SamplesIn, 16); - SamplesOut = ASSUME_ALIGNED(SamplesOut, 16); - for(c = 0;c < NumChannels;c++) - { - const ALfloat gain = state->gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < SamplesToDo;i++) - SamplesOut[c][i] += SamplesIn[0][i] * gain; - } + MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains, + state->TargetGains, SamplesToDo, 0, SamplesToDo); } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 70751d87..431941ce 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -38,9 +38,12 @@ typedef struct ALmodulatorState { ALsizei index; ALsizei step; - ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; + struct { + ALfilterState Filter; - ALfilterState Filter[MAX_EFFECT_CHANNELS]; + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + } Chans[MAX_EFFECT_CHANNELS]; } ALmodulatorState; static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state); @@ -93,16 +96,11 @@ DECL_TEMPLATE(Square) static void ALmodulatorState_Construct(ALmodulatorState *state) { - ALuint i; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALmodulatorState, ALeffectState, state); state->index = 0; state->step = 1; - - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_clear(&state->Filter[i]); } static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) @@ -110,8 +108,15 @@ static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state) ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } -static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device)) +static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device)) { + ALsizei i, j; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + ALfilterState_clear(&state->Chans[i].Filter); + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + } return AL_TRUE; } @@ -136,20 +141,19 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext cw = cosf(F_TAU * props->Modulator.HighPassCutoff / device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - { - state->Filter[i].b0 = a; - state->Filter[i].b1 = -a; - state->Filter[i].b2 = 0.0f; - state->Filter[i].a1 = -a; - state->Filter[i].a2 = 0.0f; - } + state->Chans[0].Filter.b0 = a; + state->Chans[0].Filter.b1 = -a; + state->Chans[0].Filter.b2 = 0.0f; + state->Chans[0].Filter.a1 = -a; + state->Chans[0].Filter.a2 = 0.0f; + for(i = 1;i < MAX_EFFECT_CHANNELS;i++) + ALfilterState_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Gain[i]); + slot->Params.Gain, state->Chans[i].TargetGains); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) @@ -162,29 +166,20 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT { ALfloat temps[2][128]; ALsizei td = mini(128, SamplesToDo-base); - ALsizei i, j, k; + ALsizei i; - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td); + ALfilterState_process(&state->Chans[i].Filter, temps[0], &SamplesIn[i][base], td); state->Process(temps[1], temps[0], index, step, td); - for(k = 0;k < NumChannels;k++) - { - ALfloat gain = state->Gain[j][k]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < td;i++) - SamplesOut[k][base+i] += gain * temps[1][i]; - } + MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[i].CurrentGains, + state->Chans[i].TargetGains, SamplesToDo-base, base, td); } for(i = 0;i < td;i++) - { index += step; - index &= WAVEFORM_FRACMASK; - } + index &= WAVEFORM_FRACMASK; base += td; } state->index = index; -- cgit v1.2.3 From ff231b42ff82349d935861e7afcfd4e7a7917471 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 05:03:00 -0800 Subject: Reorder some loops in the equalizer and use MixSamples --- Alc/effects/equalizer.c | 104 ++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 61 deletions(-) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 8be689d2..7df15380 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -72,19 +72,19 @@ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ -/* The maximum number of sample frames per update. */ -#define MAX_UPDATE_SAMPLES 256 - typedef struct ALequalizerState { DERIVE_FROM_TYPE(ALeffectState); - /* Effect gains for each channel */ - ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS]; + struct { + /* Effect gains for each channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - /* Effect parameters */ - ALfilterState filter[4][MAX_EFFECT_CHANNELS]; + /* Effect parameters */ + ALfilterState filter[4]; + } Chans[MAX_EFFECT_CHANNELS]; - ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES]; + ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALequalizerState; static ALvoid ALequalizerState_Destruct(ALequalizerState *state); @@ -98,18 +98,8 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState); static void ALequalizerState_Construct(ALequalizerState *state) { - int it, ft; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); 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++) - { - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_clear(&state->filter[it][ft]); - } } static ALvoid ALequalizerState_Destruct(ALequalizerState *state) @@ -117,8 +107,17 @@ static ALvoid ALequalizerState_Destruct(ALequalizerState *state) ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } -static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device)) +static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device)) { + ALsizei i, j; + + for(i = 0; i < MAX_EFFECT_CHANNELS;i++) + { + for(j = 0;j < 4;j++) + ALfilterState_clear(&state->Chans[i].filter[j]); + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + } return AL_TRUE; } @@ -133,7 +132,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Gain[i]); + slot->Params.Gain, state->Chans[i].TargetGains); /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint @@ -141,75 +140,58 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ freq_mult = props->Equalizer.LowCutoff/frequency; - ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf, + ALfilterState_setParams(&state->Chans[0].filter[0], ALfilterType_LowShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); - /* Copy the filter coefficients for the other input channels. */ - for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_copyParams(&state->filter[0][i], &state->filter[0][0]); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); freq_mult = props->Equalizer.Mid1Center/frequency; - ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking, + ALfilterState_setParams(&state->Chans[0].filter[1], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( freq_mult, props->Equalizer.Mid1Width ) ); - for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_copyParams(&state->filter[1][i], &state->filter[1][0]); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); freq_mult = props->Equalizer.Mid2Center/frequency; - ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking, + ALfilterState_setParams(&state->Chans[0].filter[2], ALfilterType_Peaking, gain, freq_mult, calc_rcpQ_from_bandwidth( freq_mult, props->Equalizer.Mid2Width ) ); - for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_copyParams(&state->filter[2][i], &state->filter[2][0]); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); freq_mult = props->Equalizer.HighCutoff/frequency; - ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf, + ALfilterState_setParams(&state->Chans[0].filter[3], ALfilterType_HighShelf, gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) ); + + /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_copyParams(&state->filter[3][i], &state->filter[3][0]); + { + ALfilterState_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); + ALfilterState_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); + ALfilterState_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); + ALfilterState_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); + } } static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer; - ALsizei it, kt, ft; - ALsizei base; + ALfloat (*restrict temps)[BUFFERSIZE] = state->SampleBuffer; + ALsizei c; - for(base = 0;base < SamplesToDo;) + for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); - - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td); - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_process(&state->filter[1][ft], Samples[1][ft], Samples[0][ft], td); - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_process(&state->filter[2][ft], Samples[2][ft], Samples[1][ft], td); - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - ALfilterState_process(&state->filter[3][ft], Samples[3][ft], Samples[2][ft], td); - - for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++) - { - for(kt = 0;kt < NumChannels;kt++) - { - ALfloat gain = state->Gain[ft][kt]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * Samples[3][ft][it]; - } - } - - base += td; + ALfilterState_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + ALfilterState_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); + ALfilterState_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); + ALfilterState_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); + + MixSamples(temps[3], NumChannels, SamplesOut, + state->Chans[c].CurrentGains, state->Chans[c].TargetGains, + SamplesToDo, 0, SamplesToDo + ); } } -- cgit v1.2.3 From f3c9bc114cb1d136fce4e790d6d2721430eb30dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 06:32:45 -0800 Subject: Move the polymorphic/inheritance macros to a separate header --- Alc/polymorphism.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/alMain.h | 95 +--------------------------------------- 2 files changed, 109 insertions(+), 94 deletions(-) create mode 100644 Alc/polymorphism.h diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h new file mode 100644 index 00000000..b41ad64b --- /dev/null +++ b/Alc/polymorphism.h @@ -0,0 +1,108 @@ +#ifndef POLYMORPHISM_H +#define POLYMORPHISM_H + +/* Macros to declare inheriting types, and to (down-)cast and up-cast. */ +#define DERIVE_FROM_TYPE(t) t t##_parent +#define STATIC_CAST(to, obj) (&(obj)->to##_parent) +#ifdef __GNUC__ +#define STATIC_UPCAST(to, from, obj) __extension__({ \ + static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ + "Invalid upcast object from type"); \ + (to*)((char*)(obj) - offsetof(to, from##_parent)); \ +}) +#else +#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent))) +#endif + +/* Defines method forwards, which call the given parent's (T2's) implementation. */ +#define DECLARE_FORWARD(T1, T2, rettype, func) \ +rettype T1##_##func(T1 *obj) \ +{ return T2##_##func(STATIC_CAST(T2, obj)); } + +#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \ +rettype T1##_##func(T1 *obj, argtype1 a) \ +{ return T2##_##func(STATIC_CAST(T2, obj), a); } + +#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); } + +#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); } + +/* Defines method thunks, functions that call to the child's method. */ +#define DECLARE_THUNK(T1, T2, rettype, func) \ +static rettype T1##_##T2##_##func(T2 *obj) \ +{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); } + +#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); } + +#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); } + +#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); } + +#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \ +static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \ +{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); } + +/* Defines the default functions used to (de)allocate a polymorphic object. */ +#define DECLARE_DEFAULT_ALLOCATORS(T) \ +static void* T##_New(size_t size) { return al_malloc(16, size); } \ +static void T##_Delete(void *ptr) { al_free(ptr); } + + +/* Helper to extract an argument list for virtual method calls. */ +#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) + +/* 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 + + +/* Helper to extract an argument list for NEW_OBJ calls. */ +#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \ + } \ +} while(0) + +/* Allocate and construct an object, with arguments. */ +#define NEW_OBJ(_res, T) do { \ + _res = T##_New(sizeof(T)); \ + if(_res) \ + { \ + memset(_res, 0, sizeof(T)); \ + T##_Construct(_res, EXTRACT_NEW_ARGS +/* Allocate and construct an object, with no arguments. */ +#define NEW_OBJ0(_res, T) do { \ + _res = T##_New(sizeof(T)); \ + if(_res) \ + { \ + memset(_res, 0, sizeof(T)); \ + T##_Construct(_res EXTRACT_NEW_ARGS + +/* Destructs and deallocate an object. */ +#define DELETE_OBJ(obj) do { \ + if((obj) != NULL) \ + { \ + V0((obj),Destruct)(); \ + V0((obj),Delete)(); \ + } \ +} while(0) + + +/* Helper to get a type's vtable thunk for a child type. */ +#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable)) +/* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */ +#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2)) + +/* Helper to set an object's vtable for a type. */ +#define SET_VTABLE1(T1, obj) ((obj)->vtbl = &(T1##_vtable)) + +#endif /* POLYMORPHISM_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 617b5a64..7af7b4bb 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -21,6 +21,7 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "polymorphism.h" #include "static_assert.h" #include "align.h" #include "atomic.h" @@ -286,100 +287,6 @@ static const union { #define COUNTOF(x) (sizeof(x) / sizeof(0[x])) -#define DERIVE_FROM_TYPE(t) t t##_parent -#define STATIC_CAST(to, obj) (&(obj)->to##_parent) -#ifdef __GNUC__ -#define STATIC_UPCAST(to, from, obj) __extension__({ \ - static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ - "Invalid upcast object from type"); \ - (to*)((char*)(obj) - offsetof(to, from##_parent)); \ -}) -#else -#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent))) -#endif - -#define DECLARE_FORWARD(T1, T2, rettype, func) \ -rettype T1##_##func(T1 *obj) \ -{ return T2##_##func(STATIC_CAST(T2, obj)); } - -#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \ -rettype T1##_##func(T1 *obj, argtype1 a) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a); } - -#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); } - -#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); } - - -#define GET_VTABLE1(T1) (&(T1##_vtable)) -#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable)) - -#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)) - -#define DECLARE_THUNK(T1, T2, rettype, func) \ -static rettype T1##_##T2##_##func(T2 *obj) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); } - -#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); } - -#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); } - -#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); } - -#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); } - -#define DECLARE_DEFAULT_ALLOCATORS(T) \ -static void* T##_New(size_t size) { return al_malloc(16, size); } \ -static void T##_Delete(void *ptr) { al_free(ptr); } - -/* Helper to extract an argument list for VCALL. Not used directly. */ -#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) - -/* 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 - -#define DELETE_OBJ(obj) do { \ - if((obj) != NULL) \ - { \ - V0((obj),Destruct)(); \ - V0((obj),Delete)(); \ - } \ -} while(0) - - -#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \ - } \ -} while(0) - -#define NEW_OBJ(_res, T) do { \ - _res = T##_New(sizeof(T)); \ - if(_res) \ - { \ - memset(_res, 0, sizeof(T)); \ - T##_Construct(_res, EXTRACT_NEW_ARGS -#define NEW_OBJ0(_res, T) do { \ - _res = T##_New(sizeof(T)); \ - if(_res) \ - { \ - memset(_res, 0, sizeof(T)); \ - T##_Construct(_res EXTRACT_NEW_ARGS - - #ifdef __cplusplus extern "C" { #endif -- cgit v1.2.3 From 9b9ec2c21a7f0992a6ca64ac9cb2a03838e11cd7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 06:50:53 -0800 Subject: Move the compressor/limiter declarations to their own header --- Alc/ALc.c | 1 + Alc/ALu.c | 1 + Alc/mastering.c | 31 ++++---------------------- Alc/mastering.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/alMain.h | 28 ----------------------- 5 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 Alc/mastering.h diff --git a/Alc/ALc.c b/Alc/ALc.c index cca88a8f..3de59521 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -37,6 +37,7 @@ #include "alBuffer.h" #include "alAuxEffectSlot.h" #include "alError.h" +#include "mastering.h" #include "bformatdec.h" #include "alu.h" diff --git a/Alc/ALu.c b/Alc/ALu.c index a4e9c1a4..bd1bf79a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -34,6 +34,7 @@ #include "alu.h" #include "bs2b.h" #include "hrtf.h" +#include "mastering.h" #include "uhjfilter.h" #include "bformatdec.h" #include "static_assert.h" diff --git a/Alc/mastering.c b/Alc/mastering.c index 9de5fd5f..91267d83 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -2,37 +2,19 @@ #include +#include "mastering.h" #include "alu.h" #include "almalloc.h" + +extern inline ALuint GetCompressorSampleRate(const Compressor *Comp); + #define RMS_WINDOW_SIZE (1<<7) #define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1) #define RMS_VALUE_MAX (1<<24) -#define LOOKAHEAD_SIZE (1<<13) -#define LOOKAHEAD_MASK (LOOKAHEAD_SIZE-1) - static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big"); -typedef struct Compressor { - ALfloat PreGain; - ALfloat PostGain; - ALboolean SummedLink; - ALfloat AttackMin; - ALfloat AttackMax; - ALfloat ReleaseMin; - ALfloat ReleaseMax; - ALfloat Ratio; - ALfloat Threshold; - ALfloat Knee; - ALuint SampleRate; - - ALuint RmsSum; - ALuint *RmsWindow; - ALsizei RmsIndex; - ALfloat Envelope[BUFFERSIZE]; - ALfloat EnvLast; -} Compressor; /* Multichannel compression is linked via one of two modes: * @@ -209,11 +191,6 @@ Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, return Comp; } -ALuint GetCompressorSampleRate(const Compressor *Comp) -{ - return Comp->SampleRate; -} - void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) { diff --git a/Alc/mastering.h b/Alc/mastering.h new file mode 100644 index 00000000..0a7b4901 --- /dev/null +++ b/Alc/mastering.h @@ -0,0 +1,57 @@ +#ifndef MASTERING_H +#define MASTERING_H + +#include "AL/al.h" + +/* For BUFFERSIZE. */ +#include "alMain.h" + +typedef struct Compressor { + ALfloat PreGain; + ALfloat PostGain; + ALboolean SummedLink; + ALfloat AttackMin; + ALfloat AttackMax; + ALfloat ReleaseMin; + ALfloat ReleaseMax; + ALfloat Ratio; + ALfloat Threshold; + ALfloat Knee; + ALuint SampleRate; + + ALuint RmsSum; + ALuint *RmsWindow; + ALsizei RmsIndex; + ALfloat Envelope[BUFFERSIZE]; + ALfloat EnvLast; +} Compressor; + +/* The compressor requires the following information for proper + * initialization: + * + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Gain applied after compression (in dB). + * SummedLink - Whether to use summed (true) or maxed (false) linking. + * RmsSensing - Whether to use RMS (true) or Peak (false) sensing. + * AttackTimeMin - Minimum attack time (in seconds). + * AttackTimeMax - Maximum attack time. Automates when min != max. + * ReleaseTimeMin - Minimum release time (in seconds). + * ReleaseTimeMax - Maximum release time. Automates when min != max. + * Ratio - Compression ratio (x:1). Set to 0 for true limiter. + * ThresholdDb - Triggering threshold (in dB). + * KneeDb - Knee width (below threshold; in dB). + * SampleRate - Sample rate to process. + */ +Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, + const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin, + const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, + const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb, + const ALuint SampleRate); + +void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, + ALfloat (*restrict OutBuffer)[BUFFERSIZE]); + +inline ALuint GetCompressorSampleRate(const Compressor *Comp) +{ return Comp->SampleRate; } + +#endif /* MASTERING_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7af7b4bb..bbf64349 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -959,34 +959,6 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir); typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; typedef ALfloat ALfloat2[2]; - -/* The compressor requires the following information for proper - * initialization: - * - * PreGainDb - Gain applied before detection (in dB). - * PostGainDb - Gain applied after compression (in dB). - * SummedLink - Whether to use summed (true) or maxed (false) linking. - * RmsSensing - Whether to use RMS (true) or Peak (false) sensing. - * AttackTimeMin - Minimum attack time (in seconds). - * AttackTimeMax - Maximum attack time. Automates when min != max. - * ReleaseTimeMin - Minimum release time (in seconds). - * ReleaseTimeMax - Maximum release time. Automates when min != max. - * Ratio - Compression ratio (x:1). Set to 0 for true limiter. - * ThresholdDb - Triggering threshold (in dB). - * KneeDb - Knee width (below threshold; in dB). - * SampleRate - Sample rate to process. - */ -struct Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, - const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin, - const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, - const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb, - const ALuint SampleRate); - -ALuint GetCompressorSampleRate(const struct Compressor *Comp); - -void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, - ALfloat (*restrict OutBuffer)[BUFFERSIZE]); - #ifdef __cplusplus } #endif -- cgit v1.2.3 From 81b13f78ea27aaa6704457124931148244fd1614 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 07:19:19 -0800 Subject: Move the CPU capability flags to a separate header --- Alc/ALc.c | 3 ++- Alc/ALu.c | 1 + Alc/cpu_caps.h | 15 +++++++++++++++ Alc/helpers.c | 8 ++++---- Alc/mixer.c | 1 + OpenAL32/Include/alMain.h | 11 ----------- 6 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 Alc/cpu_caps.h diff --git a/Alc/ALc.c b/Alc/ALc.c index 3de59521..34cb63d4 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -41,6 +41,7 @@ #include "bformatdec.h" #include "alu.h" +#include "cpu_caps.h" #include "compat.h" #include "threads.h" #include "alstring.h" @@ -900,7 +901,7 @@ static void alc_init(void) static void alc_initconfig(void) { const char *devs, *str; - ALuint capfilter; + int capfilter; float valf; int i, n; diff --git a/Alc/ALu.c b/Alc/ALu.c index bd1bf79a..e0496513 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -39,6 +39,7 @@ #include "bformatdec.h" #include "static_assert.h" +#include "cpu_caps.h" #include "mixer_defs.h" #include "bsinc_inc.h" diff --git a/Alc/cpu_caps.h b/Alc/cpu_caps.h new file mode 100644 index 00000000..328d470e --- /dev/null +++ b/Alc/cpu_caps.h @@ -0,0 +1,15 @@ +#ifndef CPU_CAPS_H +#define CPU_CAPS_H + +extern int CPUCapFlags; +enum { + CPU_CAP_SSE = 1<<0, + CPU_CAP_SSE2 = 1<<1, + CPU_CAP_SSE3 = 1<<2, + CPU_CAP_SSE4_1 = 1<<3, + CPU_CAP_NEON = 1<<4, +}; + +void FillCPUCaps(int capfilter); + +#endif /* CPU_CAPS_H */ diff --git a/Alc/helpers.c b/Alc/helpers.c index 7f6349b3..0f69b29e 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -108,6 +108,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "alMain.h" #include "alu.h" +#include "cpu_caps.h" #include "atomic.h" #include "uintmap.h" #include "vector.h" @@ -124,12 +125,11 @@ extern inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_ extern inline ALint fastf2i(ALfloat f); -ALuint CPUCapFlags = 0; +int CPUCapFlags = 0; - -void FillCPUCaps(ALuint capfilter) +void FillCPUCaps(int capfilter) { - ALuint caps = 0; + int caps = 0; /* FIXME: We really should get this for all available CPUs in case different * CPUs have different caps (is that possible on one machine?). */ diff --git a/Alc/mixer.c b/Alc/mixer.c index d99a4a8f..3d1da58f 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -35,6 +35,7 @@ #include "alAuxEffectSlot.h" #include "alu.h" +#include "cpu_caps.h" #include "mixer_defs.h" diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bbf64349..6556da37 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -940,17 +940,6 @@ extern enum LogLevel LogLevel; extern ALint RTPrioLevel; -extern ALuint CPUCapFlags; -enum { - CPU_CAP_SSE = 1<<0, - CPU_CAP_SSE2 = 1<<1, - CPU_CAP_SSE3 = 1<<2, - CPU_CAP_SSE4_1 = 1<<3, - CPU_CAP_NEON = 1<<4, -}; - -void FillCPUCaps(ALuint capfilter); - vector_al_string SearchDataFiles(const char *match, const char *subdir); /* Small hack to use a pointer-to-array types as a normal argument type. -- cgit v1.2.3 From 8aa9e35f8c743c1336142a0a49eaeee19a6d33d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 07:56:54 -0800 Subject: Move the config function declarations to their own header And rename alcConfig.c to alconfig.c for consistency. --- Alc/ALc.c | 1 + Alc/alcConfig.c | 652 --------------------------------------------- Alc/alconfig.c | 653 ++++++++++++++++++++++++++++++++++++++++++++++ Alc/alconfig.h | 17 ++ Alc/backends/alsa.c | 1 + Alc/backends/jack.c | 1 + Alc/backends/oss.c | 1 + Alc/backends/portaudio.c | 1 + Alc/backends/pulseaudio.c | 1 + Alc/backends/solaris.c | 1 + Alc/backends/wave.c | 1 + Alc/hrtf.c | 1 + Alc/mixer.c | 1 + Alc/panning.c | 1 + CMakeLists.txt | 2 +- OpenAL32/Include/alMain.h | 10 - 16 files changed, 682 insertions(+), 663 deletions(-) delete mode 100644 Alc/alcConfig.c create mode 100644 Alc/alconfig.c create mode 100644 Alc/alconfig.h diff --git a/Alc/ALc.c b/Alc/ALc.c index 34cb63d4..5297af30 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -40,6 +40,7 @@ #include "mastering.h" #include "bformatdec.h" #include "alu.h" +#include "alconfig.h" #include "cpu_caps.h" #include "compat.h" diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c deleted file mode 100644 index 6fd01746..00000000 --- a/Alc/alcConfig.c +++ /dev/null @@ -1,652 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#ifdef _WIN32 -#ifdef __MINGW32__ -#define _WIN32_IE 0x501 -#else -#define _WIN32_IE 0x400 -#endif -#endif - -#include "config.h" - -#include -#include -#include -#include -#ifdef _WIN32_IE -#include -#include -#endif - -#include "alMain.h" -#include "compat.h" -#include "bool.h" - - -typedef struct ConfigEntry { - char *key; - char *value; -} ConfigEntry; - -typedef struct ConfigBlock { - ConfigEntry *entries; - unsigned int entryCount; -} ConfigBlock; -static ConfigBlock cfgBlock; - - -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 int readline(FILE *f, char **output, size_t *maxlen) -{ - size_t len = 0; - int c; - - while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) - ; - if(c == EOF) - return 0; - - do { - if(len+1 >= *maxlen) - { - void *temp = NULL; - size_t newmax; - - newmax = (*maxlen ? (*maxlen)<<1 : 32); - if(newmax > *maxlen) - temp = realloc(*output, newmax); - if(!temp) - { - ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen); - return 0; - } - - *output = temp; - *maxlen = newmax; - } - (*output)[len++] = c; - (*output)[len] = '\0'; - } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); - - return 1; -} - - -static char *expdup(const char *str) -{ - char *output = NULL; - size_t maxlen = 0; - size_t len = 0; - - while(*str != '\0') - { - const char *addstr; - size_t addstrlen; - size_t i; - - if(str[0] != '$') - { - const char *next = strchr(str, '$'); - addstr = str; - addstrlen = next ? (size_t)(next-str) : strlen(str); - - str += addstrlen; - } - else - { - str++; - if(*str == '$') - { - const char *next = strchr(str+1, '$'); - addstr = str; - addstrlen = next ? (size_t)(next-str) : strlen(str); - - str += addstrlen; - } - else - { - bool hasbraces; - char envname[1024]; - size_t k = 0; - - hasbraces = (*str == '{'); - if(hasbraces) str++; - - while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) - envname[k++] = *(str++); - envname[k++] = '\0'; - - if(hasbraces && *str != '}') - continue; - - if(hasbraces) str++; - if((addstr=getenv(envname)) == NULL) - continue; - addstrlen = strlen(addstr); - } - } - if(addstrlen == 0) - continue; - - if(addstrlen >= maxlen-len) - { - void *temp = NULL; - size_t newmax; - - newmax = len+addstrlen+1; - if(newmax > maxlen) - temp = realloc(output, newmax); - if(!temp) - { - ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, maxlen); - return output; - } - - output = temp; - maxlen = newmax; - } - - for(i = 0;i < addstrlen;i++) - output[len++] = addstr[i]; - output[len] = '\0'; - } - - return output ? output : calloc(1, 1); -} - - -static void LoadConfigFromFile(FILE *f) -{ - char curSection[128] = ""; - char *buffer = NULL; - size_t maxlen = 0; - ConfigEntry *ent; - - while(readline(f, &buffer, &maxlen)) - { - char *line, *comment; - char key[256] = ""; - char value[256] = ""; - - line = rstrip(lstrip(buffer)); - if(!line[0]) continue; - - if(line[0] == '[') - { - char *section = line+1; - char *endsection; - - endsection = strchr(section, ']'); - if(!endsection || section == endsection) - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - if(endsection[1] != 0) - { - char *end = endsection+1; - while(isspace(*end)) - ++end; - if(*end != 0 && *end != '#') - { - ERR("config parse error: bad line \"%s\"\n", line); - continue; - } - } - *endsection = 0; - - if(strcasecmp(section, "general") == 0) - curSection[0] = 0; - else - { - size_t len, p = 0; - do { - char *nextp = strchr(section, '%'); - if(!nextp) - { - strncpy(curSection+p, section, sizeof(curSection)-1-p); - break; - } - - len = nextp - section; - if(len > sizeof(curSection)-1-p) - len = sizeof(curSection)-1-p; - strncpy(curSection+p, section, len); - p += len; - section = nextp; - - if(((section[1] >= '0' && section[1] <= '9') || - (section[1] >= 'a' && section[1] <= 'f') || - (section[1] >= 'A' && section[1] <= 'F')) && - ((section[2] >= '0' && section[2] <= '9') || - (section[2] >= 'a' && section[2] <= 'f') || - (section[2] >= 'A' && section[2] <= 'F'))) - { - unsigned char b = 0; - if(section[1] >= '0' && section[1] <= '9') - b = (section[1]-'0') << 4; - else if(section[1] >= 'a' && section[1] <= 'f') - b = (section[1]-'a'+0xa) << 4; - else if(section[1] >= 'A' && section[1] <= 'F') - b = (section[1]-'A'+0x0a) << 4; - if(section[2] >= '0' && section[2] <= '9') - b |= (section[2]-'0'); - else if(section[2] >= 'a' && section[2] <= 'f') - b |= (section[2]-'a'+0xa); - else if(section[2] >= 'A' && section[2] <= 'F') - b |= (section[2]-'A'+0x0a); - if(p < sizeof(curSection)-1) - curSection[p++] = b; - section += 3; - } - else if(section[1] == '%') - { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; - section += 2; - } - else - { - if(p < sizeof(curSection)-1) - curSection[p++] = '%'; - section += 1; - } - if(p < sizeof(curSection)-1) - curSection[p] = 0; - } while(p < sizeof(curSection)-1 && *section != 0); - curSection[sizeof(curSection)-1] = 0; - } - - continue; - } - - comment = strchr(line, '#'); - if(comment) *(comment++) = 0; - if(!line[0]) continue; - - if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || - sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || - sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) - { - /* 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 = cfgBlock.entries; - while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount) - { - if(strcasecmp(ent->key, key) == 0) - break; - ent++; - } - - if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount) - { - /* Allocate a new option entry */ - ent = realloc(cfgBlock.entries, (cfgBlock.entryCount+1)*sizeof(ConfigEntry)); - if(!ent) - { - ERR("config parse error: error reallocating config entries\n"); - continue; - } - cfgBlock.entries = ent; - ent = cfgBlock.entries + cfgBlock.entryCount; - cfgBlock.entryCount++; - - ent->key = strdup(key); - ent->value = NULL; - } - - free(ent->value); - ent->value = expdup(value); - - TRACE("found '%s' = '%s'\n", ent->key, ent->value); - } - - free(buffer); -} - -#ifdef _WIN32 -void ReadALConfig(void) -{ - WCHAR buffer[PATH_MAX]; - const WCHAR *str; - al_string ppath; - FILE *f; - - if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) - { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, buffer); - alstr_append_cstr(&filepath, "\\alsoft.ini"); - - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); - } - - ppath = GetProcPath(); - if(!alstr_empty(ppath)) - { - alstr_append_cstr(&ppath, "\\alsoft.ini"); - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - f = al_fopen(alstr_get_cstr(ppath), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) - { - al_string filepath = AL_STRING_INIT_STATIC(); - alstr_copy_wcstr(&filepath, str); - - TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); - f = al_fopen(alstr_get_cstr(filepath), "rt"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - alstr_reset(&filepath); - } - - alstr_reset(&ppath); -} -#else -void ReadALConfig(void) -{ - char buffer[PATH_MAX]; - const char *str; - al_string ppath; - FILE *f; - - str = "/etc/openal/alsoft.conf"; - - TRACE("Loading config %s...\n", str); - f = al_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 = al_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 = al_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 = al_fopen(buffer, "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - ppath = GetProcPath(); - if(!alstr_empty(ppath)) - { - alstr_append_cstr(&ppath, "/alsoft.conf"); - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - f = al_fopen(alstr_get_cstr(ppath), "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - if((str=getenv("ALSOFT_CONF")) != NULL && *str) - { - TRACE("Loading config %s...\n", str); - f = al_fopen(str, "r"); - if(f) - { - LoadConfigFromFile(f); - fclose(f); - } - } - - alstr_reset(&ppath); -} -#endif - -void FreeALConfig(void) -{ - unsigned int i; - - for(i = 0;i < cfgBlock.entryCount;i++) - { - free(cfgBlock.entries[i].key); - free(cfgBlock.entries[i].value); - } - free(cfgBlock.entries); -} - -const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) -{ - unsigned int i; - char key[256]; - - if(!keyName) - return def; - - if(blockName && strcasecmp(blockName, "general") != 0) - { - if(devName) - snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); - else - snprintf(key, sizeof(key), "%s/%s", blockName, keyName); - } - else - { - if(devName) - snprintf(key, sizeof(key), "%s/%s", devName, keyName); - else - { - strncpy(key, keyName, sizeof(key)-1); - key[sizeof(key)-1] = 0; - } - } - - for(i = 0;i < cfgBlock.entryCount;i++) - { - if(strcmp(cfgBlock.entries[i].key, key) == 0) - { - TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); - if(cfgBlock.entries[i].value[0]) - return cfgBlock.entries[i].value; - return def; - } - } - - if(!devName) - { - TRACE("Key %s not found\n", key); - return def; - } - return GetConfigValue(NULL, blockName, keyName, def); -} - -int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - return !!val[0]; -} - -int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = val; - return 1; -} - -int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = strtol(val, NULL, 0); - return 1; -} - -int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = strtoul(val, NULL, 0); - return 1; -} - -int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - -#ifdef HAVE_STRTOF - *ret = strtof(val, NULL); -#else - *ret = (float)strtod(val, NULL); -#endif - return 1; -} - -int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - if(!val[0]) return 0; - - *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); - return 1; -} - -int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) -{ - const char *val = GetConfigValue(devName, blockName, keyName, ""); - - if(!val[0]) return !!def; - return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || - strcasecmp(val, "on") == 0 || atoi(val) != 0); -} diff --git a/Alc/alconfig.c b/Alc/alconfig.c new file mode 100644 index 00000000..1115bf30 --- /dev/null +++ b/Alc/alconfig.c @@ -0,0 +1,653 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifdef _WIN32 +#ifdef __MINGW32__ +#define _WIN32_IE 0x501 +#else +#define _WIN32_IE 0x400 +#endif +#endif + +#include "config.h" + +#include +#include +#include +#include +#ifdef _WIN32_IE +#include +#include +#endif + +#include "alMain.h" +#include "alconfig.h" +#include "compat.h" +#include "bool.h" + + +typedef struct ConfigEntry { + char *key; + char *value; +} ConfigEntry; + +typedef struct ConfigBlock { + ConfigEntry *entries; + unsigned int entryCount; +} ConfigBlock; +static ConfigBlock cfgBlock; + + +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 int readline(FILE *f, char **output, size_t *maxlen) +{ + size_t len = 0; + int c; + + while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n')) + ; + if(c == EOF) + return 0; + + do { + if(len+1 >= *maxlen) + { + void *temp = NULL; + size_t newmax; + + newmax = (*maxlen ? (*maxlen)<<1 : 32); + if(newmax > *maxlen) + temp = realloc(*output, newmax); + if(!temp) + { + ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen); + return 0; + } + + *output = temp; + *maxlen = newmax; + } + (*output)[len++] = c; + (*output)[len] = '\0'; + } while((c=fgetc(f)) != EOF && c != '\r' && c != '\n'); + + return 1; +} + + +static char *expdup(const char *str) +{ + char *output = NULL; + size_t maxlen = 0; + size_t len = 0; + + while(*str != '\0') + { + const char *addstr; + size_t addstrlen; + size_t i; + + if(str[0] != '$') + { + const char *next = strchr(str, '$'); + addstr = str; + addstrlen = next ? (size_t)(next-str) : strlen(str); + + str += addstrlen; + } + else + { + str++; + if(*str == '$') + { + const char *next = strchr(str+1, '$'); + addstr = str; + addstrlen = next ? (size_t)(next-str) : strlen(str); + + str += addstrlen; + } + else + { + bool hasbraces; + char envname[1024]; + size_t k = 0; + + hasbraces = (*str == '{'); + if(hasbraces) str++; + + while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) + envname[k++] = *(str++); + envname[k++] = '\0'; + + if(hasbraces && *str != '}') + continue; + + if(hasbraces) str++; + if((addstr=getenv(envname)) == NULL) + continue; + addstrlen = strlen(addstr); + } + } + if(addstrlen == 0) + continue; + + if(addstrlen >= maxlen-len) + { + void *temp = NULL; + size_t newmax; + + newmax = len+addstrlen+1; + if(newmax > maxlen) + temp = realloc(output, newmax); + if(!temp) + { + ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, maxlen); + return output; + } + + output = temp; + maxlen = newmax; + } + + for(i = 0;i < addstrlen;i++) + output[len++] = addstr[i]; + output[len] = '\0'; + } + + return output ? output : calloc(1, 1); +} + + +static void LoadConfigFromFile(FILE *f) +{ + char curSection[128] = ""; + char *buffer = NULL; + size_t maxlen = 0; + ConfigEntry *ent; + + while(readline(f, &buffer, &maxlen)) + { + char *line, *comment; + char key[256] = ""; + char value[256] = ""; + + line = rstrip(lstrip(buffer)); + if(!line[0]) continue; + + if(line[0] == '[') + { + char *section = line+1; + char *endsection; + + endsection = strchr(section, ']'); + if(!endsection || section == endsection) + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + if(endsection[1] != 0) + { + char *end = endsection+1; + while(isspace(*end)) + ++end; + if(*end != 0 && *end != '#') + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + } + *endsection = 0; + + if(strcasecmp(section, "general") == 0) + curSection[0] = 0; + else + { + size_t len, p = 0; + do { + char *nextp = strchr(section, '%'); + if(!nextp) + { + strncpy(curSection+p, section, sizeof(curSection)-1-p); + break; + } + + len = nextp - section; + if(len > sizeof(curSection)-1-p) + len = sizeof(curSection)-1-p; + strncpy(curSection+p, section, len); + p += len; + section = nextp; + + if(((section[1] >= '0' && section[1] <= '9') || + (section[1] >= 'a' && section[1] <= 'f') || + (section[1] >= 'A' && section[1] <= 'F')) && + ((section[2] >= '0' && section[2] <= '9') || + (section[2] >= 'a' && section[2] <= 'f') || + (section[2] >= 'A' && section[2] <= 'F'))) + { + unsigned char b = 0; + if(section[1] >= '0' && section[1] <= '9') + b = (section[1]-'0') << 4; + else if(section[1] >= 'a' && section[1] <= 'f') + b = (section[1]-'a'+0xa) << 4; + else if(section[1] >= 'A' && section[1] <= 'F') + b = (section[1]-'A'+0x0a) << 4; + if(section[2] >= '0' && section[2] <= '9') + b |= (section[2]-'0'); + else if(section[2] >= 'a' && section[2] <= 'f') + b |= (section[2]-'a'+0xa); + else if(section[2] >= 'A' && section[2] <= 'F') + b |= (section[2]-'A'+0x0a); + if(p < sizeof(curSection)-1) + curSection[p++] = b; + section += 3; + } + else if(section[1] == '%') + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 2; + } + else + { + if(p < sizeof(curSection)-1) + curSection[p++] = '%'; + section += 1; + } + if(p < sizeof(curSection)-1) + curSection[p] = 0; + } while(p < sizeof(curSection)-1 && *section != 0); + curSection[sizeof(curSection)-1] = 0; + } + + continue; + } + + comment = strchr(line, '#'); + if(comment) *(comment++) = 0; + if(!line[0]) continue; + + if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || + sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || + sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) + { + /* 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 = cfgBlock.entries; + while((unsigned int)(ent-cfgBlock.entries) < cfgBlock.entryCount) + { + if(strcasecmp(ent->key, key) == 0) + break; + ent++; + } + + if((unsigned int)(ent-cfgBlock.entries) >= cfgBlock.entryCount) + { + /* Allocate a new option entry */ + ent = realloc(cfgBlock.entries, (cfgBlock.entryCount+1)*sizeof(ConfigEntry)); + if(!ent) + { + ERR("config parse error: error reallocating config entries\n"); + continue; + } + cfgBlock.entries = ent; + ent = cfgBlock.entries + cfgBlock.entryCount; + cfgBlock.entryCount++; + + ent->key = strdup(key); + ent->value = NULL; + } + + free(ent->value); + ent->value = expdup(value); + + TRACE("found '%s' = '%s'\n", ent->key, ent->value); + } + + free(buffer); +} + +#ifdef _WIN32 +void ReadALConfig(void) +{ + WCHAR buffer[PATH_MAX]; + const WCHAR *str; + al_string ppath; + FILE *f; + + if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) + { + al_string filepath = AL_STRING_INIT_STATIC(); + alstr_copy_wcstr(&filepath, buffer); + alstr_append_cstr(&filepath, "\\alsoft.ini"); + + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + alstr_reset(&filepath); + } + + ppath = GetProcPath(); + if(!alstr_empty(ppath)) + { + alstr_append_cstr(&ppath, "\\alsoft.ini"); + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + f = al_fopen(alstr_get_cstr(ppath), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) + { + al_string filepath = AL_STRING_INIT_STATIC(); + alstr_copy_wcstr(&filepath, str); + + TRACE("Loading config %s...\n", alstr_get_cstr(filepath)); + f = al_fopen(alstr_get_cstr(filepath), "rt"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + alstr_reset(&filepath); + } + + alstr_reset(&ppath); +} +#else +void ReadALConfig(void) +{ + char buffer[PATH_MAX]; + const char *str; + al_string ppath; + FILE *f; + + str = "/etc/openal/alsoft.conf"; + + TRACE("Loading config %s...\n", str); + f = al_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 = al_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 = al_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 = al_fopen(buffer, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + ppath = GetProcPath(); + if(!alstr_empty(ppath)) + { + alstr_append_cstr(&ppath, "/alsoft.conf"); + TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); + f = al_fopen(alstr_get_cstr(ppath), "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + if((str=getenv("ALSOFT_CONF")) != NULL && *str) + { + TRACE("Loading config %s...\n", str); + f = al_fopen(str, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + + alstr_reset(&ppath); +} +#endif + +void FreeALConfig(void) +{ + unsigned int i; + + for(i = 0;i < cfgBlock.entryCount;i++) + { + free(cfgBlock.entries[i].key); + free(cfgBlock.entries[i].value); + } + free(cfgBlock.entries); +} + +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) +{ + unsigned int i; + char key[256]; + + if(!keyName) + return def; + + if(blockName && strcasecmp(blockName, "general") != 0) + { + if(devName) + snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); + else + snprintf(key, sizeof(key), "%s/%s", blockName, keyName); + } + else + { + if(devName) + snprintf(key, sizeof(key), "%s/%s", devName, keyName); + else + { + strncpy(key, keyName, sizeof(key)-1); + key[sizeof(key)-1] = 0; + } + } + + for(i = 0;i < cfgBlock.entryCount;i++) + { + if(strcmp(cfgBlock.entries[i].key, key) == 0) + { + TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); + if(cfgBlock.entries[i].value[0]) + return cfgBlock.entries[i].value; + return def; + } + } + + if(!devName) + { + TRACE("Key %s not found\n", key); + return def; + } + return GetConfigValue(NULL, blockName, keyName, def); +} + +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + return !!val[0]; +} + +int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = val; + return 1; +} + +int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtol(val, NULL, 0); + return 1; +} + +int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtoul(val, NULL, 0); + return 1; +} + +int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + +#ifdef HAVE_STRTOF + *ret = strtof(val, NULL); +#else + *ret = (float)strtod(val, NULL); +#endif + return 1; +} + +int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); + return 1; +} + +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); + + if(!val[0]) return !!def; + return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); +} diff --git a/Alc/alconfig.h b/Alc/alconfig.h new file mode 100644 index 00000000..1e493e2e --- /dev/null +++ b/Alc/alconfig.h @@ -0,0 +1,17 @@ +#ifndef ALCONFIG_H +#define ALCONFIG_H + +void ReadALConfig(void); +void FreeALConfig(void); + +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); + +int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); +int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret); +int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret); +int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); +int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); + +#endif /* ALCONFIG_H */ diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 79f2795a..f941ce4b 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -26,6 +26,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index ceff0b3a..4ef9006c 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -26,6 +26,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 9c63d9d2..196432e1 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -35,6 +35,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 807e8000..0f4672c4 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -26,6 +26,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "compat.h" #include "backends/base.h" diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 8c5469b2..9f3c4762 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -25,6 +25,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 5dfb5084..59cc5ddc 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -34,6 +34,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index bdf76edc..1c502fd9 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -27,6 +27,7 @@ #include "alMain.h" #include "alu.h" +#include "alconfig.h" #include "threads.h" #include "compat.h" diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 54537a05..9d5e2ca9 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -30,6 +30,7 @@ #include "alu.h" #include "bformatdec.h" #include "hrtf.h" +#include "alconfig.h" #include "compat.h" #include "almalloc.h" diff --git a/Alc/mixer.c b/Alc/mixer.c index 3d1da58f..b1d859c6 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -34,6 +34,7 @@ #include "alListener.h" #include "alAuxEffectSlot.h" #include "alu.h" +#include "alconfig.h" #include "cpu_caps.h" #include "mixer_defs.h" diff --git a/Alc/panning.c b/Alc/panning.c index 37bf3ac9..dfb71918 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -29,6 +29,7 @@ #include "alMain.h" #include "alAuxEffectSlot.h" #include "alu.h" +#include "alconfig.h" #include "bool.h" #include "ambdec.h" #include "bformatdec.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 95b73c25..929b5517 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -713,7 +713,7 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c ) SET(ALC_OBJS Alc/ALc.c Alc/ALu.c - Alc/alcConfig.c + Alc/alconfig.c Alc/alcRing.c Alc/bs2b.c Alc/converter.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6556da37..ea797053 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -850,16 +850,6 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); -void ReadALConfig(void); -void FreeALConfig(void); -int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); -const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); -int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); -int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); -int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret); -int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret); -int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); -int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); void SetRTPriority(void); -- cgit v1.2.3 From 15ad5245bfa498dff729d2bb1cd91fad161cc806 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 08:44:52 -0800 Subject: Move the FPU mode declarations to a separate header Also don't use inheritance with FPUCtl. --- Alc/ALc.c | 1 + Alc/ALu.c | 1 + Alc/converter.c | 1 + Alc/fpu_modes.h | 37 +++++++++++++++++++++++++++++++++++++ Alc/helpers.c | 5 +++-- OpenAL32/Include/alMain.h | 32 -------------------------------- OpenAL32/alAuxEffectSlot.c | 1 + 7 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 Alc/fpu_modes.h diff --git a/Alc/ALc.c b/Alc/ALc.c index 5297af30..3b175b66 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -42,6 +42,7 @@ #include "alu.h" #include "alconfig.h" +#include "fpu_modes.h" #include "cpu_caps.h" #include "compat.h" #include "threads.h" diff --git a/Alc/ALu.c b/Alc/ALu.c index e0496513..2fe579b9 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -39,6 +39,7 @@ #include "bformatdec.h" #include "static_assert.h" +#include "fpu_modes.h" #include "cpu_caps.h" #include "mixer_defs.h" #include "bsinc_inc.h" diff --git a/Alc/converter.c b/Alc/converter.c index 8cba04a1..157073f2 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -3,6 +3,7 @@ #include "converter.h" +#include "fpu_modes.h" #include "mixer_defs.h" diff --git a/Alc/fpu_modes.h b/Alc/fpu_modes.h new file mode 100644 index 00000000..750252fc --- /dev/null +++ b/Alc/fpu_modes.h @@ -0,0 +1,37 @@ +#ifndef FPU_MODES_H +#define FPU_MODES_H + +#ifdef HAVE_FENV_H +#include +#endif + + +typedef struct FPUCtl { +#ifdef HAVE_FENV_H + fenv_t flt_env; +#ifdef _WIN32 + int round_mode; +#endif +#else + int state; +#endif +#ifdef HAVE_SSE + int sse_state; +#endif +} FPUCtl; +void SetMixerFPUMode(FPUCtl *ctl); +void RestoreFPUMode(const FPUCtl *ctl); + +#ifdef __GNUC__ +/* Use an alternate macro set with GCC to avoid accidental continue or break + * statements within the mixer mode. + */ +#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode) +#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); }) +#else +#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode) +#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0) +#endif +#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode) + +#endif /* FPU_MODES_H */ diff --git a/Alc/helpers.c b/Alc/helpers.c index 0f69b29e..238569d6 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -109,6 +109,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #include "alMain.h" #include "alu.h" #include "cpu_caps.h" +#include "fpu_modes.h" #include "atomic.h" #include "uintmap.h" #include "vector.h" @@ -295,7 +296,7 @@ void FillCPUCaps(int capfilter) void SetMixerFPUMode(FPUCtl *ctl) { #ifdef HAVE_FENV_H - fegetenv(STATIC_CAST(fenv_t, ctl)); + fegetenv(&ctl->flt_env); #ifdef _WIN32 /* HACK: A nasty bug in MinGW-W64 causes fegetenv and fesetenv to not save * and restore the FPU rounding mode, so we have to do it manually. Don't @@ -348,7 +349,7 @@ void SetMixerFPUMode(FPUCtl *ctl) void RestoreFPUMode(const FPUCtl *ctl) { #ifdef HAVE_FENV_H - fesetenv(STATIC_CAST(fenv_t, ctl)); + fesetenv(&ctl->flt_env); #ifdef _WIN32 fesetround(ctl->round_mode); #endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ea797053..5b4519eb 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -13,10 +13,6 @@ #include #endif -#ifdef HAVE_FENV_H -#include -#endif - #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" @@ -803,34 +799,6 @@ void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); -typedef struct { -#ifdef HAVE_FENV_H - DERIVE_FROM_TYPE(fenv_t); -#ifdef _WIN32 - int round_mode; -#endif -#else - int state; -#endif -#ifdef HAVE_SSE - int sse_state; -#endif -} FPUCtl; -void SetMixerFPUMode(FPUCtl *ctl); -void RestoreFPUMode(const FPUCtl *ctl); -#ifdef __GNUC__ -/* Use an alternate macro set with GCC to avoid accidental continue or break - * statements within the mixer mode. - */ -#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode); -#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); }) -#else -#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode); -#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0) -#endif -#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode) - - typedef struct ll_ringbuffer ll_ringbuffer_t; typedef struct ll_ringbuffer_data { char *buf; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 12092100..2dcf7125 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -32,6 +32,7 @@ #include "alListener.h" #include "alSource.h" +#include "fpu_modes.h" #include "almalloc.h" -- cgit v1.2.3 From 3832b25f308279539a3748bafdc5056d16e4b291 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:16:28 -0800 Subject: Move the ringbuffer declarations to a separate header And rename alcRing.c to ringbuffer.c for consistency. --- Alc/alcRing.c | 317 ---------------------------------------------- Alc/backends/alsa.c | 1 + Alc/backends/coreaudio.c | 1 + Alc/backends/dsound.c | 1 + Alc/backends/jack.c | 1 + Alc/backends/mmdevapi.c | 1 + Alc/backends/opensl.c | 3 +- Alc/backends/oss.c | 1 + Alc/backends/portaudio.c | 1 + Alc/backends/winmm.c | 1 + Alc/ringbuffer.c | 298 +++++++++++++++++++++++++++++++++++++++++++ Alc/ringbuffer.h | 29 +++++ CMakeLists.txt | 2 +- OpenAL32/Include/alMain.h | 20 --- 14 files changed, 338 insertions(+), 339 deletions(-) delete mode 100644 Alc/alcRing.c create mode 100644 Alc/ringbuffer.c create mode 100644 Alc/ringbuffer.h diff --git a/Alc/alcRing.c b/Alc/alcRing.c deleted file mode 100644 index d72b34f1..00000000 --- a/Alc/alcRing.c +++ /dev/null @@ -1,317 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "threads.h" -#include "almalloc.h" -#include "compat.h" - - -/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended - * to include an element size. Consequently, parameters and return values for a - * size or count is in 'elements', not bytes. Additionally, it only supports - * single-consumer/single-provider operation. */ -struct ll_ringbuffer { - ATOMIC(size_t) write_ptr; - ATOMIC(size_t) read_ptr; - size_t size; - size_t size_mask; - size_t elem_size; - int mlocked; - - alignas(16) char buf[]; -}; - -/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. - * The number of elements is rounded up to the next power of two. */ -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) -{ - ll_ringbuffer_t *rb; - ALuint power_of_two; - - power_of_two = NextPowerOf2(sz); - if(power_of_two < sz) - return NULL; - - rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); - if(!rb) return NULL; - - ATOMIC_INIT(&rb->write_ptr, 0); - ATOMIC_INIT(&rb->read_ptr, 0); - rb->size = power_of_two; - rb->size_mask = rb->size - 1; - rb->elem_size = elem_sz; - rb->mlocked = 0; - return rb; -} - -/* Free all data associated with the ringbuffer `rb'. */ -void ll_ringbuffer_free(ll_ringbuffer_t *rb) -{ - if(rb) - { -#ifdef USE_MLOCK - if(rb->mlocked) - munlock(rb, sizeof(*rb) + rb->size*rb->elem_size); -#endif /* USE_MLOCK */ - al_free(rb); - } -} - -/* Lock the data block of `rb' using the system call 'mlock'. */ -int ll_ringbuffer_mlock(ll_ringbuffer_t *rb) -{ -#ifdef USE_MLOCK - if(!rb->mlocked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size)) - return -1; -#endif /* USE_MLOCK */ - rb->mlocked = 1; - return 0; -} - -/* Reset the read and write pointers to zero. This is not thread safe. */ -void ll_ringbuffer_reset(ll_ringbuffer_t *rb) -{ - ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); - ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); - memset(rb->buf, 0, rb->size*rb->elem_size); -} - -/* Return the number of elements available for reading. This is the number of - * elements in front of the read pointer and behind the write pointer. */ -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) -{ - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - return (w-r) & rb->size_mask; -} -/* Return the number of elements available for writing. This is the number of - * elements in front of the write pointer and behind the read pointer. */ -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) -{ - size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - return (r-w-1) & rb->size_mask; -} - -/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. - * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) -{ - size_t read_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - - free_cnt = ll_ringbuffer_read_space(rb); - if(free_cnt == 0) return 0; - - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size) - { - n1 = rb->size - read_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_read; - n2 = 0; - } - - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - read_ptr += n1; - if(n2) - { - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); - read_ptr += n2; - } - ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); - return to_read; -} - -/* The copying data reader w/o read pointer advance. Copy at most `cnt' - * elements from `rb' to `dest'. Returns the actual number of elements copied. - */ -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) -{ - size_t free_cnt; - size_t cnt2; - size_t to_read; - size_t n1, n2; - size_t read_ptr; - - free_cnt = ll_ringbuffer_read_space(rb); - if(free_cnt == 0) return 0; - - to_read = (cnt > free_cnt) ? free_cnt : cnt; - read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = read_ptr + to_read; - if(cnt2 > rb->size) - { - n1 = rb->size - read_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_read; - n2 = 0; - } - - memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); - if(n2) - { - read_ptr += n1; - memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], - n2*rb->elem_size); - } - return to_read; -} - -/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'. - * Returns the actual number of elements copied. */ -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) -{ - size_t write_ptr; - size_t free_cnt; - size_t cnt2; - size_t to_write; - size_t n1, n2; - - free_cnt = ll_ringbuffer_write_space(rb); - if(free_cnt == 0) return 0; - - to_write = (cnt > free_cnt) ? free_cnt : cnt; - write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; - - cnt2 = write_ptr + to_write; - if(cnt2 > rb->size) - { - n1 = rb->size - write_ptr; - n2 = cnt2 & rb->size_mask; - } - else - { - n1 = to_write; - n2 = 0; - } - - memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); - write_ptr += n1; - if(n2) - { - memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, - n2*rb->elem_size); - write_ptr += n2; - } - ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); - return to_write; -} - -/* Advance the read pointer `cnt' places. */ -void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) -{ - ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); -} - -/* Advance the write pointer `cnt' places. */ -void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) -{ - ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); -} - -/* The non-copying data reader. `vec' is an array of two places. Set the values - * at `vec' to hold the current readable data at `rb'. If the readable data is - * in one segment the second segment has zero length. */ -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec) -{ - size_t free_cnt; - size_t cnt2; - size_t w, r; - - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (w-r) & rb->size_mask; - - cnt2 = r + free_cnt; - if(cnt2 > rb->size) - { - /* Two part vector: the rest of the buffer after the current write ptr, - * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; - vec[0].len = rb->size - r; - vec[1].buf = (char*)rb->buf; - vec[1].len = cnt2 & rb->size_mask; - } - else - { - /* Single part vector: just the rest of the buffer */ - vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; - vec[0].len = free_cnt; - vec[1].buf = NULL; - vec[1].len = 0; - } -} - -/* The non-copying data writer. `vec' is an array of two places. Set the values - * at `vec' to hold the current writeable data at `rb'. If the writeable data - * is in one segment the second segment has zero length. */ -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec) -{ - size_t free_cnt; - size_t cnt2; - size_t w, r; - - w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); - r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - w &= rb->size_mask; - r &= rb->size_mask; - free_cnt = (r-w-1) & rb->size_mask; - - cnt2 = w + free_cnt; - if(cnt2 > rb->size) - { - /* Two part vector: the rest of the buffer after the current write ptr, - * plus some from the start of the buffer. */ - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; - vec[0].len = rb->size - w; - vec[1].buf = (char*)rb->buf; - vec[1].len = cnt2 & rb->size_mask; - } - else - { - vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; - vec[0].len = free_cnt; - vec[1].buf = NULL; - vec[1].len = 0; - } -} diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index f941ce4b..fb5a4446 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -27,6 +27,7 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index ec926d3d..ba73ab82 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -27,6 +27,7 @@ #include "alMain.h" #include "alu.h" +#include "ringbuffer.h" #include #include diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index f730dc95..f88a50c1 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -34,6 +34,7 @@ #include "alMain.h" #include "alu.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" #include "alstring.h" diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 4ef9006c..0dc01ae7 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -27,6 +27,7 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 9afb62f0..ecd7eb5d 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -41,6 +41,7 @@ #include "alMain.h" #include "alu.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" #include "alstring.h" diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index aa1ff991..4ec003d8 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -26,8 +26,9 @@ #include "alMain.h" #include "alu.h" -#include "compat.h" +#include "ringbuffer.h" #include "threads.h" +#include "compat.h" #include "backends/base.h" diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 196432e1..2ff7c72b 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -36,6 +36,7 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "threads.h" #include "compat.h" diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 0f4672c4..b793486f 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -27,6 +27,7 @@ #include "alMain.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "compat.h" #include "backends/base.h" diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index b5b3cdb6..4e4d0c06 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -29,6 +29,7 @@ #include "alMain.h" #include "alu.h" +#include "ringbuffer.h" #include "threads.h" #include "backends/base.h" diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c new file mode 100644 index 00000000..63add593 --- /dev/null +++ b/Alc/ringbuffer.c @@ -0,0 +1,298 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "ringbuffer.h" +#include "alMain.h" +#include "threads.h" +#include "almalloc.h" +#include "compat.h" + + +/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended + * to include an element size. Consequently, parameters and return values for a + * size or count is in 'elements', not bytes. Additionally, it only supports + * single-consumer/single-provider operation. */ +struct ll_ringbuffer { + ATOMIC(size_t) write_ptr; + ATOMIC(size_t) read_ptr; + size_t size; + size_t size_mask; + size_t elem_size; + + alignas(16) char buf[]; +}; + +/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. + * The number of elements is rounded up to the next power of two. */ +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) +{ + ll_ringbuffer_t *rb; + size_t power_of_two; + + power_of_two = NextPowerOf2(sz); + if(power_of_two < sz) + return NULL; + + rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); + if(!rb) return NULL; + + ATOMIC_INIT(&rb->write_ptr, 0); + ATOMIC_INIT(&rb->read_ptr, 0); + rb->size = power_of_two; + rb->size_mask = rb->size - 1; + rb->elem_size = elem_sz; + return rb; +} + +/* Free all data associated with the ringbuffer `rb'. */ +void ll_ringbuffer_free(ll_ringbuffer_t *rb) +{ + al_free(rb); +} + +/* Reset the read and write pointers to zero. This is not thread safe. */ +void ll_ringbuffer_reset(ll_ringbuffer_t *rb) +{ + ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); + ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); + memset(rb->buf, 0, rb->size*rb->elem_size); +} + +/* Return the number of elements available for reading. This is the number of + * elements in front of the read pointer and behind the write pointer. */ +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) +{ + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + return (w-r) & rb->size_mask; +} +/* Return the number of elements available for writing. This is the number of + * elements in front of the write pointer and behind the read pointer. */ +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) +{ + size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + return (r-w-1) & rb->size_mask; +} + +/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. + * Returns the actual number of elements copied. */ +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t read_ptr; + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; + if(cnt2 > rb->size) + { + n1 = rb->size - read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + read_ptr += n1; + if(n2) + { + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); + read_ptr += n2; + } + ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release); + return to_read; +} + +/* The copying data reader w/o read pointer advance. Copy at most `cnt' + * elements from `rb' to `dest'. Returns the actual number of elements copied. + */ +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + size_t read_ptr; + + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = read_ptr + to_read; + if(cnt2 > rb->size) + { + n1 = rb->size - read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size); + if(n2) + { + read_ptr += n1; + memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size], + n2*rb->elem_size); + } + return to_read; +} + +/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'. + * Returns the actual number of elements copied. */ +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) +{ + size_t write_ptr; + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + free_cnt = ll_ringbuffer_write_space(rb); + if(free_cnt == 0) return 0; + + to_write = (cnt > free_cnt) ? free_cnt : cnt; + write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; + + cnt2 = write_ptr + to_write; + if(cnt2 > rb->size) + { + n1 = rb->size - write_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_write; + n2 = 0; + } + + memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size); + write_ptr += n1; + if(n2) + { + memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size, + n2*rb->elem_size); + write_ptr += n2; + } + ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release); + return to_write; +} + +/* Advance the read pointer `cnt' places. */ +void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); +} + +/* Advance the write pointer `cnt' places. */ +void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); +} + +/* The non-copying data reader. `vec' is an array of two places. Set the values + * at `vec' to hold the current readable data at `rb'. If the readable data is + * in one segment the second segment has zero length. */ +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; + free_cnt = (w-r) & rb->size_mask; + + cnt2 = r + free_cnt; + if(cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].len = rb->size - r; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + /* Single part vector: just the rest of the buffer */ + vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} + +/* The non-copying data writer. `vec' is an array of two places. Set the values + * at `vec' to hold the current writeable data at `rb'. If the writeable data + * is in one segment the second segment has zero length. */ +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); + r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); + w &= rb->size_mask; + r &= rb->size_mask; + free_cnt = (r-w-1) & rb->size_mask; + + cnt2 = w + free_cnt; + if(cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].len = rb->size - w; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h new file mode 100644 index 00000000..f764c20f --- /dev/null +++ b/Alc/ringbuffer.h @@ -0,0 +1,29 @@ +#ifndef RINGBUFFER_H +#define RINGBUFFER_H + +#include + + +typedef struct ll_ringbuffer ll_ringbuffer_t; +typedef struct ll_ringbuffer_data { + char *buf; + size_t len; +} ll_ringbuffer_data_t; + +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz); +void ll_ringbuffer_free(ll_ringbuffer_t *rb); +void ll_ringbuffer_reset(ll_ringbuffer_t *rb); + +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); + +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt); +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt); +void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); + +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); +void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); + +#endif /* RINGBUFFER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 929b5517..0b07f4ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -714,10 +714,10 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c SET(ALC_OBJS Alc/ALc.c Alc/ALu.c Alc/alconfig.c - Alc/alcRing.c Alc/bs2b.c Alc/converter.c Alc/mastering.c + Alc/ringbuffer.c Alc/effects/chorus.c Alc/effects/compressor.c Alc/effects/dedicated.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5b4519eb..c11eb6d1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -799,26 +799,6 @@ void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); -typedef struct ll_ringbuffer ll_ringbuffer_t; -typedef struct ll_ringbuffer_data { - char *buf; - size_t len; -} ll_ringbuffer_data_t; -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz); -void ll_ringbuffer_free(ll_ringbuffer_t *rb); -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); -size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt); -size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt); -void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); -int ll_ringbuffer_mlock(ll_ringbuffer_t *rb); -void ll_ringbuffer_reset(ll_ringbuffer_t *rb); -size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); -void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); - - void SetRTPriority(void); void SetDefaultChannelOrder(ALCdevice *device); -- cgit v1.2.3 From 88545ccae5bbae0a95c5b347b8e17a0debe7b1f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:25:17 -0800 Subject: Move the EffectList array to alEffect.c/h --- OpenAL32/Include/alEffect.h | 9 +++++++++ OpenAL32/Include/alMain.h | 8 -------- OpenAL32/alEffect.c | 15 +++++++++++++++ OpenAL32/alExtension.c | 16 ---------------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index bec50f7d..394500e0 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -27,6 +27,15 @@ extern ALboolean DisabledEffects[MAX_EFFECTS]; extern ALfloat ReverbBoost; +struct EffectList { + const char *name; + int type; + const char *ename; + ALenum val; +}; +extern const struct EffectList EffectList[]; + + 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); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c11eb6d1..a6a6471b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -471,14 +471,6 @@ enum AmbiNorm { }; -extern const struct EffectList { - const char *name; - int type; - const char *ename; - ALenum val; -} EffectList[]; - - enum DeviceType { Playback, Capture, diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 0dac429a..6fa748b3 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -32,6 +32,21 @@ #include "alError.h" +const struct EffectList EffectList[] = { + { "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, + { "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, + { "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, + { "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, + { "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, + { "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, + { "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, + { "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, + { "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, + { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, + { NULL, 0, NULL, (ALenum)0 } +}; + ALboolean DisabledEffects[MAX_EFFECTS]; extern inline void LockEffectsRead(ALCdevice *device); diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index c85e9007..7db326a2 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -35,22 +35,6 @@ #include "AL/alc.h" -const struct EffectList EffectList[] = { - { "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, - { "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, - { "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, - { "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, - { "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, - { "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, - { "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, - { "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, - { "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, - { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, - { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, - { NULL, 0, NULL, (ALenum)0 } -}; - - AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) { ALboolean ret = AL_FALSE; -- cgit v1.2.3 From 85a8f965e56dadf6928ca66503391029d7965928 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:34:01 -0800 Subject: Clean up the EffectList members and make the list size known --- Alc/ALc.c | 2 +- OpenAL32/Include/alEffect.h | 26 +++++++++++++------------- OpenAL32/alEffect.c | 31 +++++++++++++++---------------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3b175b66..00d75f8c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1133,7 +1133,7 @@ static void alc_initconfig(void) continue; len = (next ? ((size_t)(next-str)) : strlen(str)); - for(n = 0;EffectList[n].name;n++) + for(n = 0;n < EFFECTLIST_SIZE;n++) { if(len == strlen(EffectList[n].name) && strncmp(EffectList[n].name, str, len) == 0) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 394500e0..dbbd8966 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -10,16 +10,16 @@ extern "C" { struct ALeffect; enum { - AL__EAXREVERB = 0, - AL__REVERB, - AL__CHORUS, - AL__COMPRESSOR, - AL__DISTORTION, - AL__ECHO, - AL__EQUALIZER, - AL__FLANGER, - AL__MODULATOR, - AL__DEDICATED, + EAXREVERB_EFFECT = 0, + REVERB_EFFECT, + CHORUS_EFFECT, + COMPRESSOR_EFFECT, + DISTORTION_EFFECT, + ECHO_EFFECT, + EQUALIZER_EFFECT, + FLANGER_EFFECT, + MODULATOR_EFFECT, + DEDICATED_EFFECT, MAX_EFFECTS }; @@ -28,12 +28,12 @@ extern ALboolean DisabledEffects[MAX_EFFECTS]; extern ALfloat ReverbBoost; struct EffectList { - const char *name; + const char name[16]; int type; - const char *ename; ALenum val; }; -extern const struct EffectList EffectList[]; +#define EFFECTLIST_SIZE 11 +extern const struct EffectList EffectList[EFFECTLIST_SIZE]; struct ALeffectVtable { diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 6fa748b3..48268247 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -32,19 +32,18 @@ #include "alError.h" -const struct EffectList EffectList[] = { - { "eaxreverb", AL__EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, - { "reverb", AL__REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, - { "chorus", AL__CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS }, - { "compressor", AL__COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR }, - { "distortion", AL__DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION }, - { "echo", AL__ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, - { "equalizer", AL__EQUALIZER, "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER }, - { "flanger", AL__FLANGER, "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER }, - { "modulator", AL__MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, - { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, - { "dedicated", AL__DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, - { NULL, 0, NULL, (ALenum)0 } +const struct EffectList EffectList[EFFECTLIST_SIZE] = { + { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, + { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, + { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, + { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, + { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, + { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, + { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, + { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, }; ALboolean DisabledEffects[MAX_EFFECTS]; @@ -175,7 +174,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) { ALboolean isOk = (value == AL_EFFECT_NULL); ALint i; - for(i = 0;!isOk && EffectList[i].val;i++) + for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++) { if(value == EffectList[i].val && !DisabledEffects[EffectList[i].type]) @@ -682,9 +681,9 @@ ALvoid LoadReverbPreset(const char *name, ALeffect *effect) return; } - if(!DisabledEffects[AL__EAXREVERB]) + if(!DisabledEffects[EAXREVERB_EFFECT]) InitEffectParams(effect, AL_EFFECT_EAXREVERB); - else if(!DisabledEffects[AL__REVERB]) + else if(!DisabledEffects[REVERB_EFFECT]) InitEffectParams(effect, AL_EFFECT_REVERB); else InitEffectParams(effect, AL_EFFECT_NULL); -- cgit v1.2.3 From 2d2ca1d79110e0100e7a1f3b1c37efc527e37a3b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:39:52 -0800 Subject: Remove SET_VTABLE1 --- Alc/polymorphism.h | 3 --- OpenAL32/alEffect.c | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index b41ad64b..fa31fad2 100644 --- a/Alc/polymorphism.h +++ b/Alc/polymorphism.h @@ -102,7 +102,4 @@ static void T##_Delete(void *ptr) { al_free(ptr); } /* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */ #define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2)) -/* Helper to set an object's vtable for a type. */ -#define SET_VTABLE1(T1, obj) ((obj)->vtbl = &(T1##_vtable)) - #endif /* POLYMORPHISM_H */ diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 48268247..bb56e6a3 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -432,7 +432,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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); + effect->vtbl = &ALeaxreverb_vtable; break; case AL_EFFECT_REVERB: effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; @@ -462,7 +462,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Reverb.LFReference = 250.0f; effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - SET_VTABLE1(ALreverb, effect); + effect->vtbl = &ALreverb_vtable; break; case AL_EFFECT_CHORUS: effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; @@ -471,11 +471,11 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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); + effect->vtbl = &ALchorus_vtable; break; case AL_EFFECT_COMPRESSOR: effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; - SET_VTABLE1(ALcompressor, effect); + effect->vtbl = &ALcompressor_vtable; break; case AL_EFFECT_DISTORTION: effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; @@ -483,7 +483,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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); + effect->vtbl = &ALdistortion_vtable; break; case AL_EFFECT_ECHO: effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; @@ -491,7 +491,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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); + effect->vtbl = &ALecho_vtable; break; case AL_EFFECT_EQUALIZER: effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; @@ -504,7 +504,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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); + effect->vtbl = &ALequalizer_vtable; break; case AL_EFFECT_FLANGER: effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; @@ -513,21 +513,21 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; - SET_VTABLE1(ALflanger, effect); + effect->vtbl = &ALflanger_vtable; break; case AL_EFFECT_RING_MODULATOR: 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); + effect->vtbl = &ALmodulator_vtable; break; case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: case AL_EFFECT_DEDICATED_DIALOGUE: effect->Props.Dedicated.Gain = 1.0f; - SET_VTABLE1(ALdedicated, effect); + effect->vtbl = &ALdedicated_vtable; break; default: - SET_VTABLE1(ALnull, effect); + effect->vtbl = &ALnull_vtable; break; } effect->type = type; -- cgit v1.2.3 From b11131ce0c76d2b46208ad5473dd86dc5343ce5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:43:45 -0800 Subject: Move a forward declaration to the others --- OpenAL32/Include/alMain.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index a6a6471b..917e2e39 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -292,6 +292,7 @@ struct HrtfEntry; struct DirectHrtfState; struct FrontStablizer; struct Compressor; +struct ALCbackend; struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; @@ -364,8 +365,6 @@ enum DevProbe { CAPTURE_DEVICE_PROBE }; -struct ALCbackend; - enum DistanceModel { InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED, -- cgit v1.2.3 From ca9e6a4f9434ca25f821802d1b6e1363b18d7b81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 09:53:52 -0800 Subject: Ensure NextPowerOf2 is being used correctly --- Alc/effects/chorus.c | 4 ++-- Alc/effects/echo.c | 7 ++++--- Alc/ringbuffer.c | 5 ++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 9be69f92..901c1157 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -98,8 +98,8 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); ALsizei maxlen; - maxlen = fastf2i(max_delay * 2.0f * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); + maxlen = NextPowerOf2(fastf2i(max_delay*2.0f*Device->Frequency) + 1); + if(maxlen <= 0) return AL_FALSE; if(maxlen != state->BufferLength) { diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 3d538d9d..cd556f1a 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -91,9 +91,10 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) // 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 = fastf2i(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; - maxlen += fastf2i(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; - maxlen = NextPowerOf2(maxlen); + maxlen = fastf2i(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + + fastf2i(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); + maxlen = NextPowerOf2(maxlen); + if(maxlen <= 0) return AL_FALSE; if(maxlen != state->BufferLength) { diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c index 63add593..e2ea2ab5 100644 --- a/Alc/ringbuffer.c +++ b/Alc/ringbuffer.c @@ -51,9 +51,8 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) ll_ringbuffer_t *rb; size_t power_of_two; - power_of_two = NextPowerOf2(sz); - if(power_of_two < sz) - return NULL; + power_of_two = NextPowerOf2((ALuint)sz); + if(power_of_two < sz) return NULL; rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); if(!rb) return NULL; -- cgit v1.2.3 From e89c183231d26770f4c8ae80a8d05063c34cf0c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 10:03:26 -0800 Subject: Avoid including alMain.h in ringbuffer.c --- Alc/ringbuffer.c | 19 ++++++++++++++++--- OpenAL32/Include/alMain.h | 14 -------------- common/atomic.h | 13 +++++++++++++ 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c index e2ea2ab5..e029e9b6 100644 --- a/Alc/ringbuffer.c +++ b/Alc/ringbuffer.c @@ -24,7 +24,8 @@ #include #include "ringbuffer.h" -#include "alMain.h" +#include "align.h" +#include "atomic.h" #include "threads.h" #include "almalloc.h" #include "compat.h" @@ -49,9 +50,21 @@ struct ll_ringbuffer { ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) { ll_ringbuffer_t *rb; - size_t power_of_two; + size_t power_of_two = 0; - power_of_two = NextPowerOf2((ALuint)sz); + if(sz > 0) + { + power_of_two = sz - 1; + power_of_two |= power_of_two>>1; + power_of_two |= power_of_two>>2; + power_of_two |= power_of_two>>4; + power_of_two |= power_of_two>>8; + power_of_two |= power_of_two>>16; +#if SIZE_MAX > UINT_MAX + power_of_two |= power_of_two>>32; +#endif + } + power_of_two++; if(power_of_two < sz) return NULL; rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 917e2e39..7af1c195 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -186,20 +186,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif -#ifdef __GNUC__ -/* This helps cast away the const-ness of a pointer without accidentally - * changing the pointer type. This is necessary due to Clang's inability to use - * atomic_load on a const _Atomic variable. - */ -#define CONST_CAST(T, V) __extension__({ \ - const T _tmp = (V); \ - (T)_tmp; \ -}) -#else -#define CONST_CAST(T, V) ((T)(V)) -#endif - - #ifdef __GNUC__ #define LIKELY(x) __builtin_expect(!!(x), !0) #define UNLIKELY(x) __builtin_expect(!!(x), 0) diff --git a/common/atomic.h b/common/atomic.h index 874d510d..2033476b 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -4,6 +4,19 @@ #include "static_assert.h" #include "bool.h" +#ifdef __GNUC__ +/* This helps cast away the const-ness of a pointer without accidentally + * changing the pointer type. This is necessary due to Clang's inability to use + * atomic_load on a const _Atomic variable. + */ +#define CONST_CAST(T, V) __extension__({ \ + const T _tmp = (V); \ + (T)_tmp; \ +}) +#else +#define CONST_CAST(T, V) ((T)(V)) +#endif + #ifdef __cplusplus extern "C" { #endif -- cgit v1.2.3 From 2873abcbc056ca2123382b2b1e08b8bd94d608a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 10:55:35 -0800 Subject: Fix up some types for MSVC --- Alc/backends/dsound.c | 2 +- Alc/backends/winmm.c | 2 +- Alc/bformatdec.c | 8 ++++---- Alc/effects/chorus.c | 3 ++- Alc/hrtf.c | 3 ++- Alc/panning.c | 2 +- common/atomic.h | 3 ++- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index f88a50c1..8a0a30cb 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -948,7 +948,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) } done: - return ll_ringbuffer_read_space(self->Ring); + return (ALCuint)ll_ringbuffer_read_space(self->Ring); } diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 4e4d0c06..0fcab458 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -708,7 +708,7 @@ static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *bu static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - return ll_ringbuffer_read_space(self->Ring); + return (ALCuint)ll_ringbuffer_read_space(self->Ring); } diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 3efdfba9..6503ac65 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -532,7 +532,7 @@ void ambiup_free(struct AmbiUpsampler *ambiup) void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { ALfloat ratio; - size_t i; + ALsizei i; ratio = 400.0f / (ALfloat)device->Frequency; for(i = 0;i < 4;i++) @@ -545,11 +545,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) ALsizei j; size_t k; - for(i = 0;i < COUNTOF(Ambi3DPoints);i++) + for(k = 0;k < COUNTOF(Ambi3DPoints);k++) { ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; - CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[i]); + CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[k]); } /* Combine the matrices that do the in->virt and virt->out conversions diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 901c1157..2592c673 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -142,7 +142,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte */ state->delay = maxi(fastf2i(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); - state->depth = minf(props->Chorus.Depth * state->delay, state->delay - mindelay); + state->depth = minf(props->Chorus.Depth * state->delay, + (ALfloat)(state->delay - mindelay)); state->feedback = props->Chorus.Feedback; diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 9d5e2ca9..310dc68c 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -298,7 +298,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } } /* Round up to the next IR size multiple. */ - max_length = RoundUp(max_length, MOD_IR_SIZE); + max_length += MOD_IR_SIZE-1; + max_length -= max_length%MOD_IR_SIZE; TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); state->IrSize = max_length; diff --git a/Alc/panning.c b/Alc/panning.c index dfb71918..1691aacd 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -512,7 +512,7 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL { const char *devname = alstr_get_cstr(device->DeviceName); ALfloat maxdist = 0.0f; - ALsizei total = 0; + size_t total = 0; ALsizei i; for(i = 0;i < conf->NumSpeakers;i++) diff --git a/common/atomic.h b/common/atomic.h index 2033476b..64b06cce 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -306,6 +306,7 @@ enum almemory_order { } while(0) int _al_invalid_atomic_size(); /* not defined */ +void *_al_invalid_atomic_ptr_size(); /* not defined */ #define ATOMIC_ADD(_val, _incr, _MO) \ ((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \ @@ -327,7 +328,7 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \ ((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \ - (void*)_al_invalid_atomic_size()) + _al_invalid_atomic_ptr_size()) #define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\ ((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \ (bool)_al_invalid_atomic_size()) -- cgit v1.2.3 From 370817ba604954418b1d0e03daa11b1d55614e2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 20:17:02 -0800 Subject: Move logging declarations to a separate header --- Alc/logging.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/alMain.h | 59 ++------------------------------------------- 2 files changed, 63 insertions(+), 57 deletions(-) create mode 100644 Alc/logging.h diff --git a/Alc/logging.h b/Alc/logging.h new file mode 100644 index 00000000..18093b75 --- /dev/null +++ b/Alc/logging.h @@ -0,0 +1,61 @@ +#ifndef LOGGING_H +#define LOGGING_H + +#include + + +#ifdef __GNUC__ +#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) +#else +#define DECL_FORMAT(x, y, z) +#endif + +extern FILE *LogFile; + +#if defined(__GNUC__) && !defined(_WIN32) +#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, ...) DECL_FORMAT(printf, 3,4); +#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) +#endif + +#ifdef __ANDROID__ +#include +#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__) +#else +#define LOG_ANDROID(T, MSG, ...) ((void)0) +#endif + +enum LogLevel { + NoLog, + LogError, + LogWarning, + LogTrace, + LogRef +}; +extern enum LogLevel LogLevel; + +#define TRACEREF(...) do { \ + if(LogLevel >= LogRef) \ + AL_PRINT("(--)", __VA_ARGS__); \ +} while(0) + +#define TRACE(...) do { \ + if(LogLevel >= LogTrace) \ + AL_PRINT("(II)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ +} while(0) + +#define WARN(...) do { \ + if(LogLevel >= LogWarning) \ + AL_PRINT("(WW)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ +} while(0) + +#define ERR(...) do { \ + if(LogLevel >= LogError) \ + AL_PRINT("(EE)", __VA_ARGS__); \ + LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ +} while(0) + +#endif /* LOGGING_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7af1c195..7706d598 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -17,6 +17,7 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "logging.h" #include "polymorphism.h" #include "static_assert.h" #include "align.h" @@ -223,12 +224,6 @@ typedef ALuint64SOFT ALuint64; #endif #endif -#ifdef __GNUC__ -#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) -#else -#define DECL_FORMAT(x, y, z) -#endif - /* Calculates the size of a struct with N elements of a flexible array member. * GCC and Clang allow offsetof(Type, fam[N]) for this, but MSVC seems to have * trouble, so a bit more verbose workaround is needed. @@ -776,6 +771,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context); void ALCcontext_ProcessUpdates(ALCcontext *context); +extern ALint RTPrioLevel; void SetRTPriority(void); void SetDefaultChannelOrder(ALCdevice *device); @@ -803,57 +799,6 @@ inline ALint GetChannelIndex(const enum Channel names[MAX_OUTPUT_CHANNELS], enum inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) { return GetChannelIndex(real->ChannelName, chan); } -extern FILE *LogFile; - -#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER) -#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, ...) DECL_FORMAT(printf, 3,4); -#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) -#endif - -#ifdef __ANDROID__ -#include -#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__) -#else -#define LOG_ANDROID(T, MSG, ...) ((void)0) -#endif - -enum LogLevel { - NoLog, - LogError, - LogWarning, - LogTrace, - LogRef -}; -extern enum LogLevel LogLevel; - -#define TRACEREF(...) do { \ - if(LogLevel >= LogRef) \ - AL_PRINT("(--)", __VA_ARGS__); \ -} while(0) - -#define TRACE(...) do { \ - if(LogLevel >= LogTrace) \ - AL_PRINT("(II)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__); \ -} while(0) - -#define WARN(...) do { \ - if(LogLevel >= LogWarning) \ - AL_PRINT("(WW)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__); \ -} while(0) - -#define ERR(...) do { \ - if(LogLevel >= LogError) \ - AL_PRINT("(EE)", __VA_ARGS__); \ - LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ -} while(0) - - -extern ALint RTPrioLevel; - vector_al_string SearchDataFiles(const char *match, const char *subdir); -- cgit v1.2.3 From 1f236d8f204c66a5c0a1885b6893d6cb8b0c289d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 22:42:25 -0800 Subject: Define a function where it's used --- Alc/backends/mmdevapi.c | 7 +++++++ Alc/helpers.c | 3 --- OpenAL32/Include/alMain.h | 18 ------------------ 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index ecd7eb5d..9604d0f9 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -71,6 +71,13 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x #define DEVNAME_HEAD "OpenAL Soft on " +/* Scales the given value using 64-bit integer math, ceiling the result. */ +static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) +{ + return (val*new_scale + old_scale-1) / old_scale; +} + + typedef struct { al_string name; al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. diff --git a/Alc/helpers.c b/Alc/helpers.c index 238569d6..5d39f3d8 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -120,9 +120,6 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x extern inline ALuint NextPowerOf2(ALuint value); extern inline size_t RoundUp(size_t value, size_t r); -extern inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale); -extern inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale); -extern inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale); extern inline ALint fastf2i(ALfloat f); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7706d598..76624a66 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -306,24 +306,6 @@ inline size_t RoundUp(size_t value, size_t r) return value - (value%r); } -/* Scales the given value using 64-bit integer math, rounding the result. */ -inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) -{ - return (val*new_scale + old_scale/2) / old_scale; -} - -/* Scales the given value using 64-bit integer math, flooring the result. */ -inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) -{ - return val * new_scale / old_scale; -} - -/* Scales the given value using 64-bit integer math, ceiling the result. */ -inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) -{ - return (val*new_scale + old_scale-1) / old_scale; -} - /* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero * mode. */ inline ALint fastf2i(ALfloat f) -- cgit v1.2.3 From dae5faedb05c3a889a0bb1f957e610c8af85a155 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Jan 2018 23:28:15 -0800 Subject: Use atomic variables in place of volatile --- Alc/backends/mmdevapi.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 9604d0f9..670d1561 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -533,9 +533,9 @@ typedef struct ALCmmdevPlayback { HANDLE MsgEvent; - volatile UINT32 Padding; + ATOMIC(UINT32) Padding; - volatile int killNow; + ATOMIC(int) killNow; althrd_t thread; } ALCmmdevPlayback; @@ -580,9 +580,9 @@ static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device self->MsgEvent = NULL; - self->Padding = 0; + ATOMIC_INIT(&self->Padding, 0); - self->killNow = 0; + ATOMIC_INIT(&self->killNow, 0); } static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self) @@ -626,7 +626,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) update_size = device->UpdateSize; buffer_len = update_size * device->NumUpdates; - while(!self->killNow) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) { hr = IAudioClient_GetCurrentPadding(self->client, &written); if(FAILED(hr)) @@ -637,7 +637,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) V0(device->Backend,unlock)(); break; } - self->Padding = written; + ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); len = buffer_len - written; if(len < update_size) @@ -655,7 +655,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) { ALCmmdevPlayback_lock(self); aluMixData(device, buffer, len); - self->Padding = written + len; + ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); ALCmmdevPlayback_unlock(self); hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); } @@ -668,7 +668,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) break; } } - self->Padding = 0; + ATOMIC_STORE(&self->Padding, 0, almemory_order_release); CoUninitialize(); return 0; @@ -1162,7 +1162,7 @@ static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self) if(SUCCEEDED(hr)) { self->render = ptr; - self->killNow = 0; + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); if(althrd_create(&self->thread, ALCmmdevPlayback_mixerProc, self) != althrd_success) { if(self->render) @@ -1192,7 +1192,7 @@ static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self) if(!self->render) return; - self->killNow = 1; + ATOMIC_STORE_SEQ(&self->killNow, 1); althrd_join(self->thread, &res); IAudioRenderClient_Release(self->render); @@ -1208,7 +1208,8 @@ static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self) ALCmmdevPlayback_lock(self); ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = self->Padding * DEVICE_CLOCK_RES / device->Frequency; + ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / + device->Frequency; ALCmmdevPlayback_unlock(self); return ret; @@ -1232,7 +1233,7 @@ typedef struct ALCmmdevCapture { SampleConverter *SampleConv; ll_ringbuffer_t *Ring; - volatile int killNow; + ATOMIC(int) killNow; althrd_t thread; } ALCmmdevCapture; @@ -1281,7 +1282,7 @@ static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) self->SampleConv = NULL; self->Ring = NULL; - self->killNow = 0; + ATOMIC_INIT(&self->killNow, 0); } static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) @@ -1327,7 +1328,7 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) althrd_setname(althrd_current(), RECORD_THREAD_NAME); - while(!self->killNow) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) { UINT32 avail; DWORD res; @@ -1875,7 +1876,7 @@ static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self) if(SUCCEEDED(hr)) { self->capture = ptr; - self->killNow = 0; + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success) { ERR("Failed to start thread\n"); @@ -1909,7 +1910,7 @@ static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self) if(!self->capture) return; - self->killNow = 1; + ATOMIC_STORE_SEQ(&self->killNow, 1); althrd_join(self->thread, &res); IAudioCaptureClient_Release(self->capture); -- cgit v1.2.3 From e634564b26091fc315fdc592f4f87fdff86be729 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Jan 2018 02:37:48 -0800 Subject: Make a couple functions inline --- Alc/ALc.c | 17 +++-------------- Alc/backends/base.c | 2 ++ Alc/backends/base.h | 7 +++++++ OpenAL32/Include/alMain.h | 10 +++------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 00d75f8c..e70e83dd 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1494,17 +1494,6 @@ static ALCboolean IsValidAmbiScaling(ALCenum scaling) * Miscellaneous ALC helpers ************************************************/ -void ALCdevice_Lock(ALCdevice *device) -{ - V0(device->Backend,lock)(); -} - -void ALCdevice_Unlock(ALCdevice *device) -{ - V0(device->Backend,unlock)(); -} - - /* SetDefaultWFXChannelOrder * * Sets the default channel order used by WaveFormatEx. @@ -2732,7 +2721,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, NULL)) ALCcontext_DecRef(context); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); origctx = context; newhead = context->next; if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) @@ -2750,13 +2739,13 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) } else ret = !!newhead; - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); ALCcontext_DecRef(context); return ret; } -void ALCcontext_IncRef(ALCcontext *context) +static void ALCcontext_IncRef(ALCcontext *context) { uint ref = IncrementRef(&context->ref); TRACEREF("%p increasing refcount to %u\n", context, ref); diff --git a/Alc/backends/base.c b/Alc/backends/base.c index 5f568d8e..a451fee9 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -10,6 +10,8 @@ extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); +extern inline void ALCdevice_Lock(ALCdevice *device); +extern inline void ALCdevice_Unlock(ALCdevice *device); /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 8464fdee..318e86fc 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -152,4 +152,11 @@ ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); + +inline void ALCdevice_Lock(ALCdevice *device) +{ V0(device->Backend,lock)(); } + +inline void ALCdevice_Unlock(ALCdevice *device) +{ V0(device->Backend,unlock)(); } + #endif /* AL_BACKENDS_BASE_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 76624a66..2fe7f71f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -738,20 +738,16 @@ struct ALCcontext_struct { ALCcontext *GetContextRef(void); -void ALCcontext_IncRef(ALCcontext *context); void ALCcontext_DecRef(ALCcontext *context); +void ALCcontext_DeferUpdates(ALCcontext *context); +void ALCcontext_ProcessUpdates(ALCcontext *context); + void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); void AppendAllDevicesList(const ALCchar *name); void AppendCaptureDeviceList(const ALCchar *name); -void ALCdevice_Lock(ALCdevice *device); -void ALCdevice_Unlock(ALCdevice *device); - -void ALCcontext_DeferUpdates(ALCcontext *context); -void ALCcontext_ProcessUpdates(ALCcontext *context); - extern ALint RTPrioLevel; void SetRTPriority(void); -- cgit v1.2.3 From 4db1328bc58602619e12f67cb0b31e8785662ed2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Jan 2018 03:55:33 -0800 Subject: Move the FORCE_ALIGN macro to threads.h --- OpenAL32/Include/alMain.h | 10 ---------- common/threads.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 2fe7f71f..60a7daca 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -230,16 +230,6 @@ typedef ALuint64SOFT ALuint64; */ #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) -#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 - #ifdef HAVE_C99_VLA #define DECL_VLA(T, _name, _size) T _name[(_size)] #else diff --git a/common/threads.h b/common/threads.h index c2848ee7..87b8a6f5 100644 --- a/common/threads.h +++ b/common/threads.h @@ -3,6 +3,16 @@ #include +#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 + #ifdef __cplusplus extern "C" { #endif -- cgit v1.2.3 From 77910afe577458595a3fccd2487fcb567067be58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Jan 2018 11:34:23 -0800 Subject: Make NumAttrsForDevice do similar type checks as alcGetIntegerv --- Alc/ALc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index e70e83dd..dfebe02e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3104,7 +3104,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para static inline ALCsizei NumAttrsForDevice(ALCdevice *device) { if(device->Type == Capture) return 9; - if(device->Type == Loopback && device->FmtChans == DevFmtAmbi3D) + if(device->Type != Loopback) return 29; + if(device->FmtChans == DevFmtAmbi3D) return 35; return 29; } -- cgit v1.2.3 From c9edf7cf7827dbbdbd2d76087a280f6d8aff4126 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 02:03:13 -0800 Subject: Add a string function to copy a wide-char range --- Alc/alstring.h | 1 + Alc/helpers.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Alc/alstring.h b/Alc/alstring.h index a7513516..e10811da 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -43,6 +43,7 @@ void alstr_append_range(al_string *str, const al_string_char_type *from, const a /* Windows-only methods to deal with WideChar strings. */ void alstr_copy_wcstr(al_string *str, const wchar_t *from); void alstr_append_wcstr(al_string *str, const wchar_t *from); +void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to); void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); #endif diff --git a/Alc/helpers.c b/Alc/helpers.c index 5d39f3d8..ac0826f2 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -1149,6 +1149,17 @@ void alstr_append_wcstr(al_string *str, const wchar_t *from) } } +void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + { + VECTOR_RESIZE(*str, len, len+1); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL); + VECTOR_ELEM(*str, len) = 0; + } +} + void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) { int len; -- cgit v1.2.3 From 26043269e43f4f1096b2f4981ed5386ddf02db3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 02:59:21 -0800 Subject: Allow GetProcPath to return the filename also --- Alc/alconfig.c | 8 +++---- Alc/compat.h | 2 +- Alc/helpers.c | 74 ++++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/Alc/alconfig.c b/Alc/alconfig.c index 1115bf30..b1df7d14 100644 --- a/Alc/alconfig.c +++ b/Alc/alconfig.c @@ -366,9 +366,9 @@ static void LoadConfigFromFile(FILE *f) #ifdef _WIN32 void ReadALConfig(void) { + al_string ppath = AL_STRING_INIT_STATIC(); WCHAR buffer[PATH_MAX]; const WCHAR *str; - al_string ppath; FILE *f; if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) @@ -387,7 +387,7 @@ void ReadALConfig(void) alstr_reset(&filepath); } - ppath = GetProcPath(); + GetProcBinary(&ppath, NULL); if(!alstr_empty(ppath)) { alstr_append_cstr(&ppath, "\\alsoft.ini"); @@ -420,9 +420,9 @@ void ReadALConfig(void) #else void ReadALConfig(void) { + al_string ppath = AL_STRING_INIT_STATIC(); char buffer[PATH_MAX]; const char *str; - al_string ppath; FILE *f; str = "/etc/openal/alsoft.conf"; @@ -502,7 +502,7 @@ void ReadALConfig(void) } } - ppath = GetProcPath(); + GetProcBinary(&ppath, NULL); if(!alstr_empty(ppath)) { alstr_append_cstr(&ppath, "/alsoft.conf"); diff --git a/Alc/compat.h b/Alc/compat.h index 247ed05b..6cf2d0d2 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -38,7 +38,7 @@ struct FileMapping { struct FileMapping MapFileToMem(const char *fname); void UnmapFileMem(const struct FileMapping *mapping); -al_string GetProcPath(void); +void GetProcBinary(al_string *path, al_string *fname); #ifdef HAVE_DYNLOAD void *LoadLib(const char *name); diff --git a/Alc/helpers.c b/Alc/helpers.c index ac0826f2..77090d6e 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -390,9 +390,8 @@ static WCHAR *strrchrW(WCHAR *str, WCHAR ch) return ret; } -al_string GetProcPath(void) +void GetProcBinary(al_string *path, al_string *fname) { - al_string ret = AL_STRING_INIT_STATIC(); WCHAR *pathname, *sep; DWORD pathlen; DWORD len; @@ -409,23 +408,34 @@ al_string GetProcPath(void) { free(pathname); ERR("Failed to get process name: error %lu\n", GetLastError()); - return ret; + return; } pathname[len] = 0; - if((sep = strrchrW(pathname, '\\'))) + if((sep=strrchrW(pathname, '\\')) != NULL) + { + WCHAR *sep2 = strrchrW(sep+1, '/'); + if(sep2) sep = sep2; + } + else + sep = strrchrW(pathname, '/'); + + if(sep) + { + if(path) alstr_copy_wrange(path, pathname, sep); + if(fname) alstr_copy_wcstr(fname, sep+1); + } + else { - WCHAR *sep2 = strrchrW(pathname, '/'); - if(sep2) *sep2 = 0; - else *sep = 0; + if(path) alstr_clear(path); + if(fname) alstr_copy_wcstr(fname, pathname); } - else if((sep = strrchrW(pathname, '/'))) - *sep = 0; - alstr_copy_wcstr(&ret, pathname); free(pathname); - TRACE("Got: %s\n", alstr_get_cstr(ret)); - return ret; + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); } @@ -719,36 +729,36 @@ void UnmapFileMem(const struct FileMapping *mapping) #else -al_string GetProcPath(void) +void GetProcBinary(al_string *path, al_string *fname) { - al_string ret = AL_STRING_INIT_STATIC(); char *pathname, *sep; size_t pathlen; #ifdef __FreeBSD__ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; mib[3] = getpid(); - if (sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) { + if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) + { WARN("Failed to sysctl kern.proc.pathname.%d: %s\n", mib[3], strerror(errno)); - return ret; + return; } pathname = malloc(pathlen + 1); sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); pathname[pathlen] = 0; #else - const char *fname; + const char *selfname; ssize_t len; pathlen = 256; pathname = malloc(pathlen); - fname = "/proc/self/exe"; - len = readlink(fname, pathname, pathlen); + selfname = "/proc/self/exe"; + len = readlink(selfname, pathname, pathlen); if(len == -1 && errno == ENOENT) { - fname = "/proc/self/file"; - len = readlink(fname, pathname, pathlen); + selfname = "/proc/self/file"; + len = readlink(selfname, pathname, pathlen); } while(len > 0 && (size_t)len == pathlen) @@ -756,13 +766,13 @@ al_string GetProcPath(void) free(pathname); pathlen <<= 1; pathname = malloc(pathlen); - len = readlink(fname, pathname, pathlen); + len = readlink(selfname, pathname, pathlen); } if(len <= 0) { free(pathname); - WARN("Failed to readlink %s: %s\n", fname, strerror(errno)); - return ret; + WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); + return; } pathname[len] = 0; @@ -770,13 +780,21 @@ al_string GetProcPath(void) sep = strrchr(pathname, '/'); if(sep) - alstr_copy_range(&ret, pathname, sep); + { + if(path) alstr_copy_range(path, pathname, sep); + if(fname) alstr_copy_cstr(fname, sep+1); + } else - alstr_copy_cstr(&ret, pathname); + { + if(path) alstr_clear(path); + if(fname) alstr_copy_cstr(fname, pathname); + } free(pathname); - TRACE("Got: %s\n", alstr_get_cstr(ret)); - return ret; + if(path && fname) + TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname)); + else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path)); + else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname)); } -- cgit v1.2.3 From af8bbefcab1d7ff68dc9c9ce7bc0a0deffe39845 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 03:22:41 -0800 Subject: Support procfs on *BSD to get the process binary --- Alc/helpers.c | 79 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 77090d6e..2aded6c5 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -731,54 +731,65 @@ void UnmapFileMem(const struct FileMapping *mapping) void GetProcBinary(al_string *path, al_string *fname) { - char *pathname, *sep; + char *pathname = NULL; size_t pathlen; #ifdef __FreeBSD__ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; mib[3] = getpid(); if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) - { WARN("Failed to sysctl kern.proc.pathname.%d: %s\n", mib[3], strerror(errno)); - return; - } - - pathname = malloc(pathlen + 1); - sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); - pathname[pathlen] = 0; -#else - const char *selfname; - ssize_t len; - - pathlen = 256; - pathname = malloc(pathlen); - - selfname = "/proc/self/exe"; - len = readlink(selfname, pathname, pathlen); - if(len == -1 && errno == ENOENT) + else { - selfname = "/proc/self/file"; - len = readlink(selfname, pathname, pathlen); + pathname = malloc(pathlen + 1); + sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + pathname[pathlen] = 0; } - - while(len > 0 && (size_t)len == pathlen) +#endif + if(!pathname) { - free(pathname); - pathlen <<= 1; + const char *selfname; + ssize_t len; + + pathlen = 256; pathname = malloc(pathlen); + + selfname = "/proc/self/exe"; len = readlink(selfname, pathname, pathlen); - } - if(len <= 0) - { - free(pathname); - WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); - return; - } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/self/file"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/exe"; + len = readlink(selfname, pathname, pathlen); + } + if(len == -1 && errno == ENOENT) + { + selfname = "/proc/curproc/file"; + len = readlink(selfname, pathname, pathlen); + } - pathname[len] = 0; -#endif + while(len > 0 && (size_t)len == pathlen) + { + free(pathname); + pathlen <<= 1; + pathname = malloc(pathlen); + len = readlink(selfname, pathname, pathlen); + } + if(len <= 0) + { + free(pathname); + WARN("Failed to readlink %s: %s\n", selfname, strerror(errno)); + return; + } + + pathname[len] = 0; + } - sep = strrchr(pathname, '/'); + char *sep = strrchr(pathname, '/'); if(sep) { if(path) alstr_copy_range(path, pathname, sep); -- cgit v1.2.3 From 71ad3b17153e7cbf25c3c6c1fb04fedabf596ff6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 03:38:10 -0800 Subject: Use KERN_PROCARGS to get the process path+filename on FreeBSD --- Alc/helpers.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 2aded6c5..790484e9 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -735,14 +735,13 @@ void GetProcBinary(al_string *path, al_string *fname) size_t pathlen; #ifdef __FreeBSD__ - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; - mib[3] = getpid(); - if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) - WARN("Failed to sysctl kern.proc.pathname.%d: %s\n", mib[3], strerror(errno)); + int mib[4] = { CTL_KERN, KERN_PROCARGS, getpid() }; + if(sysctl(mib, 3, NULL, &pathlen, NULL, 0) == -1) + WARN("Failed to sysctl kern.procargs.%d: %s\n", mib[2], strerror(errno)); else { pathname = malloc(pathlen + 1); - sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); + sysctl(mib, 3, (void*)pathname, &pathlen, NULL, 0); pathname[pathlen] = 0; } #endif -- cgit v1.2.3 From bbc4ebecabc9417f92fbc9a185edf7360f1a8b6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 03:41:56 -0800 Subject: Use GetProcBinary to get the executable name for PulseAudio --- Alc/backends/pulseaudio.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 9f3c4762..3208bf26 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -334,18 +334,20 @@ static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) { const char *name = "OpenAL Soft"; - char path_name[PATH_MAX]; + al_string binname = AL_STRING_INIT_STATIC(); 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); + GetProcBinary(NULL, &binname); + if(!alstr_empty(binname)) + name = alstr_get_cstr(binname); context = pa_context_new(pa_threaded_mainloop_get_api(loop), name); if(!context) { ERR("pa_context_new() failed\n"); + alstr_reset(&binname); return NULL; } @@ -372,9 +374,10 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) if(!silent) ERR("Context did not connect: %s\n", pa_strerror(err)); pa_context_unref(context); - return NULL; + context = NULL; } + alstr_reset(&binname); return context; } -- cgit v1.2.3 From c031b3cc6a8bb1525b59a850d3d8c6e4541256ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 04:40:20 -0800 Subject: Avoid fixed-PATH_MAX-size buffers Windows still needs to use MAX_PATH in a couple places, but that macro's guaranteed there. --- Alc/alconfig.c | 88 +++++++++++++++++++++++++++++------------------ Alc/helpers.c | 27 ++++++++++++--- OpenAL32/Include/alMain.h | 8 ----- 3 files changed, 77 insertions(+), 46 deletions(-) diff --git a/Alc/alconfig.c b/Alc/alconfig.c index b1df7d14..5dbf59d2 100644 --- a/Alc/alconfig.c +++ b/Alc/alconfig.c @@ -367,7 +367,7 @@ static void LoadConfigFromFile(FILE *f) void ReadALConfig(void) { al_string ppath = AL_STRING_INIT_STATIC(); - WCHAR buffer[PATH_MAX]; + WCHAR buffer[MAX_PATH]; const WCHAR *str; FILE *f; @@ -420,8 +420,8 @@ void ReadALConfig(void) #else void ReadALConfig(void) { - al_string ppath = AL_STRING_INIT_STATIC(); - char buffer[PATH_MAX]; + al_string confpaths = AL_STRING_INIT_STATIC(); + al_string fname = AL_STRING_INIT_STATIC(); const char *str; FILE *f; @@ -437,45 +437,55 @@ void ReadALConfig(void) if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) str = "/etc/xdg"; - strncpy(buffer, str, sizeof(buffer)-1); - buffer[sizeof(buffer)-1] = 0; + alstr_copy_cstr(&confpaths, str); /* 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) + while(!alstr_empty(confpaths)) { - char *next = strrchr(buffer, ':'); - if(next) *(next++) = 0; - else next = buffer; + char *next = strrchr(alstr_get_cstr(confpaths), ':'); + if(next) + { + size_t len = next - alstr_get_cstr(confpaths); + alstr_copy_cstr(&fname, next+1); + VECTOR_RESIZE(confpaths, len, len+1); + VECTOR_ELEM(confpaths, len) = 0; + } + else + { + alstr_reset(&fname); + fname = confpaths; + AL_STRING_INIT(confpaths); + } - if(next[0] != '/') - WARN("Ignoring XDG config dir: %s\n", next); + if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/') + WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname)); else { - size_t len = strlen(next); - strncpy(next+len, "/alsoft.conf", buffer+sizeof(buffer)-next-len); - buffer[sizeof(buffer)-1] = 0; + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); - TRACE("Loading config %s...\n", next); - f = al_fopen(next, "r"); + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } - if(next == buffer) - break; + alstr_clear(&fname); } if((str=getenv("HOME")) != NULL && *str) { - snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str); + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc"); + else alstr_append_cstr(&fname, ".alsoftrc"); - TRACE("Loading config %s...\n", buffer); - f = al_fopen(buffer, "r"); + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); @@ -484,17 +494,25 @@ void ReadALConfig(void) } if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0) - snprintf(buffer, sizeof(buffer), "%s/%s", str, "alsoft.conf"); + { + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); + } else { - buffer[0] = 0; + alstr_clear(&fname); if((str=getenv("HOME")) != NULL && str[0] != 0) - snprintf(buffer, sizeof(buffer), "%s/.config/%s", str, "alsoft.conf"); + { + alstr_copy_cstr(&fname, str); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf"); + else alstr_append_cstr(&fname, ".config/alsoft.conf"); + } } - if(buffer[0] != 0) + if(!alstr_empty(fname)) { - TRACE("Loading config %s...\n", buffer); - f = al_fopen(buffer, "r"); + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); @@ -502,12 +520,15 @@ void ReadALConfig(void) } } - GetProcBinary(&ppath, NULL); - if(!alstr_empty(ppath)) + alstr_clear(&fname); + GetProcBinary(&fname, NULL); + if(!alstr_empty(fname)) { - alstr_append_cstr(&ppath, "/alsoft.conf"); - TRACE("Loading config %s...\n", alstr_get_cstr(ppath)); - f = al_fopen(alstr_get_cstr(ppath), "r"); + if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); + else alstr_append_cstr(&fname, "alsoft.conf"); + + TRACE("Loading config %s...\n", alstr_get_cstr(fname)); + f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); @@ -526,7 +547,8 @@ void ReadALConfig(void) } } - alstr_reset(&ppath); + alstr_reset(&fname); + alstr_reset(&confpaths); } #endif diff --git a/Alc/helpers.c b/Alc/helpers.c index 790484e9..96f9b681 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -642,7 +642,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) /* Search the local and global data dirs. */ for(i = 0;i < COUNTOF(ids);i++) { - WCHAR buffer[PATH_MAX]; + WCHAR buffer[MAX_PATH]; if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) { alstr_copy_wcstr(&path, buffer); @@ -907,15 +907,32 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir) { al_string path = AL_STRING_INIT_STATIC(); const char *str, *next; - char cwdbuf[PATH_MAX]; /* Search the app-local directory. */ if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') DirectorySearch(str, ext, &results); - else if(getcwd(cwdbuf, sizeof(cwdbuf))) - DirectorySearch(cwdbuf, ext, &results); else - DirectorySearch(".", ext, &results); + { + size_t cwdlen = 256; + char *cwdbuf = malloc(cwdlen); + while(!getcwd(cwdbuf, cwdlen)) + { + free(cwdbuf); + cwdbuf = NULL; + if(errno != ERANGE) + break; + cwdlen <<= 1; + cwdbuf = malloc(cwdlen); + } + if(!cwdbuf) + DirectorySearch(".", ext, &results); + else + { + DirectorySearch(cwdbuf, ext, &results); + free(cwdbuf); + cwdbuf = NULL; + } + } // Search local data dir if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 60a7daca..e4f5df74 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -236,14 +236,6 @@ typedef ALuint64SOFT ALuint64; #define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T)) #endif -#ifndef PATH_MAX -#ifdef MAX_PATH -#define PATH_MAX MAX_PATH -#else -#define PATH_MAX 4096 -#endif -#endif - static const union { ALuint u; -- cgit v1.2.3 From 16e4e0fa7c97d8b7273e590adc9432f317f93d57 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 08:07:03 -0800 Subject: Use a more normal vtable setup for filter methods --- OpenAL32/Include/alFilter.h | 42 ++++++------ OpenAL32/alFilter.c | 152 +++++++++++++++++--------------------------- 2 files changed, 81 insertions(+), 113 deletions(-) diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 227d50cf..e0046d86 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -107,6 +107,28 @@ inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat * } +struct ALfilter; + +typedef struct ALfilterVtable { + void (*const setParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*const setParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*const setParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*const setParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*const getParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*const getParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*const getParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*const getParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); +} ALfilterVtable; + +#define DEFINE_ALFILTER_VTABLE(T) \ +const struct ALfilterVtable T##_vtable = { \ + T##_setParami, T##_setParamiv, \ + T##_setParamf, T##_setParamfv, \ + T##_getParami, T##_getParamiv, \ + T##_getParamf, T##_getParamfv, \ +} + typedef struct ALfilter { // Filter type (AL_FILTER_NULL, ...) ALenum type; @@ -117,30 +139,12 @@ typedef struct ALfilter { ALfloat GainLF; ALfloat LFReference; - void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); + const struct ALfilterVtable *vtbl; /* Self ID */ ALuint id; } ALfilter; -#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v))) -#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v))) -#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v))) -#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v))) - -#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v))) -#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v))) -#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 void LockFiltersRead(ALCdevice *device) { LockUIntMapRead(&device->FilterMap); } inline void UnlockFiltersRead(ALCdevice *device) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 2a2b9621..6e07d41b 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -166,7 +166,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) else { /* Call the appropriate handler */ - ALfilter_SetParami(ALFilter, Context, param, value); + V(ALFilter,setParami)(Context, param, value); } } UnlockFiltersWrite(Device); @@ -197,7 +197,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v else { /* Call the appropriate handler */ - ALfilter_SetParamiv(ALFilter, Context, param, values); + V(ALFilter,setParamiv)(Context, param, values); } UnlockFiltersWrite(Device); @@ -220,7 +220,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) else { /* Call the appropriate handler */ - ALfilter_SetParamf(ALFilter, Context, param, value); + V(ALFilter,setParamf)(Context, param, value); } UnlockFiltersWrite(Device); @@ -243,7 +243,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat else { /* Call the appropriate handler */ - ALfilter_SetParamfv(ALFilter, Context, param, values); + V(ALFilter,setParamfv)(Context, param, values); } UnlockFiltersWrite(Device); @@ -270,7 +270,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value else { /* Call the appropriate handler */ - ALfilter_GetParami(ALFilter, Context, param, value); + V(ALFilter,getParami)(Context, param, value); } } UnlockFiltersRead(Device); @@ -301,7 +301,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu else { /* Call the appropriate handler */ - ALfilter_GetParamiv(ALFilter, Context, param, values); + V(ALFilter,getParamiv)(Context, param, values); } UnlockFiltersRead(Device); @@ -324,7 +324,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val else { /* Call the appropriate handler */ - ALfilter_GetParamf(ALFilter, Context, param, value); + V(ALFilter,getParamf)(Context, param, value); } UnlockFiltersRead(Device); @@ -347,7 +347,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va else { /* Call the appropriate handler */ - ALfilter_GetParamfv(ALFilter, Context, param, values); + V(ALFilter,getParamfv)(Context, param, values); } UnlockFiltersRead(Device); @@ -435,11 +435,11 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g } -static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +static void ALlowpass_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)) +static void ALlowpass_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) +static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -459,16 +459,14 @@ static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - lp_SetParamf(filter, context, param, vals[0]); -} +static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALlowpass_setParamf(filter, context, param, vals[0]); } -static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +static void ALlowpass_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)) +static void ALlowpass_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) +static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -484,17 +482,17 @@ static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ - lp_GetParamf(filter, context, param, vals); -} +static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALlowpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALlowpass); -static void hp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void hp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -514,16 +512,14 @@ static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void hp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - hp_SetParamf(filter, context, param, vals[0]); -} +static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALhighpass_setParamf(filter, context, param, vals[0]); } -static void hp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void hp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -539,17 +535,17 @@ static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void hp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ - hp_GetParamf(filter, context, param, vals); -} +static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALhighpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALhighpass); -static void bp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void bp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { @@ -575,16 +571,14 @@ static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void bp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - bp_SetParamf(filter, context, param, vals[0]); -} +static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ ALbandpass_setParamf(filter, context, param, vals[0]); } -static void bp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void bp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) { @@ -604,30 +598,32 @@ static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, AL SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } } -static void bp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) -{ - bp_GetParamf(filter, context, param, vals); -} +static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ ALbandpass_getParamf(filter, context, param, vals); } + +DEFINE_ALFILTER_VTABLE(ALbandpass); -static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_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)) +static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +DEFINE_ALFILTER_VTABLE(ALnullfilter); + ALvoid ReleaseALFilters(ALCdevice *device) { @@ -654,15 +650,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = 1.0f; filter->LFReference = HIGHPASSFREQREF; - - filter->SetParami = lp_SetParami; - filter->SetParamiv = lp_SetParamiv; - filter->SetParamf = lp_SetParamf; - filter->SetParamfv = lp_SetParamfv; - filter->GetParami = lp_GetParami; - filter->GetParamiv = lp_GetParamiv; - filter->GetParamf = lp_GetParamf; - filter->GetParamfv = lp_GetParamfv; + filter->vtbl = &ALlowpass_vtable; } else if(type == AL_FILTER_HIGHPASS) { @@ -671,15 +659,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; filter->LFReference = HIGHPASSFREQREF; - - filter->SetParami = hp_SetParami; - filter->SetParamiv = hp_SetParamiv; - filter->SetParamf = hp_SetParamf; - filter->SetParamfv = hp_SetParamfv; - filter->GetParami = hp_GetParami; - filter->GetParamiv = hp_GetParamiv; - filter->GetParamf = hp_GetParamf; - filter->GetParamfv = hp_GetParamfv; + filter->vtbl = &ALhighpass_vtable; } else if(type == AL_FILTER_BANDPASS) { @@ -688,15 +668,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; filter->LFReference = HIGHPASSFREQREF; - - filter->SetParami = bp_SetParami; - filter->SetParamiv = bp_SetParamiv; - filter->SetParamf = bp_SetParamf; - filter->SetParamfv = bp_SetParamfv; - filter->GetParami = bp_GetParami; - filter->GetParamiv = bp_GetParamiv; - filter->GetParamf = bp_GetParamf; - filter->GetParamfv = bp_GetParamfv; + filter->vtbl = &ALbandpass_vtable; } else { @@ -705,15 +677,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = 1.0f; filter->LFReference = HIGHPASSFREQREF; - - filter->SetParami = null_SetParami; - filter->SetParamiv = null_SetParamiv; - filter->SetParamf = null_SetParamf; - filter->SetParamfv = null_SetParamfv; - filter->GetParami = null_GetParami; - filter->GetParamiv = null_GetParamiv; - filter->GetParamf = null_GetParamf; - filter->GetParamfv = null_GetParamfv; + filter->vtbl = &ALnullfilter_vtable; } filter->type = type; } -- cgit v1.2.3 From 78cb70a5f9f2782e1335aea03168ffee2fea0122 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 09:14:46 -0800 Subject: Replace some freq_mult variable names with f0norm The latter is a bit more descriptive as f0 is often used to denote the reference frequency of a filter, so f0norm indicates the normalized reference frequency (ref_freq / sample_rate). --- Alc/bformatdec.c | 8 ++++---- Alc/bformatdec.h | 4 ++-- Alc/effects/equalizer.c | 22 +++++++++++----------- Alc/effects/reverb.c | 12 ++++++------ OpenAL32/Include/alFilter.h | 36 +++++++++++++++++++++++++++--------- OpenAL32/alFilter.c | 6 +++--- 6 files changed, 53 insertions(+), 35 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 6503ac65..2c5326d4 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -11,9 +11,9 @@ #include "almalloc.h" -void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult) +void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) { - ALfloat w = freq_mult * F_TAU; + ALfloat w = f0norm * F_TAU; ALfloat cw = cosf(w); if(cw > FLT_EPSILON) splitter->coeff = (sinf(w) - 1.0f) / cw; @@ -75,9 +75,9 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat } -void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult) +void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) { - ALfloat w = freq_mult * F_TAU; + ALfloat w = f0norm * F_TAU; ALfloat cw = cosf(w); if(cw > FLT_EPSILON) splitter->coeff = (sinf(w) - 1.0f) / cw; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index baaecf40..b017cfd3 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -55,7 +55,7 @@ typedef struct BandSplitter { ALfloat hp_z1; } BandSplitter; -void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult); +void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); void bandsplit_clear(BandSplitter *splitter); void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, const ALfloat *input, ALsizei count); @@ -68,7 +68,7 @@ typedef struct SplitterAllpass { ALfloat z1; } SplitterAllpass; -void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult); +void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); void splitterap_clear(SplitterAllpass *splitter); void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 7df15380..bc84f87f 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -125,7 +125,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext { const ALCdevice *device = context->Device; ALfloat frequency = (ALfloat)device->Frequency; - ALfloat gain, freq_mult; + ALfloat gain, f0norm; ALuint i; STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; @@ -139,31 +139,31 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext * of the transition band. */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ - freq_mult = props->Equalizer.LowCutoff/frequency; + f0norm = props->Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->Chans[0].filter[0], ALfilterType_LowShelf, - gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); - freq_mult = props->Equalizer.Mid1Center/frequency; + f0norm = props->Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->Chans[0].filter[1], ALfilterType_Peaking, - gain, freq_mult, calc_rcpQ_from_bandwidth( - freq_mult, props->Equalizer.Mid1Width + gain, f0norm, calc_rcpQ_from_bandwidth( + f0norm, props->Equalizer.Mid1Width ) ); gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); - freq_mult = props->Equalizer.Mid2Center/frequency; + f0norm = props->Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->Chans[0].filter[2], ALfilterType_Peaking, - gain, freq_mult, calc_rcpQ_from_bandwidth( - freq_mult, props->Equalizer.Mid2Width + gain, f0norm, calc_rcpQ_from_bandwidth( + f0norm, props->Equalizer.Mid2Width ) ); gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); - freq_mult = props->Equalizer.HighCutoff/frequency; + f0norm = props->Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->Chans[0].filter[3], ALfilterType_HighShelf, - gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f6cd2b04..49362e2a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1281,23 +1281,23 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte const ALCdevice *Device = Context->Device; const ALlistener *Listener = Context->Listener; ALuint frequency = Device->Frequency; - ALfloat lfScale, hfScale, hfRatio; + ALfloat lf0norm, hf0norm, hfRatio; ALfloat lfDecayTime, hfDecayTime; ALfloat gain, gainlf, gainhf; ALsizei i; /* Calculate the master filters */ - hfScale = props->Reverb.HFReference / frequency; + hf0norm = props->Reverb.HFReference / frequency; /* Restrict the filter gains from going below -60dB to keep the filter from * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, - gainhf, hfScale, calc_rcpQ_from_slope(gainhf, 1.0f)); - lfScale = props->Reverb.LFReference / frequency; + gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); + lf0norm = props->Reverb.LFReference / frequency; gainlf = maxf(props->Reverb.GainLF, 0.001f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, - gainlf, lfScale, calc_rcpQ_from_slope(gainlf, 1.0f)); + gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < 4;i++) { ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); @@ -1341,7 +1341,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, - F_TAU * lfScale, F_TAU * hfScale, + F_TAU * lf0norm, F_TAU * hf0norm, props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, State); diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index e0046d86..c1932e2e 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -48,22 +48,25 @@ typedef struct ALfilterState { /* Currently only a C-based filter process method is implemented. */ #define ALfilterState_process ALfilterState_processC -/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the * reference gain and shelf slope parameter. - * 0 < gain - * 0 < slope <= 1 + * \param gain 0 < gain + * \param slope 0 < slope <= 1 */ inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) { return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); } -/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency - * multiple (i.e. ref_freq / sampling_freq) and bandwidth. - * 0 < freq_mult < 0.5. +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized + * reference frequency and bandwidth. + * \param f0norm 0 < f0norm < 0.5. + * \param bandwidth 0 < bandwidth */ -inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth) +inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) { - ALfloat w0 = F_TAU * freq_mult; + ALfloat w0 = F_TAU * f0norm; return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); } @@ -75,7 +78,22 @@ inline void ALfilterState_clear(ALfilterState *filter) filter->y[1] = 0.0f; } -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); +/** + * Sets up the filter state for the specified filter type and its parameters. + * + * \param filter The filter object to prepare. + * \param type The type of filter for the object to apply. + * \param gain The gain for the reference frequency response. Only used by the + * Shelf and Peaking filter types. + * \param f0norm The normalized reference frequency (ref_freq / sample_rate). + * This is the center point for the Shelf, Peaking, and BandPass + * filter types, or the cutoff frequency for the LowPass and + * HighPass filter types. + * \param rcpQ The reciprocal of the Q coefficient for the filter's transition + * band. Can be generated from calc_rcpQ_from_slope or + * calc_rcpQ_from_bandwidth depending on the available data. + */ +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src) { diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 6e07d41b..4771414a 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -39,7 +39,7 @@ extern inline void ALfilterState_clear(ALfilterState *filter); extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); -extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); +extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); static void InitFilterParams(ALfilter *filter, ALenum type); @@ -355,7 +355,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va } -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ) +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) { ALfloat alpha, sqrtgain_alpha_2; ALfloat w0, sin_w0, cos_w0; @@ -365,7 +365,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g // Limit gain to -100dB assert(gain > 0.00001f); - w0 = F_TAU * freq_mult; + w0 = F_TAU * f0norm; sin_w0 = sinf(w0); cos_w0 = cosf(w0); alpha = sin_w0/2.0f * rcpQ; -- cgit v1.2.3 From 2b968766b9610cab51721e77e6402ce2652416b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Jan 2018 09:58:47 -0800 Subject: Pre-apply the T60 filter midgain to the HF filter coeffs --- Alc/effects/reverb.c | 68 +++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 49362e2a..eb0d0684 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -319,7 +319,6 @@ typedef struct ALreverbState { struct { ALfloat LFCoeffs[3]; ALfloat HFCoeffs[3]; - ALfloat MidCoeff; /* The LF and HF filters keep a state of the last input and last * output sample. */ @@ -431,8 +430,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Filters[i].LFCoeffs[j] = 0.0f; state->Late.Filters[i].HFCoeffs[j] = 0.0f; } - state->Late.Filters[i].MidCoeff = 0.0f; - state->Late.Filters[i].States[0][0] = 0.0f; state->Late.Filters[i].States[0][1] = 0.0f; state->Late.Filters[i].States[1][0] = 0.0f; @@ -924,7 +921,7 @@ static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfl static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, ALfloat lfcoeffs[3], - ALfloat hfcoeffs[3], ALfloat *midcoeff) + ALfloat hfcoeffs[3]) { ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); @@ -932,51 +929,46 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime if(lfGain < mfGain) { + CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs); if(mfGain < hfGain) { - CalcLowShelfCoeffs(mfGain / hfGain, hfW, lfcoeffs); - CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs); - *midcoeff = hfGain; + CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); + hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; } else if(mfGain > hfGain) { - CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs); CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - *midcoeff = mfGain; + hfcoeffs[0] *= mfGain; hfcoeffs[1] *= mfGain; } else { - lfcoeffs[0] = 1.0f; - lfcoeffs[1] = 0.0f; - lfcoeffs[2] = 0.0f; - CalcHighpassCoeffs(lfGain / mfGain, lfW, hfcoeffs); - *midcoeff = mfGain; + hfcoeffs[0] = mfGain; + hfcoeffs[1] = 0.0f; + hfcoeffs[2] = 0.0f; } } else if(lfGain > mfGain) { + CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs); if(mfGain < hfGain) { ALfloat hg = mfGain / lfGain; ALfloat lg = mfGain / hfGain; + ALfloat mg = maxf(lfGain, hfGain) / maxf(hg, lg); - CalcHighShelfCoeffs(hg, lfW, lfcoeffs); CalcLowShelfCoeffs(lg, hfW, hfcoeffs); - *midcoeff = maxf(lfGain, hfGain) / maxf(hg, lg); + hfcoeffs[0] *= mg; hfcoeffs[1] *= mg; } else if(mfGain > hfGain) { - CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs); CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - *midcoeff = lfGain; + hfcoeffs[0] *= lfGain; hfcoeffs[1] *= lfGain; } else { - lfcoeffs[0] = 1.0f; - lfcoeffs[1] = 0.0f; - lfcoeffs[2] = 0.0f; - CalcHighShelfCoeffs(mfGain / lfGain, lfW, hfcoeffs); - *midcoeff = lfGain; + hfcoeffs[0] = lfGain; + hfcoeffs[1] = 0.0f; + hfcoeffs[2] = 0.0f; } } else @@ -988,19 +980,18 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime if(mfGain < hfGain) { CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); - *midcoeff = hfGain; + hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; } else if(mfGain > hfGain) { CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - *midcoeff = mfGain; + hfcoeffs[0] *= mfGain; hfcoeffs[1] *= mfGain; } else { - hfcoeffs[3] = 1.0f; - hfcoeffs[4] = 0.0f; - hfcoeffs[5] = 0.0f; - *midcoeff = mfGain; + hfcoeffs[0] = mfGain; + hfcoeffs[1] = 0.0f; + hfcoeffs[2] = 0.0f; } } } @@ -1162,8 +1153,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the T60 damping coefficients for each line. */ CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, lfW, hfW, State->Late.Filters[i].LFCoeffs, - State->Late.Filters[i].HFCoeffs, - &State->Late.Filters[i].MidCoeff); + State->Late.Filters[i].HFCoeffs); } } @@ -1386,7 +1376,8 @@ static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, const ALsizei off1, const ALsizei c, const ALfloat mu) { - return lerp(Delay->Line[off0&Delay->Mask][c], Delay->Line[off1&Delay->Mask][c], mu); + return Delay->Line[off0&Delay->Mask][c]*(1.0f-mu) + + Delay->Line[off1&Delay->Mask][c]*( mu); } #define UnfadedDelayLineOut(d, o0, o1, c, mu) DelayLineOut(d, o0, c) @@ -1615,12 +1606,13 @@ static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat coeffs[3] /* Applies the two T60 damping filter sections. */ static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALreverbState *State) { - ALfloat out = FirstOrderFilter(in, State->Late.Filters[index].LFCoeffs, - State->Late.Filters[index].States[0]); - - return State->Late.Filters[index].MidCoeff * - FirstOrderFilter(out, State->Late.Filters[index].HFCoeffs, - State->Late.Filters[index].States[1]); + return FirstOrderFilter( + FirstOrderFilter( + in, State->Late.Filters[index].LFCoeffs, + State->Late.Filters[index].States[0] + ), State->Late.Filters[index].HFCoeffs, + State->Late.Filters[index].States[1] + ); } /* This generates the reverb tail using a modified feed-back delay network -- cgit v1.2.3 From 2957d859243176cf41a810b9164b921eac9e6534 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 05:16:19 -0800 Subject: Only pass the needed parameters to LateT60Filter --- Alc/effects/reverb.c | 49 +++++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index eb0d0684..472037ba 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -217,17 +217,6 @@ static const ALfloat LATE_LINE_LENGTHS[4] = static const ALfloat MODULATION_DEPTH_COEFF = 0.0032f; -/* Prior to VS2013, MSVC lacks the round() family of functions. */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -static inline long lroundf(float val) -{ - if(val < 0.0) - return fastf2i(ceilf(val-0.5f)); - return fastf2i(floorf(val+0.5f)); -} -#endif - - typedef struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers * of 2 to allow the use of bit-masking instead of a modulus for wrapping. @@ -317,10 +306,10 @@ typedef struct ALreverbState { /* T60 decay filters are used to simulate absorption. */ struct { - ALfloat LFCoeffs[3]; ALfloat HFCoeffs[3]; - /* The LF and HF filters keep a state of the last input and last - * output sample. + ALfloat LFCoeffs[3]; + /* The HF and LF filters each keep a state of the last input and + * last output sample. */ ALfloat States[2][2]; } Filters[4]; @@ -427,8 +416,8 @@ static void ALreverbState_Construct(ALreverbState *state) for(j = 0;j < 3;j++) { - state->Late.Filters[i].LFCoeffs[j] = 0.0f; state->Late.Filters[i].HFCoeffs[j] = 0.0f; + state->Late.Filters[i].LFCoeffs[j] = 0.0f; } state->Late.Filters[i].States[0][0] = 0.0f; state->Late.Filters[i].States[0][1] = 0.0f; @@ -1593,25 +1582,23 @@ DECL_TEMPLATE(Faded) #undef DECL_TEMPLATE /* Applies a first order filter section. */ -static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat coeffs[3], ALfloat state[2]) +static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict coeffs, + ALfloat *restrict state) { ALfloat out = coeffs[0]*in + coeffs[1]*state[0] + coeffs[2]*state[1]; - state[0] = in; state[1] = out; - return out; } /* Applies the two T60 damping filter sections. */ -static inline ALfloat LateT60Filter(const ALsizei index, const ALfloat in, ALreverbState *State) +static inline ALfloat LateT60Filter(const ALfloat *restrict HFCoeffs, ALfloat *restrict HFState, + const ALfloat *restrict LFCoeffs, ALfloat *restrict LFState, + const ALfloat in) { return FirstOrderFilter( - FirstOrderFilter( - in, State->Late.Filters[index].LFCoeffs, - State->Late.Filters[index].States[0] - ), State->Late.Filters[index].HFCoeffs, - State->Late.Filters[index].States[1] + FirstOrderFilter(in, HFCoeffs, HFState), + LFCoeffs, LFState ); } @@ -1659,8 +1646,11 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat ); for(j = 0;j < 4;j++) - f[j] = LateT60Filter(j, f[j], State); - + f[j] = LateT60Filter( + State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], + State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], + f[j] + ); VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); @@ -1702,8 +1692,11 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo offset - State->Late.Offset[j][0], j); for(j = 0;j < 4;j++) - f[j] = LateT60Filter(j, f[j], State); - + f[j] = LateT60Filter( + State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], + State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], + f[j] + ); VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); -- cgit v1.2.3 From 7a77a20a6727ccf17408ff91d619191f038ff1f6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 07:25:02 -0800 Subject: Use a macro for the number of reverb lines --- Alc/effects/reverb.c | 168 ++++++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 82 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 472037ba..b4961ce8 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -49,6 +49,13 @@ ALfloat ReverbBoost = 1.0f; */ #define FADE_SAMPLES 128 +/* The number of spatialized lines or channels to process. Four channels allows + * for a 3D A-Format response. NOTE: This can't be changed without taking care + * of the conversion matrices, and a few places where the length arrays are + * assumed to have 4 elements. + */ +#define NUM_LINES 4 + static RowMixerFunc MixRowSamples = MixRow_C; @@ -137,7 +144,7 @@ static const ALfloat LINE_MULTIPLIER = 9.0f; * Assuming an average of 5m (up to 50m with the density multiplier), we get * the following taps: */ -static const ALfloat EARLY_TAP_LENGTHS[4] = +static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = { 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f }; @@ -148,7 +155,7 @@ static const ALfloat EARLY_TAP_LENGTHS[4] = * * Where a is the approximate maximum all-pass cycle limit (20). */ -static const ALfloat EARLY_ALLPASS_LENGTHS[4] = +static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = { 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f }; @@ -175,7 +182,7 @@ static const ALfloat EARLY_ALLPASS_LENGTHS[4] = * * Using an average dimension of 5m, we get: */ -static const ALfloat EARLY_LINE_LENGTHS[4] = +static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = { 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f }; @@ -184,7 +191,7 @@ static const ALfloat EARLY_LINE_LENGTHS[4] = * * A_i = (5 / 3) L_i / r_1 */ -static const ALfloat LATE_ALLPASS_LENGTHS[4] = +static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = { 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f }; @@ -204,7 +211,7 @@ static const ALfloat LATE_ALLPASS_LENGTHS[4] = * * For our 5m average room, we get: */ -static const ALfloat LATE_LINE_LENGTHS[4] = +static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = { 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f }; @@ -222,12 +229,12 @@ typedef struct DelayLineI { * of 2 to allow the use of bit-masking instead of a modulus for wrapping. */ ALsizei Mask; - ALfloat (*Line)[4]; + ALfloat (*Line)[NUM_LINES]; } DelayLineI; typedef struct VecAllpass { DelayLineI Delay; - ALsizei Offset[4][2]; + ALsizei Offset[NUM_LINES][2]; } VecAllpass; typedef struct ALreverbState { @@ -243,18 +250,18 @@ typedef struct ALreverbState { struct { ALfilterState Lp; ALfilterState Hp; /* EAX only */ - } Filter[4]; + } Filter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ DelayLineI Delay; /* Tap points for early reflection delay. */ - ALsizei EarlyDelayTap[4][2]; - ALfloat EarlyDelayCoeff[4]; + ALsizei EarlyDelayTap[NUM_LINES][2]; + ALfloat EarlyDelayCoeff[NUM_LINES]; /* Tap points for late reverb feed and delay. */ ALsizei LateFeedTap; - ALsizei LateDelayTap[4][2]; + ALsizei LateDelayTap[NUM_LINES][2]; /* The feed-back and feed-forward all-pass coefficient. */ ALfloat ApFeedCoeff; @@ -274,12 +281,12 @@ typedef struct ALreverbState { * reflections. */ DelayLineI Delay; - ALsizei Offset[4][2]; - ALfloat Coeff[4]; + ALsizei Offset[NUM_LINES][2]; + ALfloat Coeff[NUM_LINES]; /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; } Early; struct { @@ -302,7 +309,7 @@ typedef struct ALreverbState { /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; - ALsizei Offset[4][2]; + ALsizei Offset[NUM_LINES][2]; /* T60 decay filters are used to simulate absorption. */ struct { @@ -312,7 +319,7 @@ typedef struct ALreverbState { * last output sample. */ ALfloat States[2][2]; - } Filters[4]; + } Filters[NUM_LINES]; /* A Gerzon vector all-pass filter is used to simulate diffusion. */ VecAllpass VecAp; @@ -329,10 +336,10 @@ typedef struct ALreverbState { ALsizei Offset; /* Temporary storage used when processing. */ - alignas(16) ALsizei ModulationDelays[4][MAX_UPDATE_SAMPLES][2]; - alignas(16) ALfloat AFormatSamples[4][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat ReverbSamples[4][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat EarlySamples[4][MAX_UPDATE_SAMPLES]; + alignas(16) ALsizei ModulationDelays[NUM_LINES][MAX_UPDATE_SAMPLES][2]; + alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat ReverbSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat EarlySamples[NUM_LINES][MAX_UPDATE_SAMPLES]; } ALreverbState; static ALvoid ALreverbState_Destruct(ALreverbState *State); @@ -353,7 +360,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->TotalSamples = 0; state->SampleBuffer = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { ALfilterState_clear(&state->Filter[i].Lp); ALfilterState_clear(&state->Filter[i].Hp); @@ -362,7 +369,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Delay.Mask = 0; state->Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->EarlyDelayTap[i][0] = 0; state->EarlyDelayTap[i][1] = 0; @@ -371,7 +378,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->LateFeedTap = 0; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->LateDelayTap[i][0] = 0; state->LateDelayTap[i][1] = 0; @@ -385,7 +392,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.VecAp.Delay.Line = NULL; state->Early.Delay.Mask = 0; state->Early.Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->Early.VecAp.Offset[i][0] = 0; state->Early.VecAp.Offset[i][1] = 0; @@ -406,7 +413,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; state->Late.VecAp.Delay.Line = NULL; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; @@ -425,7 +432,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Filters[i].States[1][1] = 0.0f; } - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) { @@ -459,9 +466,9 @@ static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLineI *Delay) { union { ALfloat *f; - ALfloat (*f4)[4]; + ALfloat (*f4)[NUM_LINES]; } u; - u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * 4]; + u.f = &sampleBuffer[(ptrdiff_t)Delay->Line * NUM_LINES]; Delay->Line = u.f4; } @@ -479,7 +486,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const /* All lines share a single sample buffer. */ Delay->Mask = samples - 1; - Delay->Line = (ALfloat(*)[4])offset; + Delay->Line = (ALfloat(*)[NUM_LINES])offset; /* Return the sample count for accumulation. */ return samples; @@ -509,35 +516,34 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) * largest late tap width. Finally, it must also be extended by the * update size (MAX_UPDATE_SAMPLES) for block processing. */ - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[3]*multiplier + + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier + AL_EAXREVERB_MAX_LATE_REVERB_DELAY + - (LATE_LINE_LENGTHS[3] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; + (LATE_LINE_LENGTHS[NUM_LINES-1] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Delay); /* The early vector all-pass line. */ - length = EARLY_ALLPASS_LENGTHS[3] * multiplier; + length = EARLY_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.VecAp.Delay); /* The early reflection line. */ - length = EARLY_LINE_LENGTHS[3] * multiplier; + length = EARLY_LINE_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Early.Delay); /* The late vector all-pass line. */ - length = LATE_ALLPASS_LENGTHS[3] * multiplier; + length = LATE_ALLPASS_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.VecAp.Delay); /* The late delay lines are calculated from the larger of the maximum * density line length or the maximum echo time, and includes the maximum * modulation-related delay. The modulator's delay is calculated from the - * maximum modulation time and depth coefficient, and halved for the low- - * to-high frequency swing. + * depth coefficient. */ - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[3]*multiplier) + - AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f; + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[NUM_LINES-1]*multiplier) + + MODULATION_DEPTH_COEFF; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay); @@ -546,7 +552,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) ALfloat *newBuffer; TRACE("New reverb buffer length: %ux4 samples\n", totalSamples); - newBuffer = al_calloc(16, sizeof(ALfloat[4]) * totalSamples); + newBuffer = al_calloc(16, sizeof(ALfloat[NUM_LINES]) * totalSamples); if(!newBuffer) return AL_FALSE; al_free(State->SampleBuffer); @@ -581,7 +587,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev /* The late feed taps are set a fixed position past the latest delay tap. */ State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[3]*multiplier) * + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * frequency); return AL_TRUE; @@ -1038,7 +1044,7 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, * delay path and offsets that would continue the propagation naturally * into the late lines. */ - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; State->EarlyDelayTap[i][1] = fastf2i(length * frequency); @@ -1059,7 +1065,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c multiplier = 1.0f + density*LINE_MULTIPLIER; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = EARLY_ALLPASS_LENGTHS[i] * multiplier; @@ -1112,7 +1118,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co bandWeights[2]*hfDecayTime) / F_TAU) ); - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ length = LATE_ALLPASS_LENGTHS[i] * multiplier; @@ -1277,7 +1283,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte gainlf = maxf(props->Reverb.GainLF, 0.001f); ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); - for(i = 1;i < 4;i++) + for(i = 1;i < NUM_LINES;i++) { ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); @@ -1332,7 +1338,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.LateReverbGain, State); /* Determine if delay-line cross-fading is required. */ - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) { if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) || (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) || @@ -1375,20 +1381,20 @@ static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const Delay->Line[offset&Delay->Mask][c] = in; } -static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) { ALsizei i; offset &= Delay->Mask; - for(i = 0;i < 4;i++) + for(i = 0;i < NUM_LINES;i++) Delay->Line[offset][i] = in[i]; } -static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[4]) +static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) { ALsizei i; offset &= Delay->Mask; - for(i = 0;i < 4;i++) - Delay->Line[offset][i] = in[3-i]; + for(i = 0;i < NUM_LINES;i++) + Delay->Line[offset][i] = in[NUM_LINES-1-i]; } static void CalcModulationDelays(ALreverbState *State, @@ -1399,7 +1405,7 @@ static void CalcModulationDelays(ALreverbState *State, ALsizei index, c, i; ALfloat sinus; - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) { ALsizei offset0 = offsets[c][0] << FRACTIONBITS; ALsizei offset1 = offsets[c][1] << FRACTIONBITS; @@ -1483,13 +1489,13 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ const ALfloat yCoeff, const ALfloat mu, \ VecAllpass *Vap) \ { \ - ALfloat f[4], fs[4]; \ + ALfloat f[NUM_LINES], fs[NUM_LINES]; \ ALfloat input; \ ALsizei i; \ \ (void)mu; /* Ignore for Unfaded. */ \ \ - for(i = 0;i < 4;i++) \ + for(i = 0;i < NUM_LINES;i++) \ { \ input = vec[i]; \ vec[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ @@ -1509,10 +1515,9 @@ DECL_TEMPLATE(Faded) /* A helper to reverse vector components. */ static inline void VectorReverse(ALfloat *restrict out, const ALfloat *restrict in) { - out[0] = in[3]; - out[1] = in[2]; - out[2] = in[1]; - out[3] = in[0]; + ALsizei i; + for(i = 0;i < NUM_LINES;i++) + out[i] = in[NUM_LINES-1-i]; } /* This generates early reflections. @@ -1543,12 +1548,12 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ const ALfloat mixX = State->MixX; \ const ALfloat mixY = State->MixY; \ - ALfloat f[4], fr[4]; \ + ALfloat f[NUM_LINES], fr[NUM_LINES]; \ ALsizei i, j; \ \ for(i = 0;i < todo;i++) \ { \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ f[j] = T##DelayLineOut(&State->Delay, \ offset-State->EarlyDelayTap[j][0], \ offset-State->EarlyDelayTap[j][1], j, fade \ @@ -1559,13 +1564,13 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ \ DelayLineIn4Rev(&State->Early.Delay, offset, f); \ \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ f[j] += T##DelayLineOut(&State->Early.Delay, \ offset-State->Early.Offset[j][0], \ offset-State->Early.Offset[j][1], j, fade \ ) * State->Early.Coeff[j]; \ \ - for(j = 0;j < 4;j++) \ + for(j = 0;j < NUM_LINES;j++) \ out[j][i] = f[j]; \ \ VectorReverse(fr, f); \ @@ -1631,21 +1636,21 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat offset = State->Offset; for(i = 0;i < todo;i++) { - ALfloat f[4], fr[4]; + ALfloat f[NUM_LINES], fr[NUM_LINES]; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = FadedDelayLineOut(&State->Delay, - offset-State->LateDelayTap[j][0], - offset-State->LateDelayTap[j][1], j, fade + offset - State->LateDelayTap[j][0], + offset - State->LateDelayTap[j][1], j, fade ) * State->Late.DensityGain; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] += FadedDelayLineOut(&State->Late.Delay, offset - State->Late.Offset[j][0], offset - State->Late.Offset[j][1], j, fade ); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], @@ -1654,7 +1659,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; VectorReverse(fr, f); @@ -1681,17 +1686,16 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo offset = State->Offset; for(i = 0;i < todo;i++) { - ALfloat f[4], fr[4]; + ALfloat f[NUM_LINES], fr[NUM_LINES]; - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = DelayLineOut(&State->Delay, offset-State->LateDelayTap[j][0], j) * State->Late.DensityGain; - for(j = 0;j < 4;j++) - f[j] += DelayLineOut(&State->Late.Delay, - offset - State->Late.Offset[j][0], j); + for(j = 0;j < NUM_LINES;j++) + f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], @@ -1700,7 +1704,7 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); - for(j = 0;j < 4;j++) + for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; VectorReverse(fr, f); @@ -1730,14 +1734,14 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c todo = mini(todo, FADE_SAMPLES-fadeCount); /* Convert B-Format to A-Format for processing. */ - memset(afmt, 0, sizeof(*afmt)*4); - for(c = 0;c < 4;c++) + memset(afmt, 0, sizeof(*afmt)*NUM_LINES); + for(c = 0;c < NUM_LINES;c++) MixRowSamples(afmt[c], B2A.m[c], SamplesIn, MAX_EFFECT_CHANNELS, base, todo ); /* Process the samples for reverb. */ - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) { /* Band-pass the incoming samples. Use the early output lines for * temp storage. @@ -1776,7 +1780,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Update the cross-fading delay line taps. */ fadeCount = FADE_SAMPLES; fade = 1.0f; - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; @@ -1791,12 +1795,12 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Mix the A-Format results to output, implicitly converting back to * B-Format. */ - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) MixSamples(early[c], NumChannels, SamplesOut, State->Early.CurrentGain[c], State->Early.PanGain[c], SamplesToDo-base, base, todo ); - for(c = 0;c < 4;c++) + for(c = 0;c < NUM_LINES;c++) MixSamples(late[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], SamplesToDo-base, base, todo -- cgit v1.2.3 From 25b3ed3532eeb1a41a0e99d348f28a476c948977 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 07:29:18 -0800 Subject: Use separate arrays for the T60 filter states --- Alc/effects/reverb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index b4961ce8..206362a2 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -318,7 +318,8 @@ typedef struct ALreverbState { /* The HF and LF filters each keep a state of the last input and * last output sample. */ - ALfloat States[2][2]; + ALfloat HFState[2]; + ALfloat LFState[2]; } Filters[NUM_LINES]; /* A Gerzon vector all-pass filter is used to simulate diffusion. */ @@ -426,10 +427,10 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Filters[i].HFCoeffs[j] = 0.0f; state->Late.Filters[i].LFCoeffs[j] = 0.0f; } - state->Late.Filters[i].States[0][0] = 0.0f; - state->Late.Filters[i].States[0][1] = 0.0f; - state->Late.Filters[i].States[1][0] = 0.0f; - state->Late.Filters[i].States[1][1] = 0.0f; + state->Late.Filters[i].HFState[0] = 0.0f; + state->Late.Filters[i].HFState[1] = 0.0f; + state->Late.Filters[i].LFState[0] = 0.0f; + state->Late.Filters[i].LFState[1] = 0.0f; } for(i = 0;i < NUM_LINES;i++) @@ -1652,8 +1653,8 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( - State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], - State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], + State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].HFState, + State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].LFState, f[j] ); VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, @@ -1697,8 +1698,8 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( - State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].States[0], - State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].States[1], + State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].HFState, + State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].LFState, f[j] ); VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, -- cgit v1.2.3 From 6f532fa0e5a42354d423db1f4d2e034769eacc0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 07:33:53 -0800 Subject: Don't check the modulation depth for changes multiple times --- Alc/effects/reverb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 206362a2..a024a5ac 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1341,18 +1341,19 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Determine if delay-line cross-fading is required. */ for(i = 0;i < NUM_LINES;i++) { - if((State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0]) || - (State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0]) || - (State->Early.Offset[i][1] != State->Early.Offset[i][0]) || - (State->LateDelayTap[i][1] != State->LateDelayTap[i][0]) || - (State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0]) || - (State->Late.Offset[i][1] != State->Late.Offset[i][0]) || - (State->Mod.Depth[1] != State->Mod.Depth[0])) + if(State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0] || + State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0] || + State->Early.Offset[i][1] != State->Early.Offset[i][0] || + State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || + State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || + State->Late.Offset[i][1] != State->Late.Offset[i][0]) { State->FadeCount = 0; break; } } + if(State->Mod.Depth[1] != State->Mod.Depth[0]) + State->FadeCount = 0; } -- cgit v1.2.3 From 7e491ef2b2d58e90ce34eabea21056646aace089 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 08:25:36 -0800 Subject: Remove a redundant lower value clamp --- Alc/effects/reverb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a024a5ac..77830c96 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -665,11 +665,9 @@ static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorp */ limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * SpeedOfSound); - /* Using the limit calculated above, apply the upper bound to the HF - * ratio. Also need to limit the result to a minimum of 0.1, just like - * the HF ratio parameter. + /* Using the limit calculated above, apply the upper bound to the HF ratio. */ - return clampf(limitRatio, 0.1f, hfRatio); + return minf(limitRatio, hfRatio); } /* Calculates the first-order high-pass coefficients following the I3DL2 -- cgit v1.2.3 From 0152bc0d10901cc60e579e2f7fa6ebf7786e6106 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 08:51:03 -0800 Subject: Remove the SAFE_CONST macro Seems compilers are now allowing a pointer-to-type-array to implicitly convert to pointer-to-const-type-array. --- Alc/ALu.c | 19 +++++++++---------- Alc/bformatdec.c | 12 ++++-------- Alc/mixer.c | 4 ++-- OpenAL32/Include/alMain.h | 42 ------------------------------------------ 4 files changed, 15 insertions(+), 62 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 2fe579b9..c010ecba 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1724,8 +1724,8 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(device->AmbiUp) ambiup_process(device->AmbiUp, - device->Dry.Buffer, device->Dry.NumChannels, - SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo + device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, + SamplesToDo ); lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); @@ -1737,8 +1737,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) { MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], device->Dry.Buffer[c], state->Offset, state->IrSize, - SAFE_CONST(ALfloat2*,state->Chan[c].Coeffs), - state->Chan[c].Values, SamplesToDo + state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo ); } state->Offset += SamplesToDo; @@ -1747,19 +1746,19 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) { if(device->Dry.Buffer != device->FOAOut.Buffer) bformatdec_upSample(device->AmbiDecoder, - device->Dry.Buffer, SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), - device->FOAOut.NumChannels, SamplesToDo + device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, + SamplesToDo ); bformatdec_process(device->AmbiDecoder, - device->RealOut.Buffer, device->RealOut.NumChannels, - SAFE_CONST(ALfloatBUFFERSIZE*,device->Dry.Buffer), SamplesToDo + device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + SamplesToDo ); } else if(device->AmbiUp) { ambiup_process(device->AmbiUp, - device->RealOut.Buffer, device->RealOut.NumChannels, - SAFE_CONST(ALfloatBUFFERSIZE*,device->FOAOut.Buffer), SamplesToDo + device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, + SamplesToDo ); } else if(device->Uhj_Encoder) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 2c5326d4..ae1f7381 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -433,12 +433,10 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], - SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0, - SamplesToDo + dec->SamplesHF, dec->NumChannels, 0, SamplesToDo ); MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], - SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0, - SamplesToDo + dec->SamplesLF, dec->NumChannels, 0, SamplesToDo ); for(i = 0;i < SamplesToDo;i++) @@ -489,8 +487,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B /* Now write each band to the output. */ MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains, - SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0, - SamplesToDo + dec->Samples, FB_Max, 0, SamplesToDo ); } } @@ -605,8 +602,7 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[ for(j = 0;j < OutChannels;j++) MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j], - SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0, - SamplesToDo + ambiup->Samples, FB_Max, 0, SamplesToDo ); } } diff --git a/Alc/mixer.c b/Alc/mixer.c index b1d859c6..76e5f759 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -583,7 +583,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei */ gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, minf(1.0f, (ALfloat)fademix/Counter)); - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = 0.0f; @@ -612,7 +612,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei gain = lerp(parms->Hrtf.Old.Gain, gain, (ALfloat)todo/(Counter-fademix)); - hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs); + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; hrtfparams.Gain = parms->Hrtf.Old.Gain; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e4f5df74..10f9008a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -145,48 +145,6 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); #endif -#ifdef __GNUC__ -/* Because of a long-standing deficiency in C, you're not allowed to implicitly - * cast a pointer-to-type-array to a pointer-to-const-type-array. For example, - * - * int (*ptr)[10]; - * const int (*cptr)[10] = ptr; - * - * is not allowed and most compilers will generate noisy warnings about - * incompatible types, even though it just makes the array elements const. - * Clang will allow it if you make the array type a typedef, like this: - * - * typedef int int10[10]; - * int10 *ptr; - * const int10 *cptr = ptr; - * - * however GCC does not and still issues the incompatible type warning. The - * "proper" way to fix it is to add an explicit cast for the constified type, - * but that removes the vast majority of otherwise useful type-checking you'd - * get, and runs the risk of improper casts if types are later changed. Leaving - * it non-const can also be an issue if you use it as a function parameter, and - * happen to have a const type as input (and also reduce the capabilities of - * the compiler to better optimize the function). - * - * So to work around the problem, we use a macro. The macro first assigns the - * incoming variable to the specified non-const type to ensure it's the correct - * type, then casts the variable as the desired constified type. Very ugly, but - * I'd rather not have hundreds of lines of warnings because I want to tell the - * compiler that some array(s) can't be changed by the code, or have lots of - * error-prone casts. - */ -#define SAFE_CONST(T, var) __extension__({ \ - T _tmp = (var); \ - (const T)_tmp; \ -}) -#else -/* Non-GNU-compatible compilers have to use a straight cast with no extra - * checks, due to the lack of multi-statement expressions. - */ -#define SAFE_CONST(T, var) ((const T)(var)) -#endif - - #ifdef __GNUC__ #define LIKELY(x) __builtin_expect(!!(x), !0) #define UNLIKELY(x) __builtin_expect(!!(x), 0) -- cgit v1.2.3 From 63416bf28f0a717941c752fd84015ee35e7f4e4b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 09:02:59 -0800 Subject: Avoid unnecessarily using type aliases --- Alc/ALu.c | 9 +++++---- Alc/effects/null.c | 4 ++-- OpenAL32/Include/alAuxEffectSlot.h | 5 +++++ OpenAL32/Include/alMain.h | 6 ------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index c010ecba..04227ce4 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1521,7 +1521,7 @@ static void ApplyStablizer(FrontStablizer *Stablizer, ALfloat (*restrict Buffer) } } -static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp *distcomp, +static void ApplyDistanceComp(ALfloat (*restrict Samples)[BUFFERSIZE], DistanceComp *distcomp, ALfloat *restrict Values, ALsizei SamplesToDo, ALsizei numchans) { ALsizei i, c; @@ -1564,7 +1564,7 @@ static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp } } -static void ApplyDither(ALfloatBUFFERSIZE *restrict Samples, ALuint *dither_seed, +static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_seed, const ALfloat quant_scale, const ALsizei SamplesToDo, const ALsizei numchans) { @@ -1618,8 +1618,9 @@ DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u) #undef DECL_TEMPLATE #define DECL_TEMPLATE(T, A) \ -static void Write##A(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ - ALsizei Offset, ALsizei SamplesToDo, ALsizei numchans) \ +static void Write##A(const ALfloat (*restrict InBuffer)[BUFFERSIZE], \ + ALvoid *OutBuffer, ALsizei Offset, ALsizei SamplesToDo, \ + ALsizei numchans) \ { \ ALsizei i, j; \ for(j = 0;j < numchans;j++) \ diff --git a/Alc/effects/null.c b/Alc/effects/null.c index a6591c58..f3e8a6df 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -17,7 +17,7 @@ typedef struct ALnullState { static ALvoid ALnullState_Destruct(ALnullState *state); static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device); static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALsizei NumChannels); +static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei mumChannels); static void *ALnullState_New(size_t size); static void ALnullState_Delete(void *ptr); @@ -64,7 +64,7 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* U * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(NumChannels)) +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(numChannels)) { } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 908c72c5..74bb841c 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -35,6 +35,11 @@ struct ALeffectStateVtable { void (*const Delete)(void *ptr); }; +/* Small hack to use a pointer-to-array types as a normal argument type. + * Shouldn't be used directly. + */ +typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; + #define DEFINE_ALEFFECTSTATE_VTABLE(T) \ DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 10f9008a..7e954f0d 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -720,12 +720,6 @@ inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) vector_al_string SearchDataFiles(const char *match, const char *subdir); -/* Small hack to use a pointer-to-array types as a normal argument type. - * Shouldn't be used directly. - */ -typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; -typedef ALfloat ALfloat2[2]; - #ifdef __cplusplus } #endif -- cgit v1.2.3 From bc078e5158fe03fcdae686d706029a8eb30447de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Jan 2018 13:48:20 -0800 Subject: Separate some anonymous structs into defined structs --- Alc/effects/reverb.c | 216 ++++++++++++++++++++++++++------------------------- Alc/mixer_c.c | 2 +- 2 files changed, 110 insertions(+), 108 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 77830c96..a2f90dc7 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -237,6 +237,65 @@ typedef struct VecAllpass { ALsizei Offset[NUM_LINES][2]; } VecAllpass; +typedef struct EarlyReflections { + /* A Gerzon vector all-pass filter is used to simulate initial diffusion. + * The spread from this filter also helps smooth out the reverb tail. + */ + VecAllpass VecAp; + + /* An echo line is used to complete the second half of the early + * reflections. + */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]; + ALfloat Coeff[NUM_LINES]; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; +} EarlyReflections; + +typedef struct Modulator { + /* The vibrato time is tracked with an index over a modulus-wrapped range + * (in samples). + */ + ALsizei Index; + ALsizei Range; + ALfloat IdxScale; + + /* The depth of frequency change (also in samples) and its filter. */ + ALfloat Depth[2]; +} Modulator; + +typedef struct LateReverb { + /* Attenuation to compensate for the modal density and decay rate of the + * late lines. + */ + ALfloat DensityGain; + + /* A recursive delay line is used fill in the reverb tail. */ + DelayLineI Delay; + ALsizei Offset[NUM_LINES][2]; + + /* T60 decay filters are used to simulate absorption. */ + struct { + ALfloat HFCoeffs[3]; + ALfloat LFCoeffs[3]; + /* The HF and LF filters each keep a state of the last input and last + * output sample. + */ + ALfloat HFState[2]; + ALfloat LFState[2]; + } T60[NUM_LINES]; + + /* A Gerzon vector all-pass filter is used to simulate diffusion. */ + VecAllpass VecAp; + + /* The gain for each output channel based on 3D panning. */ + ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; + ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; +} LateReverb; + typedef struct ALreverbState { DERIVE_FROM_TYPE(ALeffectState); @@ -249,7 +308,7 @@ typedef struct ALreverbState { /* Master effect filters */ struct { ALfilterState Lp; - ALfilterState Hp; /* EAX only */ + ALfilterState Hp; } Filter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ @@ -270,65 +329,11 @@ typedef struct ALreverbState { ALfloat MixX; ALfloat MixY; - struct { - /* A Gerzon vector all-pass filter is used to simulate initial - * diffusion. The spread from this filter also helps smooth out the - * reverb tail. - */ - VecAllpass VecAp; - - /* An echo line is used to complete the second half of the early - * reflections. - */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; - ALfloat Coeff[NUM_LINES]; - - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; - } Early; - - struct { - /* The vibrato time is tracked with an index over a modulus-wrapped - * range (in samples). - */ - ALsizei Index; - ALsizei Range; - ALfloat Scale; - - /* The depth of frequency change (also in samples) and its filter. */ - ALfloat Depth[2]; - } Mod; /* EAX only */ - - struct { - /* Attenuation to compensate for the modal density and decay rate of - * the late lines. - */ - ALfloat DensityGain; - - /* A recursive delay line is used fill in the reverb tail. */ - DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; - - /* T60 decay filters are used to simulate absorption. */ - struct { - ALfloat HFCoeffs[3]; - ALfloat LFCoeffs[3]; - /* The HF and LF filters each keep a state of the last input and - * last output sample. - */ - ALfloat HFState[2]; - ALfloat LFState[2]; - } Filters[NUM_LINES]; + EarlyReflections Early; - /* A Gerzon vector all-pass filter is used to simulate diffusion. */ - VecAllpass VecAp; + Modulator Mod; - /* The gain for each output channel based on 3D panning. */ - ALfloat CurrentGain[4][MAX_OUTPUT_CHANNELS]; - ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; - } Late; + LateReverb Late; /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ ALsizei FadeCount; @@ -404,7 +409,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Mod.Index = 0; state->Mod.Range = 1; - state->Mod.Scale = 0.0f; + state->Mod.IdxScale = 0.0f; state->Mod.Depth[0] = 0.0f; state->Mod.Depth[1] = 0.0f; @@ -424,13 +429,13 @@ static void ALreverbState_Construct(ALreverbState *state) for(j = 0;j < 3;j++) { - state->Late.Filters[i].HFCoeffs[j] = 0.0f; - state->Late.Filters[i].LFCoeffs[j] = 0.0f; + state->Late.T60[i].HFCoeffs[j] = 0.0f; + state->Late.T60[i].LFCoeffs[j] = 0.0f; } - state->Late.Filters[i].HFState[0] = 0.0f; - state->Late.Filters[i].HFState[1] = 0.0f; - state->Late.Filters[i].LFState[0] = 0.0f; - state->Late.Filters[i].LFState[1] = 0.0f; + state->Late.T60[i].HFState[0] = 0.0f; + state->Late.T60[i].HFState[1] = 0.0f; + state->Late.T60[i].LFState[0] = 0.0f; + state->Late.T60[i].LFState[1] = 0.0f; } for(i = 0;i < NUM_LINES;i++) @@ -995,7 +1000,7 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime * downswing will sound stronger than the upswing. */ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, - const ALuint frequency, ALreverbState *State) + const ALuint frequency, Modulator *Mod) { ALsizei range; @@ -1003,15 +1008,13 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, * * The modulation time effects the speed of the sinus. An index out of the * current range (both in samples) is incremented each sample, so a longer - * time implies a larger range. The range is bound to a reasonable minimum - * (1 sample) and when the timing changes, the index is rescaled to the new - * range to keep the sinus consistent. + * time implies a larger range. When the timing changes, the index is + * rescaled to the new range to keep the sinus consistent. */ range = fastf2i(modTime*frequency + 0.5f); - State->Mod.Index = (ALsizei)(State->Mod.Index * (ALint64)range / - State->Mod.Range) % range; - State->Mod.Range = range; - State->Mod.Scale = F_TAU / range; + Mod->Index = (ALsizei)(Mod->Index * (ALint64)range / Mod->Range)%range; + Mod->Range = range; + Mod->IdxScale = F_TAU / range; /* The modulation depth effects the scale of the sinus, which varies the * delay for the tapped output. This delay changing over time changes the @@ -1020,9 +1023,9 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth, * that a given depth produces a consistent shift in frequency over all * ranges of time. */ - State->Mod.Depth[1] = modDepth * MODULATION_DEPTH_COEFF * - (modTime / AL_EAXREVERB_MAX_MODULATION_TIME) * - frequency * FRACTIONONE; + Mod->Depth[1] = modDepth * MODULATION_DEPTH_COEFF * + (modTime / AL_EAXREVERB_MAX_MODULATION_TIME) * + frequency * FRACTIONONE; } /* Update the offsets for the main effect delay line. */ @@ -1057,7 +1060,7 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, } /* Update the early reflection line lengths and gain coefficients. */ -static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State) +static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) { ALfloat multiplier, length; ALsizei i; @@ -1070,21 +1073,21 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c length = EARLY_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - State->Early.VecAp.Offset[i][1] = fastf2i(length * frequency); + Early->VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; /* Calculate the delay offset for each delay line. */ - State->Early.Offset[i][1] = fastf2i(length * frequency); + Early->Offset[i][1] = fastf2i(length * frequency); /* Calculate the gain (coefficient) for each line. */ - State->Early.Coeff[i] = CalcDecayCoeff(length, decayTime); + Early->Coeff[i] = CalcDecayCoeff(length, decayTime); } } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALreverbState *State) +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, LateReverb *Late) { ALfloat multiplier, length, bandWeights[3]; ALsizei i; @@ -1112,7 +1115,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co bandWeights[0] = lfW; bandWeights[1] = hfW - lfW; bandWeights[2] = F_TAU - hfW; - State->Late.DensityGain = CalcDensityGain( + Late->DensityGain = CalcDensityGain( CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime) / F_TAU) ); @@ -1123,7 +1126,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - State->Late.VecAp.Offset[i][1] = fastf2i(length * frequency); + Late->VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. This also * applies the echo transformation. As the EAX echo depth approaches @@ -1133,7 +1136,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth); /* Calculate the delay offset for each delay line. */ - State->Late.Offset[i][1] = fastf2i(length*frequency + 0.5f); + Late->Offset[i][1] = fastf2i(length*frequency + 0.5f); /* Approximate the absorption that the vector all-pass would exhibit * given the current diffusion so we don't have to process a full T60 @@ -1146,8 +1149,8 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the T60 damping coefficients for each line. */ CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, - lfW, hfW, State->Late.Filters[i].LFCoeffs, - State->Late.Filters[i].HFCoeffs); + lfW, hfW, Late->T60[i].LFCoeffs, + Late->T60[i].HFCoeffs); } } @@ -1298,7 +1301,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Update the early lines. */ UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime, - frequency, State); + frequency, &State->Early); /* Get the mixing matrix coefficients. */ CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); @@ -1318,16 +1321,16 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); - /* Update the modulator line. */ + /* Update the modulator parameters. */ UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, - frequency, State); + frequency, &State->Mod); /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, F_TAU * lf0norm, F_TAU * hf0norm, props->Reverb.EchoTime, props->Reverb.EchoDepth, - frequency, State); + frequency, &State->Late); /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; @@ -1397,33 +1400,32 @@ static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const AL Delay->Line[offset][i] = in[NUM_LINES-1-i]; } -static void CalcModulationDelays(ALreverbState *State, - ALsizei (*restrict delays)[MAX_UPDATE_SAMPLES][2], +static void CalcModulationDelays(Modulator *Mod, ALsizei (*restrict delays)[MAX_UPDATE_SAMPLES][2], const ALsizei (*restrict offsets)[2], const ALsizei todo) { - ALsizei phase_offset = State->Mod.Range >> 2; - ALsizei index, c, i; + const ALsizei phase_offset = Mod->Range >> 2; ALfloat sinus; + ALsizei c, i; for(c = 0;c < NUM_LINES;c++) { ALsizei offset0 = offsets[c][0] << FRACTIONBITS; ALsizei offset1 = offsets[c][1] << FRACTIONBITS; - index = State->Mod.Index + phase_offset*c; + ALsizei index = Mod->Index + phase_offset*c; for(i = 0;i < todo;i++) { /* Calculate the sinus rhythm (dependent on modulation time and the * sampling rate). */ - sinus = sinf(index * State->Mod.Scale); - index = (index+1) % State->Mod.Range; + sinus = sinf(index * Mod->IdxScale); + index = (index+1) % Mod->Range; /* Calculate the read offset. */ - delays[c][i][0] = fastf2i(sinus*State->Mod.Depth[0]) + offset0; - delays[c][i][1] = fastf2i(sinus*State->Mod.Depth[1]) + offset1; + delays[c][i][0] = fastf2i(sinus*Mod->Depth[0]) + offset0; + delays[c][i][1] = fastf2i(sinus*Mod->Depth[1]) + offset1; } } - State->Mod.Index = (State->Mod.Index+todo) % State->Mod.Range; + Mod->Index = (Mod->Index+todo) % Mod->Range; } /* Applies a scattering matrix to the 4-line (vector) input. This is used @@ -1631,7 +1633,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat ALsizei offset; ALsizei i, j; - CalcModulationDelays(State, moddelay, State->Late.Offset, todo); + CalcModulationDelays(&State->Mod, moddelay, State->Late.Offset, todo); offset = State->Offset; for(i = 0;i < todo;i++) @@ -1652,8 +1654,8 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( - State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].HFState, - State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].LFState, + State->Late.T60[j].HFCoeffs, State->Late.T60[j].HFState, + State->Late.T60[j].LFCoeffs, State->Late.T60[j].LFState, f[j] ); VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, @@ -1681,7 +1683,7 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo ALsizei offset; ALsizei i, j; - CalcModulationDelays(State, moddelay, State->Late.Offset, todo); + CalcModulationDelays(&State->Mod, moddelay, State->Late.Offset, todo); offset = State->Offset; for(i = 0;i < todo;i++) @@ -1697,8 +1699,8 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo for(j = 0;j < NUM_LINES;j++) f[j] = LateT60Filter( - State->Late.Filters[j].HFCoeffs, State->Late.Filters[j].HFState, - State->Late.Filters[j].LFCoeffs, State->Late.Filters[j].LFState, + State->Late.T60[j].HFCoeffs, State->Late.T60[j].HFState, + State->Late.T60[j].LFCoeffs, State->Late.T60[j].LFState, f[j] ); VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, @@ -1754,7 +1756,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c DelayLineIn(&State->Delay, State->Offset+i, c, early[1][i]); } - if(fade < 1.0f) + if(UNLIKELY(fadeCount < FADE_SAMPLES)) { /* Generate early reflections. */ EarlyReflection_Faded(State, todo, fade, early); diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index 0bb93e8a..f8c3c833 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -95,7 +95,7 @@ const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restric void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { ALsizei i; - if(numsamples > 1) + if(LIKELY(numsamples > 1)) { dst[0] = filter->b0 * src[0] + filter->b1 * filter->x[0] + -- cgit v1.2.3 From 6f48dac4cc92f057028fb2b36b53856d1344e9f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 05:23:35 -0800 Subject: Use a proper type for the T60 decay filter --- Alc/effects/reverb.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a2f90dc7..4354e022 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -237,6 +237,21 @@ typedef struct VecAllpass { ALsizei Offset[NUM_LINES][2]; } VecAllpass; +typedef struct T60Filter { + /* Two filters are used to adjust the signal. One to control the low + * frequencies, and one to control the high frequencies. The HF filter also + * adjusts the overall output gain, affecting the remaining mid-band. + */ + ALfloat HFCoeffs[3]; + ALfloat LFCoeffs[3]; + + /* The HF and LF filters each keep a state of the last input and last + * output sample. + */ + ALfloat HFState[2]; + ALfloat LFState[2]; +} T60Filter; + typedef struct EarlyReflections { /* A Gerzon vector all-pass filter is used to simulate initial diffusion. * The spread from this filter also helps smooth out the reverb tail. @@ -263,7 +278,7 @@ typedef struct Modulator { ALsizei Range; ALfloat IdxScale; - /* The depth of frequency change (also in samples) and its filter. */ + /* The LFO delay scale (in samples scaled by FRACTIONONE). */ ALfloat Depth[2]; } Modulator; @@ -278,15 +293,7 @@ typedef struct LateReverb { ALsizei Offset[NUM_LINES][2]; /* T60 decay filters are used to simulate absorption. */ - struct { - ALfloat HFCoeffs[3]; - ALfloat LFCoeffs[3]; - /* The HF and LF filters each keep a state of the last input and last - * output sample. - */ - ALfloat HFState[2]; - ALfloat LFState[2]; - } T60[NUM_LINES]; + T60Filter T60[NUM_LINES]; /* A Gerzon vector all-pass filter is used to simulate diffusion. */ VecAllpass VecAp; @@ -1599,13 +1606,11 @@ static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict } /* Applies the two T60 damping filter sections. */ -static inline ALfloat LateT60Filter(const ALfloat *restrict HFCoeffs, ALfloat *restrict HFState, - const ALfloat *restrict LFCoeffs, ALfloat *restrict LFState, - const ALfloat in) +static inline ALfloat LateT60Filter(T60Filter *filter, const ALfloat in) { return FirstOrderFilter( - FirstOrderFilter(in, HFCoeffs, HFState), - LFCoeffs, LFState + FirstOrderFilter(in, filter->HFCoeffs, filter->HFState), + filter->LFCoeffs, filter->LFState ); } @@ -1653,11 +1658,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat ); for(j = 0;j < NUM_LINES;j++) - f[j] = LateT60Filter( - State->Late.T60[j].HFCoeffs, State->Late.T60[j].HFState, - State->Late.T60[j].LFCoeffs, State->Late.T60[j].LFState, - f[j] - ); + f[j] = LateT60Filter(&State->Late.T60[j], f[j]); VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); @@ -1698,11 +1699,7 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); for(j = 0;j < NUM_LINES;j++) - f[j] = LateT60Filter( - State->Late.T60[j].HFCoeffs, State->Late.T60[j].HFState, - State->Late.T60[j].LFCoeffs, State->Late.T60[j].LFState, - f[j] - ); + f[j] = LateT60Filter(&State->Late.T60[j], f[j]); VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); -- cgit v1.2.3 From 7441311e3def88a56fcdeca9bca7938629df9d54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 05:37:00 -0800 Subject: Use separate input and outputs for the T60 and allpass processing --- Alc/effects/reverb.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 4354e022..39d449ee 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1493,10 +1493,11 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re * line processing and non-transitional processing. */ #define DECL_TEMPLATE(T) \ -static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ - const ALfloat feedCoeff, const ALfloat xCoeff, \ - const ALfloat yCoeff, const ALfloat mu, \ - VecAllpass *Vap) \ +static void VectorAllpass_##T(ALfloat *restrict out, \ + const ALfloat *restrict in, \ + const ALsizei offset, const ALfloat feedCoeff, \ + const ALfloat xCoeff, const ALfloat yCoeff, \ + const ALfloat mu, VecAllpass *Vap) \ { \ ALfloat f[NUM_LINES], fs[NUM_LINES]; \ ALfloat input; \ @@ -1506,13 +1507,12 @@ static void VectorAllpass_##T(ALfloat *restrict vec, const ALsizei offset, \ \ for(i = 0;i < NUM_LINES;i++) \ { \ - input = vec[i]; \ - vec[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ + input = in[i]; \ + out[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ offset-Vap->Offset[i][1], i, mu) - \ feedCoeff*input; \ - f[i] = input + feedCoeff*vec[i]; \ + f[i] = input + feedCoeff*out[i]; \ } \ - \ VectorPartialScatter(fs, f, xCoeff, yCoeff); \ \ DelayLineIn4(&Vap->Delay, offset, fs); \ @@ -1563,12 +1563,12 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ for(i = 0;i < todo;i++) \ { \ for(j = 0;j < NUM_LINES;j++) \ - f[j] = T##DelayLineOut(&State->Delay, \ + fr[j] = T##DelayLineOut(&State->Delay, \ offset-State->EarlyDelayTap[j][0], \ offset-State->EarlyDelayTap[j][1], j, fade \ ) * State->EarlyDelayCoeff[j]; \ \ - VectorAllpass_##T(f, offset, apFeedCoeff, mixX, mixY, fade, \ + VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ &State->Early.VecAp); \ \ DelayLineIn4Rev(&State->Early.Delay, offset, f); \ @@ -1606,12 +1606,15 @@ static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict } /* Applies the two T60 damping filter sections. */ -static inline ALfloat LateT60Filter(T60Filter *filter, const ALfloat in) +static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict in, + T60Filter *filter) { - return FirstOrderFilter( - FirstOrderFilter(in, filter->HFCoeffs, filter->HFState), - filter->LFCoeffs, filter->LFState - ); + ALsizei i; + for(i = 0;i < NUM_LINES;i++) + out[i] = FirstOrderFilter( + FirstOrderFilter(in[i], filter[i].HFCoeffs, filter[i].HFState), + filter[i].LFCoeffs, filter[i].LFState + ); } /* This generates the reverb tail using a modified feed-back delay network @@ -1657,9 +1660,8 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat offset - State->Late.Offset[j][1], j, fade ); - for(j = 0;j < NUM_LINES;j++) - f[j] = LateT60Filter(&State->Late.T60[j], f[j]); - VectorAllpass_Faded(f, offset, apFeedCoeff, mixX, mixY, fade, + LateT60Filter(fr, f, State->Late.T60); + VectorAllpass_Faded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) @@ -1698,9 +1700,8 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo for(j = 0;j < NUM_LINES;j++) f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); - for(j = 0;j < NUM_LINES;j++) - f[j] = LateT60Filter(&State->Late.T60[j], f[j]); - VectorAllpass_Unfaded(f, offset, apFeedCoeff, mixX, mixY, fade, + LateT60Filter(fr, f, State->Late.T60); + VectorAllpass_Unfaded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) -- cgit v1.2.3 From 682205a3d44da7ff2402c7323033a1aabf2477ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 06:45:53 -0800 Subject: Finalize ALC_SOFT_device_clock --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 15 --------------- examples/alffplay.cpp | 5 +---- include/AL/alext.h | 15 +++++++++++++++ 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dfebe02e..71db5e0f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -778,7 +778,7 @@ 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_SOFTX_device_clock ALC_SOFT_HRTF " + "ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF " "ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device"; static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 7e954f0d..4f6d0b49 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -47,21 +47,6 @@ #define ALC_N3D_SOFT 0xfff7 #endif -#ifndef ALC_SOFT_device_clock -#define ALC_SOFT_device_clock 1 -typedef int64_t ALCint64SOFT; -typedef uint64_t ALCuint64SOFT; -#define ALC_DEVICE_CLOCK_SOFT 0x1600 -#define ALC_DEVICE_LATENCY_SOFT 0x1601 -#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 -#define AL_SAMPLE_OFFSET_CLOCK_SOFT 0x1202 -#define AL_SEC_OFFSET_CLOCK_SOFT 0x1203 -typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -#endif -#endif - #ifndef AL_SOFT_buffer_samples2 #define AL_SOFT_buffer_samples2 1 /* Channel configurations */ diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index acd2e149..b57de5e4 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -1589,10 +1589,7 @@ int main(int argc, char *argv[]) name = alcGetString(device, ALC_DEVICE_SPECIFIER); std::cout<< "Opened \""<( diff --git a/include/AL/alext.h b/include/AL/alext.h index 4b9a1553..1a76397b 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -459,6 +459,21 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); #define ALC_OUTPUT_LIMITER_SOFT 0x199A #endif +#ifndef ALC_SOFT_device_clock +#define ALC_SOFT_device_clock 1 +typedef int64_t ALCint64SOFT; +typedef uint64_t ALCuint64SOFT; +#define ALC_DEVICE_CLOCK_SOFT 0x1600 +#define ALC_DEVICE_LATENCY_SOFT 0x1601 +#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 +#define AL_SAMPLE_OFFSET_CLOCK_SOFT 0x1202 +#define AL_SEC_OFFSET_CLOCK_SOFT 0x1203 +typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); +#endif +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 5acb2e5165abcfdc61bc8d4702425923343c07df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 07:14:35 -0800 Subject: Remove alffplay's duplicate ALC_SOFT_device_clock declarations --- examples/alffplay.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index b57de5e4..65719807 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -37,20 +37,6 @@ extern "C" { #include "AL/al.h" #include "AL/alext.h" -extern "C" { -#ifndef ALC_SOFT_device_clock -#define ALC_SOFT_device_clock 1 -typedef int64_t ALCint64SOFT; -typedef uint64_t ALCuint64SOFT; -#define ALC_DEVICE_CLOCK_SOFT 0x1600 -#define ALC_DEVICE_LATENCY_SOFT 0x1601 -#define ALC_DEVICE_CLOCK_LATENCY_SOFT 0x1602 -#define AL_SAMPLE_OFFSET_CLOCK_SOFT 0x1202 -#define AL_SEC_OFFSET_CLOCK_SOFT 0x1203 -typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -#endif -} // extern "C" - namespace { using nanoseconds = std::chrono::nanoseconds; -- cgit v1.2.3 From 44795b8614564ea65ae864419dedaa610742350c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 08:38:25 -0800 Subject: Assign the HRTF storage pointers separately --- Alc/hrtf.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 310dc68c..d1cfe6b0 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -343,20 +343,22 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, Hrtf->evCount = evCount; /* Set up pointers to storage following the main HRTF struct. */ - _azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount; + _azCount = (ALubyte*)(base + offset); offset += sizeof(_azCount[0])*evCount; offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */ - _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset; + _evOffset = (ALushort*)(base + offset); offset += sizeof(_evOffset[0])*evCount; offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */ - _coeffs = (ALfloat(*)[2])(base + offset); Hrtf->coeffs = _coeffs; + _coeffs = (ALfloat(*)[2])(base + offset); offset += sizeof(_coeffs[0])*irSize*irCount; - _delays = (ALubyte(*)[2])(base + offset); Hrtf->delays = _delays; + _delays = (ALubyte(*)[2])(base + offset); offset += sizeof(_delays[0])*irCount; + assert(offset == total); + /* Copy input data to storage. */ for(i = 0;i < evCount;i++) _azCount[i] = azCount[i]; for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i]; @@ -371,7 +373,11 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, _delays[i][1] = delays[i][1]; } - assert(offset == total); + /* Finally, assign the storage pointers. */ + Hrtf->azCount = _azCount; + Hrtf->evOffset = _evOffset; + Hrtf->coeffs = _coeffs; + Hrtf->delays = _delays; } return Hrtf; -- cgit v1.2.3 From 47c9b0a17e7e497aeeadea32ddb48e62bcf4a9ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 09:17:15 -0800 Subject: Simplify preparing the T60 filters --- Alc/effects/reverb.c | 61 ++++++++++------------------------------------------ 1 file changed, 11 insertions(+), 50 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 39d449ee..76f9b2d6 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -713,7 +713,6 @@ static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALflo coeffs[0] = 1.0f; coeffs[1] = 0.0f; coeffs[2] = 0.0f; - return; } @@ -758,7 +757,6 @@ static inline void CalcLowpassCoeffs(const ALfloat gain, const ALfloat w, ALfloa coeffs[0] = 1.0f; coeffs[1] = 0.0f; coeffs[2] = 0.0f; - return; } @@ -830,7 +828,6 @@ static inline void CalcLowShelfCoeffs(const ALfloat gain, const ALfloat w, ALflo coeffs[0] = 1.0f; coeffs[1] = 0.0f; coeffs[2] = 0.0f; - return; } @@ -902,7 +899,6 @@ static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfl coeffs[0] = 1.0f; coeffs[1] = 0.0f; coeffs[2] = 0.0f; - return; } @@ -933,71 +929,36 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); - if(lfGain < mfGain) + if(lfGain <= mfGain) { CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs); - if(mfGain < hfGain) - { - CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); - hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; - } - else if(mfGain > hfGain) + if(mfGain >= hfGain) { CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); hfcoeffs[0] *= mfGain; hfcoeffs[1] *= mfGain; } else { - hfcoeffs[0] = mfGain; - hfcoeffs[1] = 0.0f; - hfcoeffs[2] = 0.0f; + CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); + hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; } } - else if(lfGain > mfGain) + else { CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs); - if(mfGain < hfGain) - { - ALfloat hg = mfGain / lfGain; - ALfloat lg = mfGain / hfGain; - ALfloat mg = maxf(lfGain, hfGain) / maxf(hg, lg); - - CalcLowShelfCoeffs(lg, hfW, hfcoeffs); - hfcoeffs[0] *= mg; hfcoeffs[1] *= mg; - } - else if(mfGain > hfGain) + if(mfGain >= hfGain) { CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); hfcoeffs[0] *= lfGain; hfcoeffs[1] *= lfGain; } else { - hfcoeffs[0] = lfGain; - hfcoeffs[1] = 0.0f; - hfcoeffs[2] = 0.0f; - } - } - else - { - lfcoeffs[0] = 1.0f; - lfcoeffs[1] = 0.0f; - lfcoeffs[2] = 0.0f; + ALfloat hg = mfGain / lfGain; + ALfloat lg = mfGain / hfGain; + ALfloat mg = maxf(lfGain, hfGain) / maxf(hg, lg); - if(mfGain < hfGain) - { - CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); - hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; - } - else if(mfGain > hfGain) - { - CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - hfcoeffs[0] *= mfGain; hfcoeffs[1] *= mfGain; - } - else - { - hfcoeffs[0] = mfGain; - hfcoeffs[1] = 0.0f; - hfcoeffs[2] = 0.0f; + CalcLowShelfCoeffs(lg, hfW, hfcoeffs); + hfcoeffs[0] *= mg; hfcoeffs[1] *= mg; } } } -- cgit v1.2.3 From 813b06a3a4dbe17df1f780ecd1341e68537de153 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 09:22:28 -0800 Subject: Fix a comment regarding the T60 filter coefficients --- Alc/effects/reverb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 76f9b2d6..4e039d3e 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -916,9 +916,8 @@ static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfl /* Calculates the 3-band T60 damping coefficients for a particular delay line * of specified length using a combination of two low/high-pass/shelf or - * pass-through filter sections (producing 3 coefficients each) and a general - * gain (7th coefficient) given decay times for each band split at two (LF/ - * HF) reference frequencies (w). + * pass-through filter sections (producing 3 coefficients each) given decay + * times for each band split at two (LF/HF) reference frequencies (w). */ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, -- cgit v1.2.3 From 799dfb732b4f49198d72649e86955ea82f45f229 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 18:02:11 -0800 Subject: Don't fade the all-pass delay changes --- Alc/effects/reverb.c | 76 +++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 4e039d3e..85f55880 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -234,7 +234,7 @@ typedef struct DelayLineI { typedef struct VecAllpass { DelayLineI Delay; - ALsizei Offset[NUM_LINES][2]; + ALsizei Offset[NUM_LINES]; } VecAllpass; typedef struct T60Filter { @@ -407,8 +407,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Delay.Line = NULL; for(i = 0;i < NUM_LINES;i++) { - state->Early.VecAp.Offset[i][0] = 0; - state->Early.VecAp.Offset[i][1] = 0; + state->Early.VecAp.Offset[i] = 0; state->Early.Offset[i][0] = 0; state->Early.Offset[i][1] = 0; state->Early.Coeff[i] = 0.0f; @@ -431,8 +430,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; - state->Late.VecAp.Offset[i][0] = 0; - state->Late.VecAp.Offset[i][1] = 0; + state->Late.VecAp.Offset[i] = 0; for(j = 0;j < 3;j++) { @@ -1040,7 +1038,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c length = EARLY_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Early->VecAp.Offset[i][1] = fastf2i(length * frequency); + Early->VecAp.Offset[i] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; @@ -1093,7 +1091,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Late->VecAp.Offset[i][1] = fastf2i(length * frequency); + Late->VecAp.Offset[i] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. This also * applies the echo transformation. As the EAX echo depth approaches @@ -1310,10 +1308,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte for(i = 0;i < NUM_LINES;i++) { if(State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0] || - State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0] || State->Early.Offset[i][1] != State->Early.Offset[i][0] || State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || - State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || State->Late.Offset[i][1] != State->Late.Offset[i][0]) { State->FadeCount = 0; @@ -1448,38 +1444,26 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re * It works by vectorizing a regular all-pass filter and replacing the delay * element with a scattering matrix (like the one above) and a diagonal * matrix of delay elements. - * - * Two static specializations are used for transitional (cross-faded) delay - * line processing and non-transitional processing. */ -#define DECL_TEMPLATE(T) \ -static void VectorAllpass_##T(ALfloat *restrict out, \ - const ALfloat *restrict in, \ - const ALsizei offset, const ALfloat feedCoeff, \ - const ALfloat xCoeff, const ALfloat yCoeff, \ - const ALfloat mu, VecAllpass *Vap) \ -{ \ - ALfloat f[NUM_LINES], fs[NUM_LINES]; \ - ALfloat input; \ - ALsizei i; \ - \ - (void)mu; /* Ignore for Unfaded. */ \ - \ - for(i = 0;i < NUM_LINES;i++) \ - { \ - input = in[i]; \ - out[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ - offset-Vap->Offset[i][1], i, mu) - \ - feedCoeff*input; \ - f[i] = input + feedCoeff*out[i]; \ - } \ - VectorPartialScatter(fs, f, xCoeff, yCoeff); \ - \ - DelayLineIn4(&Vap->Delay, offset, fs); \ +static void ApplyAllpass(ALfloat *restrict out, const ALfloat *restrict in, const ALsizei offset, + const ALfloat feedCoeff, const ALfloat xCoeff, const ALfloat yCoeff, + VecAllpass *Vap) +{ + ALfloat f[NUM_LINES], fs[NUM_LINES]; + ALfloat input; + ALsizei i; + + for(i = 0;i < NUM_LINES;i++) + { + input = in[i]; + out[i] = DelayLineOut(&Vap->Delay, offset-Vap->Offset[i], i) - + feedCoeff*input; + f[i] = input + feedCoeff*out[i]; + } + VectorPartialScatter(fs, f, xCoeff, yCoeff); + + DelayLineIn4(&Vap->Delay, offset, fs); } -DECL_TEMPLATE(Unfaded) -DECL_TEMPLATE(Faded) -#undef DECL_TEMPLATE /* A helper to reverse vector components. */ static inline void VectorReverse(ALfloat *restrict out, const ALfloat *restrict in) @@ -1528,8 +1512,8 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ offset-State->EarlyDelayTap[j][1], j, fade \ ) * State->EarlyDelayCoeff[j]; \ \ - VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ - &State->Early.VecAp); \ + ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, \ + &State->Early.VecAp); \ \ DelayLineIn4Rev(&State->Early.Delay, offset, f); \ \ @@ -1621,8 +1605,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat ); LateT60Filter(fr, f, State->Late.T60); - VectorAllpass_Faded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, - &State->Late.VecAp); + ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; @@ -1636,7 +1619,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade += FadeStep; } } -static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat fade, +static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat UNUSED(fade), ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALsizei (*restrict moddelay)[MAX_UPDATE_SAMPLES][2] = State->ModulationDelays; @@ -1661,8 +1644,7 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); LateT60Filter(fr, f, State->Late.T60); - VectorAllpass_Unfaded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, - &State->Late.VecAp); + ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; @@ -1743,10 +1725,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c for(c = 0;c < NUM_LINES;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; State->Early.Offset[c][0] = State->Early.Offset[c][1]; State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } State->Mod.Depth[0] = State->Mod.Depth[1]; -- cgit v1.2.3 From bc44efb91d54b6c4af213b015fc146ee0002cd72 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Jan 2018 18:31:43 -0800 Subject: Use ALsizei for some count/length variables --- OpenAL32/sample_cvt.c | 74 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 89c2a408..58cad523 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -632,15 +632,13 @@ static inline ALmulaw Conv_ALmulaw_ALalaw(ALalaw val) #define DECL_TEMPLATE(T1, T2) \ -static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint numchans, \ - ALuint len, ALsizei UNUSED(align)) \ +static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALsizei numchans, \ + ALsizei len, ALsizei UNUSED(align)) \ { \ - ALuint i, j; \ + ALsizei i; \ + len *= numchans; \ for(i = 0;i < len;i++) \ - { \ - for(j = 0;j < numchans;j++) \ - *(dst++) = Conv_##T1##_##T2(*(src++)); \ - } \ + *(dst++) = Conv_##T1##_##T2(*(src++)); \ } #define DECL_TEMPLATE2(T) \ @@ -670,12 +668,12 @@ DECL_TEMPLATE2(ALalaw) #undef DECL_TEMPLATE #define DECL_TEMPLATE(T) \ -static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \ - ALuint len, ALuint align) \ +static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALsizei numchans, \ + ALsizei len, ALsizei align) \ { \ ALsizei byte_align = ((align-1)/2 + 4) * numchans; \ DECL_VLA(ALshort, tmp, align*numchans); \ - ALuint i, j, k; \ + ALsizei i, j, k; \ \ assert(align > 0 && (len%align) == 0); \ for(i = 0;i < len;i += align) \ @@ -693,11 +691,11 @@ static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) -static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALuint numchans, - ALuint len, ALuint align) +static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numchans, + ALsizei len, ALsizei align) { ALsizei byte_align = ((align-1)/2 + 4) * numchans; - ALuint i; + ALsizei i; assert(align > 0 && (len%align) == 0); for(i = 0;i < len;i += align) @@ -718,14 +716,14 @@ DECL_TEMPLATE(ALalaw) #undef DECL_TEMPLATE #define DECL_TEMPLATE(T) \ -static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \ - ALuint len, ALuint align) \ +static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALsizei numchans, \ + ALsizei len, ALsizei align) \ { \ ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ ALsizei byte_align = ((align-1)/2 + 4) * numchans; \ DECL_VLA(ALshort, tmp, align*numchans); \ - ALuint i, j, k; \ + ALsizei i, j, k; \ \ assert(align > 0 && (len%align) == 0); \ for(i = 0;i < len;i += align) \ @@ -743,12 +741,12 @@ static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src, - ALuint numchans, ALuint len, ALuint align) + ALsizei numchans, ALsizei len, ALsizei align) { ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; ALsizei byte_align = ((align-1)/2 + 4) * numchans; - ALuint i; + ALsizei i; assert(align > 0 && (len%align) == 0); for(i = 0;i < len;i += align) @@ -771,12 +769,12 @@ DECL_TEMPLATE(ALalaw) #define DECL_TEMPLATE(T) \ static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \ - ALuint numchans, ALuint len, \ - ALuint align) \ + ALsizei numchans, ALsizei len, \ + ALsizei align) \ { \ ALsizei byte_align = ((align-2)/2 + 7) * numchans; \ DECL_VLA(ALshort, tmp, align*numchans); \ - ALuint i, j, k; \ + ALsizei i, j, k; \ \ assert(align > 1 && (len%align) == 0); \ for(i = 0;i < len;i += align) \ @@ -795,11 +793,11 @@ static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, - ALuint numchans, ALuint len, - ALuint align) + ALsizei numchans, ALsizei len, + ALsizei align) { ALsizei byte_align = ((align-2)/2 + 7) * numchans; - ALuint i; + ALsizei i; assert(align > 1 && (len%align) == 0); for(i = 0;i < len;i += align) @@ -821,12 +819,13 @@ DECL_TEMPLATE(ALalaw) #define DECL_TEMPLATE(T) \ static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \ - ALuint numchans, ALuint len, ALuint align) \ + ALsizei numchans, ALsizei len, \ + ALsizei align) \ { \ ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ ALsizei byte_align = ((align-2)/2 + 7) * numchans; \ DECL_VLA(ALshort, tmp, align*numchans); \ - ALuint i, j, k; \ + ALsizei i, j, k; \ \ assert(align > 1 && (len%align) == 0); \ for(i = 0;i < len;i += align) \ @@ -844,11 +843,11 @@ static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src, - ALuint numchans, ALuint len, ALuint align) + ALsizei numchans, ALsizei len, ALsizei align) { ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; ALsizei byte_align = ((align-2)/2 + 7) * numchans; - ALuint i; + ALsizei i; assert(align > 1 && (len%align) == 0); for(i = 0;i < len;i += align) @@ -871,29 +870,29 @@ DECL_TEMPLATE(ALalaw) /* NOTE: We don't store compressed samples internally, so these conversions * should never happen. */ static void Convert_ALima4_ALima4(ALima4* UNUSED(dst), const ALima4* UNUSED(src), - ALuint UNUSED(numchans), ALuint UNUSED(len), - ALuint UNUSED(align)) + ALsizei UNUSED(numchans), ALsizei UNUSED(len), + ALsizei UNUSED(align)) { ERR("Unexpected IMA4-to-IMA4 conversion!\n"); } static void Convert_ALmsadpcm_ALmsadpcm(ALmsadpcm* UNUSED(dst), const ALmsadpcm* UNUSED(src), - ALuint UNUSED(numchans), ALuint UNUSED(len), - ALuint UNUSED(align)) + ALsizei UNUSED(numchans), ALsizei UNUSED(len), + ALsizei UNUSED(align)) { ERR("Unexpected MSADPCM-to-MSADPCM conversion!\n"); } static void Convert_ALmsadpcm_ALima4(ALmsadpcm* UNUSED(dst), const ALima4* UNUSED(src), - ALuint UNUSED(numchans), ALuint UNUSED(len), - ALuint UNUSED(align)) + ALsizei UNUSED(numchans), ALsizei UNUSED(len), + ALsizei UNUSED(align)) { ERR("Unexpected IMA4-to-MSADPCM conversion!\n"); } static void Convert_ALima4_ALmsadpcm(ALima4* UNUSED(dst), const ALmsadpcm* UNUSED(src), - ALuint UNUSED(numchans), ALuint UNUSED(len), - ALuint UNUSED(align)) + ALsizei UNUSED(numchans), ALsizei UNUSED(len), + ALsizei UNUSED(align)) { ERR("Unexpected MSADPCM-to-IMA4 conversion!\n"); } @@ -960,7 +959,8 @@ DECL_TEMPLATE(ALmsadpcm) #undef DECL_TEMPLATE -void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align) +void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, + enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align) { switch(dstType) { -- cgit v1.2.3 From 14a0df03e859882c421d4069fe41c72322466602 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 08:49:15 -0800 Subject: Do more samples at once with the distortion effect --- Alc/effects/distortion.c | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 837e4d3b..8fba07df 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -41,6 +41,8 @@ typedef struct ALdistortionState { ALfilterState bandpass; ALfloat attenuation; ALfloat edge_coeff; + + ALfloat Buffer[2][BUFFERSIZE]; } ALdistortionState; static ALvoid ALdistortionState_Destruct(ALdistortionState *state); @@ -106,73 +108,67 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { + ALfloat (*restrict buffer)[BUFFERSIZE] = state->Buffer; const ALfloat fc = state->edge_coeff; - ALsizei it, kt; ALsizei base; + ALsizei i, k; for(base = 0;base < SamplesToDo;) { - float buffer[2][64 * 4]; - ALsizei td = mini(64, SamplesToDo-base); - /* 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. */ + ALsizei todo = mini(BUFFERSIZE, (SamplesToDo-base) * 4); - /* Fill oversample buffer using zero stuffing. */ - for(it = 0;it < td;it++) - { - /* Multiply the sample by the amount of oversampling to maintain - * the signal's power. - */ - buffer[0][it*4 + 0] = SamplesIn[0][it+base] * 4.0f; - buffer[0][it*4 + 1] = 0.0f; - buffer[0][it*4 + 2] = 0.0f; - buffer[0][it*4 + 3] = 0.0f; - } + /* Fill oversample buffer using zero stuffing. Multiply the sample by + * the amount of oversampling to maintain the signal's power. + */ + for(i = 0;i < todo;i++) + buffer[0][i] = !(i&3) ? SamplesIn[0][(i>>2)+base] * 4.0f : 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. */ - ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4); + ALfilterState_process(&state->lowpass, buffer[1], buffer[0], todo); /* 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(it = 0;it < td*4;it++) + for(i = 0;i < todo;i++) { - ALfloat smp = buffer[1][it]; + ALfloat smp = buffer[1][i]; 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)); - buffer[0][it] = smp; + buffer[0][i] = smp; } /* Third step, do bandpass filtering of distorted signal. */ - ALfilterState_process(&state->bandpass, buffer[1], buffer[0], td*4); + ALfilterState_process(&state->bandpass, buffer[1], buffer[0], todo); - for(kt = 0;kt < NumChannels;kt++) + todo >>= 2; + for(k = 0;k < NumChannels;k++) { /* Fourth step, final, do attenuation and perform decimation, * storing only one sample out of four. */ - ALfloat gain = state->Gain[kt]; + ALfloat gain = state->Gain[k]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * buffer[1][it*4]; + for(i = 0;i < todo;i++) + SamplesOut[k][base+i] += gain * buffer[1][i*4]; } - base += td; + base += todo; } } -- cgit v1.2.3 From 5deb1df8dbc4c9484cdd424aa2f9a1e964937834 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 09:39:28 -0800 Subject: Add min/max/clamp functions for size_t --- Alc/ALu.c | 4 ++++ OpenAL32/Include/alu.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/Alc/ALu.c b/Alc/ALu.c index 04227ce4..909c689a 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -71,6 +71,10 @@ 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 size_t minz(size_t a, size_t b); +extern inline size_t maxz(size_t a, size_t b); +extern inline size_t clampz(size_t val, size_t min, size_t max); + extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); extern inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index e450d68e..a6e0efa8 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -385,6 +385,13 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b) inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) { return minu64(max, maxu64(min, val)); } +inline size_t minz(size_t a, size_t b) +{ return ((a > b) ? b : a); } +inline size_t maxz(size_t a, size_t b) +{ return ((a > b) ? a : b); } +inline size_t clampz(size_t val, size_t min, size_t max) +{ return minz(max, maxz(min, val)); } + inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) { -- cgit v1.2.3 From 8c19497340951aceb88d4f91038cafece6f00d7c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 09:40:34 -0800 Subject: Properly cast some parameters for MSVC --- Alc/backends/mmdevapi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 670d1561..55d8ec54 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1374,7 +1374,7 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) ALsizei srcframes = numsamples; dstframes = SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[0].buf, data[0].len + &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) ); if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) { @@ -1383,16 +1383,16 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) * dest block, do another run for the second block. */ dstframes += SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[1].buf, data[1].len + &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) ); } } else { - size_t framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, + ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - ALuint len1 = minu(data[0].len, numsamples); - ALuint len2 = minu(data[1].len, numsamples-len1); + size_t len1 = minz(data[0].len, numsamples); + size_t len2 = minz(data[1].len, numsamples-len1); memcpy(data[0].buf, rdata, len1*framesize); if(len2 > 0) -- cgit v1.2.3 From e80b016cbedd500bec7119005537bdc92231e667 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 12:18:59 -0800 Subject: Use a global RowMixerFunc --- Alc/bformatdec.c | 25 ++++++------------------- Alc/effects/reverb.c | 10 ---------- Alc/mixer.c | 4 +++- OpenAL32/Include/alu.h | 2 +- 4 files changed, 10 insertions(+), 31 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index ae1f7381..0e79fd3f 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -185,17 +185,6 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { }; -static RowMixerFunc MixMatrixRow = MixRow_C; - - -static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT; - -static void init_bformatdec(void) -{ - MixMatrixRow = SelectRowMixer(); -} - - /* NOTE: BandSplitter filters are unused with single-band decoding */ typedef struct BFormatDec { ALboolean Enabled[MAX_OUTPUT_CHANNELS]; @@ -225,7 +214,6 @@ typedef struct BFormatDec { BFormatDec *bformatdec_alloc() { - alcall_once(&bformatdec_inited, init_bformatdec); return al_calloc(16, sizeof(BFormatDec)); } @@ -432,10 +420,10 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], dec->SamplesHF, dec->NumChannels, 0, SamplesToDo ); - MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], dec->SamplesLF, dec->NumChannels, 0, SamplesToDo ); @@ -451,8 +439,8 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, - dec->NumChannels, 0, SamplesToDo); + MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples, + dec->NumChannels, 0, SamplesToDo); for(i = 0;i < SamplesToDo;i++) OutBuffer[chan][i] += dec->ChannelMix[i]; @@ -486,7 +474,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B ); /* Now write each band to the output. */ - MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains, + MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, dec->Samples, FB_Max, 0, SamplesToDo ); } @@ -517,7 +505,6 @@ typedef struct AmbiUpsampler { AmbiUpsampler *ambiup_alloc() { - alcall_once(&bformatdec_inited, init_bformatdec); return al_calloc(16, sizeof(AmbiUpsampler)); } @@ -601,7 +588,7 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[ ); for(j = 0;j < OutChannels;j++) - MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j], + MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], ambiup->Samples, FB_Max, 0, SamplesToDo ); } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 85f55880..7729caec 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -57,14 +57,6 @@ ALfloat ReverbBoost = 1.0f; #define NUM_LINES 4 -static RowMixerFunc MixRowSamples = MixRow_C; - -static alonce_flag mixfunc_inited = AL_ONCE_FLAG_INIT; -static void init_mixfunc(void) -{ - MixRowSamples = SelectRowMixer(); -} - /* The B-Format to A-Format conversion matrix. The arrangement of rows is * deliberately chosen to align the resulting lines to their spatial opposites * (0:above front left <-> 3:above back right, 1:below front right <-> 2:below @@ -1760,8 +1752,6 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f { ALreverbState *state; - alcall_once(&mixfunc_inited, init_mixfunc); - NEW_OBJ0(state, ALreverbState)(); if(!state) return NULL; diff --git a/Alc/mixer.c b/Alc/mixer.c index 76e5f759..a63bd909 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -53,6 +53,7 @@ static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least enum Resampler ResamplerDefault = LinearResampler; MixerFunc MixSamples = Mix_C; +RowMixerFunc MixRowSamples = MixRow_C; static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; @@ -69,7 +70,7 @@ static MixerFunc SelectMixer(void) return Mix_C; } -RowMixerFunc SelectRowMixer(void) +static RowMixerFunc SelectRowMixer(void) { #ifdef HAVE_NEON if((CPUCapFlags&CPU_CAP_NEON)) @@ -187,6 +188,7 @@ void aluInitMixer(void) MixHrtfBlendSamples = SelectHrtfBlendMixer(); MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a6e0efa8..f6462cd4 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -418,7 +418,6 @@ void aluInit(void); void aluInitMixer(void); -RowMixerFunc SelectRowMixer(void); ResamplerFunc SelectResampler(enum Resampler resampler); /* aluInitRenderer @@ -526,6 +525,7 @@ void aluHandleDisconnect(ALCdevice *device); void UpdateContextProps(ALCcontext *context); extern MixerFunc MixSamples; +extern RowMixerFunc MixRowSamples; extern ALfloat ConeScale; extern ALfloat ZScale; -- cgit v1.2.3 From 273dca2fa0fc4b009735010fd42c2c53649f872c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 12:54:20 -0800 Subject: Avoid using alloca in the CoreAudio backend --- Alc/backends/coreaudio.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index ba73ab82..2ee3fa54 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "alMain.h" #include "alu.h" @@ -725,27 +724,26 @@ static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self) static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples) { - AudioBufferList *list; + union { + ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)]; + AudioBufferList list; + } audiobuf = { { 0 } }; UInt32 frameCount; OSStatus err; // If no samples are requested, just return - if(samples == 0) - return ALC_NO_ERROR; - - // Allocate a temporary AudioBufferList to use as the return resamples data - list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer)); + if(samples == 0) return ALC_NO_ERROR; // Point the resampling buffer to the capture buffer - list->mNumberBuffers = 1; - list->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; - list->mBuffers[0].mDataByteSize = samples * self->frameSize; - list->mBuffers[0].mData = buffer; + audiobuf.list.mNumberBuffers = 1; + audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame; + audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize; + audiobuf.list.mBuffers[0].mData = buffer; // Resample into another AudioBufferList frameCount = samples; err = AudioConverterFillComplexBuffer(self->audioConverter, - ALCcoreAudioCapture_ConvertCallback, self, &frameCount, list, NULL + ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL ); if(err != noErr) { -- cgit v1.2.3 From bf8c889631f48f9112987eb0f26e7c6eaa2429aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 12:57:06 -0800 Subject: Define DECL_VLA where it's used --- OpenAL32/Include/alMain.h | 6 ------ OpenAL32/sample_cvt.c | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4f6d0b49..c9439770 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -173,12 +173,6 @@ typedef ALuint64SOFT ALuint64; */ #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) -#ifdef HAVE_C99_VLA -#define DECL_VLA(T, _name, _size) T _name[(_size)] -#else -#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T)) -#endif - static const union { ALuint u; diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 58cad523..535d8b6d 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -15,6 +15,13 @@ #include "alBuffer.h" +#ifdef HAVE_C99_VLA +#define DECL_VLA(T, _name, _size) T _name[(_size)] +#else +#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T)) +#endif + + /* IMA ADPCM Stepsize table */ static const int IMAStep_size[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, -- cgit v1.2.3 From 248832b26680de4ce48bf17076287a07dbd36ff7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 18:07:59 -0800 Subject: Use a voice flag to indicate it being static --- Alc/ALu.c | 2 +- Alc/mixer.c | 4 ++-- OpenAL32/Include/alu.h | 10 +++++----- OpenAL32/alSource.c | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 909c689a..d190a1be 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1693,7 +1693,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) && voice->Step > 0) { - if(!MixSource(voice, source, device, SamplesToDo)) + if(!MixSource(voice, device, SamplesToDo)) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); diff --git a/Alc/mixer.c b/Alc/mixer.c index a63bd909..8f946f6d 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -276,7 +276,7 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter #define RESAMPLED_BUF 1 #define FILTERED_BUF 2 #define NFC_DATA_BUF 3 -ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo) +ALboolean MixSource(ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo) { ALbufferlistitem *BufferListItem; ALbufferlistitem *BufferLoopItem; @@ -297,7 +297,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei /* Get source info */ isplaying = true; /* Will only be called while playing. */ - isstatic = Source->SourceType == AL_STATIC; + isstatic = !!(voice->Flags&VOICE_IS_STATIC); DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index f6462cd4..21390806 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -236,10 +236,10 @@ struct ALvoiceProps { } Send[]; }; -/* If not 'fading', gain targets are used directly without fading. */ -#define VOICE_IS_FADING (1<<0) -#define VOICE_HAS_HRTF (1<<1) -#define VOICE_HAS_NFC (1<<2) +#define VOICE_IS_STATIC (1<<0) +#define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */ +#define VOICE_HAS_HRTF (1<<2) +#define VOICE_HAS_NFC (1<<3) typedef struct ALvoice { struct ALvoiceProps *Props; @@ -516,7 +516,7 @@ inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], } -ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo); +ALboolean MixSource(struct ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device. */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f4d82c68..83233b3f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2623,6 +2623,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Step = 0; voice->Flags = start_fading ? VOICE_IS_FADING : 0; + if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); for(s = 0;s < device->NumAuxSends;s++) memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels); -- cgit v1.2.3 From 3baf9d0e81c16555fc417697a5445b7cd674db02 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jan 2018 19:24:14 -0800 Subject: Add a method to get the system's page size --- CMakeLists.txt | 1 + common/almalloc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ common/almalloc.h | 9 +++++++++ config.h.in | 3 +++ 4 files changed, 61 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b07f4ea..dd371f70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -499,6 +499,7 @@ IF(HAVE_INTRIN_H) }" HAVE_CPUID_INTRINSIC) ENDIF() +CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) diff --git a/common/almalloc.c b/common/almalloc.c index 8c1c5794..0d982ca1 100644 --- a/common/almalloc.c +++ b/common/almalloc.c @@ -10,8 +10,20 @@ #endif #ifdef HAVE_WINDOWS_H #include +#else +#include +#endif + + +#ifdef __GNUC__ +#define LIKELY(x) __builtin_expect(!!(x), !0) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define LIKELY(x) (!!(x)) +#define UNLIKELY(x) (!!(x)) #endif + void *al_malloc(size_t alignment, size_t size) { #if defined(HAVE_ALIGNED_ALLOC) @@ -60,3 +72,39 @@ void al_free(void *ptr) } #endif } + +size_t al_get_page_size(void) +{ + static size_t psize = 0; + if(UNLIKELY(!psize)) + { +#ifdef HAVE_SYSCONF +#if defined(_SC_PAGESIZE) + if(!psize) psize = sysconf(_SC_PAGESIZE); +#elif defined(_SC_PAGE_SIZE) + if(!psize) psize = sysconf(_SC_PAGE_SIZE); +#endif +#endif /* HAVE_SYSCONF */ +#ifdef _WIN32 + if(!psize) + { + SYSTEM_INFO sysinfo; + memset(&sysinfo, 0, sizeof(sysinfo)); + + GetSystemInfo(&sysinfo); + psize = sysinfo.dwPageSize; + } +#endif + if(!psize) psize = DEF_ALIGN; + } + return psize; +} + +int al_is_sane_alignment_allocator(void) +{ +#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC) + return 1; +#else + return 0; +#endif +} diff --git a/common/almalloc.h b/common/almalloc.h index 8eadb5b3..a4297cf5 100644 --- a/common/almalloc.h +++ b/common/almalloc.h @@ -14,6 +14,15 @@ void *al_malloc(size_t alignment, size_t size); void *al_calloc(size_t alignment, size_t size); void al_free(void *ptr); +size_t al_get_page_size(void); + +/** + * Returns non-0 if the allocation function has direct alignment handling. + * Otherwise, the standard malloc is used with an over-allocation and pointer + * offset strategy. + */ +int al_is_sane_alignment_allocator(void); + #ifdef __cplusplus } #endif diff --git a/config.h.in b/config.h.in index 22c3b1c7..0bee5c98 100644 --- a/config.h.in +++ b/config.h.in @@ -11,6 +11,9 @@ /* Define if HRTF data is embedded in the library */ #cmakedefine ALSOFT_EMBED_HRTF_DATA +/* Define if we have the sysconf function */ +#cmakedefine HAVE_SYSCONF + /* Define if we have the C11 aligned_alloc function */ #cmakedefine HAVE_ALIGNED_ALLOC -- cgit v1.2.3 From 884fe40fd1262fe642a86d29f27e157e2b562212 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 17 Jan 2018 08:49:49 -0800 Subject: Store mulaw and alaw samples directly in the buffer They're now decompressed on the fly in the mixer. This is not a significant performance issue given that it only needs a 512-byte lookup table, and the buffer stores half as much data (it may actually be faster, requiring less overall memory). --- Alc/mixer.c | 27 ++++++++++++++++++--------- OpenAL32/Include/alBuffer.h | 2 ++ OpenAL32/Include/sample_cvt.h | 3 +++ OpenAL32/alBuffer.c | 39 +++++++++++++++------------------------ OpenAL32/sample_cvt.c | 4 ++-- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 8f946f6d..d1796da8 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -33,6 +33,7 @@ #include "alBuffer.h" #include "alListener.h" #include "alAuxEffectSlot.h" +#include "sample_cvt.h" #include "alu.h" #include "alconfig.h" @@ -201,6 +202,14 @@ static inline ALfloat Sample_ALshort(ALshort val) static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } +typedef ALubyte ALmulaw; +static inline ALfloat Sample_ALmulaw(ALmulaw val) +{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } + +typedef ALubyte ALalaw; +static inline ALfloat Sample_ALalaw(ALalaw val) +{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } + #define DECL_TEMPLATE(T) \ static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ ALint srcstep, ALsizei samples) \ @@ -213,24 +222,24 @@ static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALshort) DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) #undef DECL_TEMPLATE static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep, enum FmtType srctype, ALsizei samples) { +#define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break switch(srctype) { - case FmtByte: - Load_ALbyte(dst, src, srcstep, samples); - break; - case FmtShort: - Load_ALshort(dst, src, srcstep, samples); - break; - case FmtFloat: - Load_ALfloat(dst, src, srcstep, samples); - break; + HANDLE_FMT(FmtByte, ALbyte); + HANDLE_FMT(FmtShort, ALshort); + HANDLE_FMT(FmtFloat, ALfloat); + HANDLE_FMT(FmtMulaw, ALmulaw); + HANDLE_FMT(FmtAlaw, ALalaw); } +#undef HANDLE_FMT } diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index b13e1231..7653db6a 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -47,6 +47,8 @@ enum FmtType { FmtByte = UserFmtByte, FmtShort = UserFmtShort, FmtFloat = UserFmtFloat, + FmtMulaw = UserFmtMulaw, + FmtAlaw = UserFmtAlaw, }; enum FmtChannels { FmtMono = UserFmtMono, diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h index 12bb1fa6..35ead20c 100644 --- a/OpenAL32/Include/sample_cvt.h +++ b/OpenAL32/Include/sample_cvt.h @@ -4,6 +4,9 @@ #include "AL/al.h" #include "alBuffer.h" +extern const ALshort muLawDecompressionTable[256]; +extern const ALshort aLawDecompressionTable[256]; + void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align); #endif /* SAMPLE_CVT_H */ diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 376741bd..a4b19a95 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -171,6 +171,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtShort: case UserFmtUShort: case UserFmtFloat: + case UserFmtMulaw: + case UserFmtAlaw: framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; if((size%framesize) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -206,30 +208,6 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, err, done); break; - case UserFmtMulaw: - case UserFmtAlaw: - framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; - if((size%framesize) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - 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; - case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; - case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; - } - err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, AL_TRUE); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); - break; - case UserFmtIMA4: framesize = (align-1)/2 + 4; framesize *= ChannelsFromUserFmt(srcchannels); @@ -1193,6 +1171,8 @@ ALsizei BytesFromFmt(enum FmtType type) case FmtByte: return sizeof(ALbyte); case FmtShort: return sizeof(ALshort); case FmtFloat: return sizeof(ALfloat); + case FmtMulaw: return sizeof(ALubyte); + case FmtAlaw: return sizeof(ALubyte); } return 0; } @@ -1222,14 +1202,19 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm { AL_MONO8_SOFT, FmtMono, FmtByte }, { AL_MONO16_SOFT, FmtMono, FmtShort }, { AL_MONO32F_SOFT, FmtMono, FmtFloat }, + { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, { AL_STEREO8_SOFT, FmtStereo, FmtByte }, { AL_STEREO16_SOFT, FmtStereo, FmtShort }, { AL_STEREO32F_SOFT, FmtStereo, FmtFloat }, + { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, { AL_REAR8_SOFT, FmtRear, FmtByte }, { AL_REAR16_SOFT, FmtRear, FmtShort }, { AL_REAR32F_SOFT, FmtRear, FmtFloat }, + { AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw }, { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte }, { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, @@ -1237,26 +1222,32 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm { AL_QUAD8_SOFT, FmtQuad, FmtByte }, { AL_QUAD16_SOFT, FmtQuad, FmtShort }, { AL_QUAD32F_SOFT, FmtQuad, FmtFloat }, + { AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw }, { AL_5POINT1_8_SOFT, FmtX51, FmtByte }, { AL_5POINT1_16_SOFT, FmtX51, FmtShort }, { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat }, + { AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw }, { AL_6POINT1_8_SOFT, FmtX61, FmtByte }, { AL_6POINT1_16_SOFT, FmtX61, FmtShort }, { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat }, + { AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw }, { AL_7POINT1_8_SOFT, FmtX71, FmtByte }, { AL_7POINT1_16_SOFT, FmtX71, FmtShort }, { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat }, + { AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw }, { AL_BFORMAT2D_8_SOFT, FmtBFormat2D, FmtByte }, { AL_BFORMAT2D_16_SOFT, FmtBFormat2D, FmtShort }, { AL_BFORMAT2D_32F_SOFT, FmtBFormat2D, FmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, { AL_BFORMAT3D_8_SOFT, FmtBFormat3D, FmtByte }, { AL_BFORMAT3D_16_SOFT, FmtBFormat3D, FmtShort }, { AL_BFORMAT3D_32F_SOFT, FmtBFormat3D, FmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, }; ALuint i; diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 535d8b6d..af73695b 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -68,7 +68,7 @@ static const int MSADPCMAdaptionCoeff[7][2] = { /* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a * signed 16-bit sample */ -static const ALshort muLawDecompressionTable[256] = { +const ALshort muLawDecompressionTable[256] = { -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, @@ -128,7 +128,7 @@ static const char muLawCompressTable[256] = { /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a * signed 16-bit sample */ -static const ALshort aLawDecompressionTable[256] = { +const ALshort aLawDecompressionTable[256] = { -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -- cgit v1.2.3 From 2102625021112b8bccc34cafb1f189f75b889d61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 17 Jan 2018 18:03:31 -0800 Subject: Reformat the format array --- OpenAL32/alBuffer.c | 72 ++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index a4b19a95..6dda6738 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1199,57 +1199,57 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm enum FmtChannels channels; enum FmtType type; } list[] = { - { AL_MONO8_SOFT, FmtMono, FmtByte }, - { AL_MONO16_SOFT, FmtMono, FmtShort }, - { AL_MONO32F_SOFT, FmtMono, FmtFloat }, - { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, - - { AL_STEREO8_SOFT, FmtStereo, FmtByte }, - { AL_STEREO16_SOFT, FmtStereo, FmtShort }, - { AL_STEREO32F_SOFT, FmtStereo, FmtFloat }, - { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, - - { AL_REAR8_SOFT, FmtRear, FmtByte }, - { AL_REAR16_SOFT, FmtRear, FmtShort }, - { AL_REAR32F_SOFT, FmtRear, FmtFloat }, + { AL_FORMAT_MONO8, FmtMono, FmtByte }, + { AL_FORMAT_MONO16, FmtMono, FmtShort }, + { AL_FORMAT_MONO_FLOAT32, FmtMono, FmtFloat }, + { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, + + { AL_FORMAT_STEREO8, FmtStereo, FmtByte }, + { AL_FORMAT_STEREO16, FmtStereo, FmtShort }, + { AL_FORMAT_STEREO_FLOAT32, FmtStereo, FmtFloat }, + { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, + + { AL_FORMAT_REAR8, FmtRear, FmtByte }, + { AL_FORMAT_REAR16, FmtRear, FmtShort }, + { AL_FORMAT_REAR32, FmtRear, FmtFloat }, { AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw }, { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte }, { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, - { AL_QUAD8_SOFT, FmtQuad, FmtByte }, - { AL_QUAD16_SOFT, FmtQuad, FmtShort }, - { AL_QUAD32F_SOFT, FmtQuad, FmtFloat }, + { AL_FORMAT_QUAD8, FmtQuad, FmtByte }, + { AL_FORMAT_QUAD16, FmtQuad, FmtShort }, + { AL_FORMAT_QUAD32, FmtQuad, FmtFloat }, { AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw }, - { AL_5POINT1_8_SOFT, FmtX51, FmtByte }, - { AL_5POINT1_16_SOFT, FmtX51, FmtShort }, - { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat }, + { AL_FORMAT_51CHN8, FmtX51, FmtByte }, + { AL_FORMAT_51CHN16, FmtX51, FmtShort }, + { AL_FORMAT_51CHN32, FmtX51, FmtFloat }, { AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw }, - { AL_6POINT1_8_SOFT, FmtX61, FmtByte }, - { AL_6POINT1_16_SOFT, FmtX61, FmtShort }, - { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat }, + { AL_FORMAT_61CHN8, FmtX61, FmtByte }, + { AL_FORMAT_61CHN16, FmtX61, FmtShort }, + { AL_FORMAT_61CHN32, FmtX61, FmtFloat }, { AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw }, - { AL_7POINT1_8_SOFT, FmtX71, FmtByte }, - { AL_7POINT1_16_SOFT, FmtX71, FmtShort }, - { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat }, + { AL_FORMAT_71CHN8, FmtX71, FmtByte }, + { AL_FORMAT_71CHN16, FmtX71, FmtShort }, + { AL_FORMAT_71CHN32, FmtX71, FmtFloat }, { AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw }, - { AL_BFORMAT2D_8_SOFT, FmtBFormat2D, FmtByte }, - { AL_BFORMAT2D_16_SOFT, FmtBFormat2D, FmtShort }, - { AL_BFORMAT2D_32F_SOFT, FmtBFormat2D, FmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, + { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte }, + { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, - { AL_BFORMAT3D_8_SOFT, FmtBFormat3D, FmtByte }, - { AL_BFORMAT3D_16_SOFT, FmtBFormat3D, FmtShort }, - { AL_BFORMAT3D_32F_SOFT, FmtBFormat3D, FmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, + { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte }, + { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, }; - ALuint i; + size_t i; for(i = 0;i < COUNTOF(list);i++) { -- cgit v1.2.3 From b56673bbce948b7ea6a79261934abc940119a20a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 17 Jan 2018 18:34:13 -0800 Subject: Make a function static that's only used in one source file --- OpenAL32/Include/alBuffer.h | 2 -- OpenAL32/alBuffer.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 7653db6a..5abee8c6 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -105,8 +105,6 @@ typedef struct ALbuffer { ALbuffer *NewBuffer(ALCcontext *context); void DeleteBuffer(ALCdevice *device, ALbuffer *buffer); -ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc); - inline void LockBuffersRead(ALCdevice *device) { LockUIntMapRead(&device->BufferMap); } inline void UnlockBuffersRead(ALCdevice *device) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 6dda6738..de49d948 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,6 +45,7 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); +static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc); static ALboolean IsValidType(ALenum type); static ALboolean IsValidChannels(ALenum channels); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); @@ -955,7 +956,7 @@ done: * Currently, the new format must have the same channel configuration as the * original format. */ -ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc) +static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc) { enum FmtChannels DstChannels = FmtMono; enum FmtType DstType = FmtByte; -- cgit v1.2.3 From 940c6146e832b2226876f3d8fdc3369974ed16e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Jan 2018 19:28:23 -0800 Subject: Remove unnecessary private AL_SOFT_buffer_samples2 definitions --- Alc/ALc.c | 9 ------ OpenAL32/Include/alBuffer.h | 8 ++--- OpenAL32/Include/alMain.h | 73 --------------------------------------------- OpenAL32/alBuffer.c | 3 -- 4 files changed, 4 insertions(+), 89 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 71db5e0f..9a494c36 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -493,12 +493,6 @@ static const struct { DECL(AL_7POINT1_8_SOFT), DECL(AL_7POINT1_16_SOFT), DECL(AL_7POINT1_32F_SOFT), - DECL(AL_BFORMAT2D_8_SOFT), - DECL(AL_BFORMAT2D_16_SOFT), - DECL(AL_BFORMAT2D_32F_SOFT), - DECL(AL_BFORMAT3D_8_SOFT), - DECL(AL_BFORMAT3D_16_SOFT), - DECL(AL_BFORMAT3D_32F_SOFT), DECL(AL_MONO_SOFT), DECL(AL_STEREO_SOFT), @@ -507,8 +501,6 @@ static const struct { DECL(AL_5POINT1_SOFT), DECL(AL_6POINT1_SOFT), DECL(AL_7POINT1_SOFT), - DECL(AL_BFORMAT2D_SOFT), - DECL(AL_BFORMAT3D_SOFT), DECL(AL_BYTE_SOFT), DECL(AL_UNSIGNED_BYTE_SOFT), @@ -520,7 +512,6 @@ static const struct { DECL(AL_DOUBLE_SOFT), DECL(AL_BYTE3_SOFT), DECL(AL_UNSIGNED_BYTE3_SOFT), - DECL(AL_MULAW_SOFT), DECL(AL_FREQUENCY), DECL(AL_BITS), diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 5abee8c6..0f39dfae 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -17,8 +17,8 @@ enum UserFmtType { UserFmtUInt = AL_UNSIGNED_INT_SOFT, UserFmtFloat = AL_FLOAT_SOFT, UserFmtDouble = AL_DOUBLE_SOFT, - UserFmtMulaw = AL_MULAW_SOFT, - UserFmtAlaw = 0x10000000, + UserFmtMulaw = 0x10000000, + UserFmtAlaw, UserFmtIMA4, UserFmtMSADPCM, }; @@ -30,8 +30,8 @@ enum UserFmtChannels { UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ - UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */ - UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */ + UserFmtBFormat2D = 0x20000000, /* WXY */ + UserFmtBFormat3D, /* WXYZ */ }; ALsizei BytesFromUserFmt(enum UserFmtType type); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c9439770..50c9decf 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -47,79 +47,6 @@ #define ALC_N3D_SOFT 0xfff7 #endif -#ifndef AL_SOFT_buffer_samples2 -#define AL_SOFT_buffer_samples2 1 -/* Channel configurations */ -#define AL_MONO_SOFT 0x1500 -#define AL_STEREO_SOFT 0x1501 -#define AL_REAR_SOFT 0x1502 -#define AL_QUAD_SOFT 0x1503 -#define AL_5POINT1_SOFT 0x1504 -#define AL_6POINT1_SOFT 0x1505 -#define AL_7POINT1_SOFT 0x1506 -#define AL_BFORMAT2D_SOFT 0x1507 -#define AL_BFORMAT3D_SOFT 0x1508 - -/* Sample types */ -#define AL_BYTE_SOFT 0x1400 -#define AL_UNSIGNED_BYTE_SOFT 0x1401 -#define AL_SHORT_SOFT 0x1402 -#define AL_UNSIGNED_SHORT_SOFT 0x1403 -#define AL_INT_SOFT 0x1404 -#define AL_UNSIGNED_INT_SOFT 0x1405 -#define AL_FLOAT_SOFT 0x1406 -#define AL_DOUBLE_SOFT 0x1407 -#define AL_BYTE3_SOFT 0x1408 -#define AL_UNSIGNED_BYTE3_SOFT 0x1409 -#define AL_MULAW_SOFT 0x140A - -/* Storage formats */ -#define AL_MONO8_SOFT 0x1100 -#define AL_MONO16_SOFT 0x1101 -#define AL_MONO32F_SOFT 0x10010 -#define AL_STEREO8_SOFT 0x1102 -#define AL_STEREO16_SOFT 0x1103 -#define AL_STEREO32F_SOFT 0x10011 -#define AL_QUAD8_SOFT 0x1204 -#define AL_QUAD16_SOFT 0x1205 -#define AL_QUAD32F_SOFT 0x1206 -#define AL_REAR8_SOFT 0x1207 -#define AL_REAR16_SOFT 0x1208 -#define AL_REAR32F_SOFT 0x1209 -#define AL_5POINT1_8_SOFT 0x120A -#define AL_5POINT1_16_SOFT 0x120B -#define AL_5POINT1_32F_SOFT 0x120C -#define AL_6POINT1_8_SOFT 0x120D -#define AL_6POINT1_16_SOFT 0x120E -#define AL_6POINT1_32F_SOFT 0x120F -#define AL_7POINT1_8_SOFT 0x1210 -#define AL_7POINT1_16_SOFT 0x1211 -#define AL_7POINT1_32F_SOFT 0x1212 -#define AL_BFORMAT2D_8_SOFT 0x20021 -#define AL_BFORMAT2D_16_SOFT 0x20022 -#define AL_BFORMAT2D_32F_SOFT 0x20023 -#define AL_BFORMAT3D_8_SOFT 0x20031 -#define AL_BFORMAT3D_16_SOFT 0x20032 -#define AL_BFORMAT3D_32F_SOFT 0x20033 - -/* Buffer attributes */ -#define AL_INTERNAL_FORMAT_SOFT 0x2008 -#define AL_BYTE_LENGTH_SOFT 0x2009 -#define AL_SAMPLE_LENGTH_SOFT 0x200A -#define AL_SEC_LENGTH_SOFT 0x200B - -#if 0 -typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); -typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); -typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); -#endif -#endif -#endif - #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index de49d948..1b15a1b3 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1316,7 +1316,6 @@ static ALboolean IsValidType(ALenum type) case AL_UNSIGNED_INT_SOFT: case AL_FLOAT_SOFT: case AL_DOUBLE_SOFT: - case AL_MULAW_SOFT: return AL_TRUE; } return AL_FALSE; @@ -1333,8 +1332,6 @@ static ALboolean IsValidChannels(ALenum channels) case AL_5POINT1_SOFT: case AL_6POINT1_SOFT: case AL_7POINT1_SOFT: - case AL_BFORMAT2D_SOFT: - case AL_BFORMAT3D_SOFT: return AL_TRUE; } return AL_FALSE; -- cgit v1.2.3 From ab2295b68f19212ce34cf2b56e81ee80186310f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Jan 2018 20:10:31 -0800 Subject: Store 8-bit sample types directly as unsigned byte --- Alc/mixer.c | 8 ++++---- OpenAL32/Include/alBuffer.h | 2 +- OpenAL32/alBuffer.c | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index d1796da8..fe4bcd78 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -193,8 +193,8 @@ void aluInitMixer(void) } -static inline ALfloat Sample_ALbyte(ALbyte val) -{ return val * (1.0f/128.0f); } +static inline ALfloat Sample_ALubyte(ALubyte val) +{ return (val-128) * (1.0f/128.0f); } static inline ALfloat Sample_ALshort(ALshort val) { return val * (1.0f/32768.0f); } @@ -219,7 +219,7 @@ static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ dst[i] += Sample_##T(src[i*srcstep]); \ } -DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALmulaw) @@ -233,7 +233,7 @@ static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint #define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break switch(srctype) { - HANDLE_FMT(FmtByte, ALbyte); + HANDLE_FMT(FmtUByte, ALubyte); HANDLE_FMT(FmtShort, ALshort); HANDLE_FMT(FmtFloat, ALfloat); HANDLE_FMT(FmtMulaw, ALmulaw); diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 0f39dfae..852a8782 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -44,7 +44,7 @@ inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType /* Storable formats */ enum FmtType { - FmtByte = UserFmtByte, + FmtUByte = UserFmtUByte, FmtShort = UserFmtShort, FmtFloat = UserFmtFloat, FmtMulaw = UserFmtMulaw, diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 1b15a1b3..d063b071 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -959,7 +959,7 @@ done: static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc) { enum FmtChannels DstChannels = FmtMono; - enum FmtType DstType = FmtByte; + enum FmtType DstType = FmtUByte; ALuint NewChannels, NewBytes; ALuint64 newsize; @@ -1169,7 +1169,7 @@ ALsizei BytesFromFmt(enum FmtType type) { switch(type) { - case FmtByte: return sizeof(ALbyte); + case FmtUByte: return sizeof(ALubyte); case FmtShort: return sizeof(ALshort); case FmtFloat: return sizeof(ALfloat); case FmtMulaw: return sizeof(ALubyte); @@ -1200,52 +1200,52 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm enum FmtChannels channels; enum FmtType type; } list[] = { - { AL_FORMAT_MONO8, FmtMono, FmtByte }, + { AL_FORMAT_MONO8, FmtMono, FmtUByte }, { AL_FORMAT_MONO16, FmtMono, FmtShort }, { AL_FORMAT_MONO_FLOAT32, FmtMono, FmtFloat }, { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, - { AL_FORMAT_STEREO8, FmtStereo, FmtByte }, + { AL_FORMAT_STEREO8, FmtStereo, FmtUByte }, { AL_FORMAT_STEREO16, FmtStereo, FmtShort }, { AL_FORMAT_STEREO_FLOAT32, FmtStereo, FmtFloat }, { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, - { AL_FORMAT_REAR8, FmtRear, FmtByte }, + { AL_FORMAT_REAR8, FmtRear, FmtUByte }, { AL_FORMAT_REAR16, FmtRear, FmtShort }, { AL_FORMAT_REAR32, FmtRear, FmtFloat }, { AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw }, - { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte }, + { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtUByte }, { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, - { AL_FORMAT_QUAD8, FmtQuad, FmtByte }, + { AL_FORMAT_QUAD8, FmtQuad, FmtUByte }, { AL_FORMAT_QUAD16, FmtQuad, FmtShort }, { AL_FORMAT_QUAD32, FmtQuad, FmtFloat }, { AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw }, - { AL_FORMAT_51CHN8, FmtX51, FmtByte }, + { AL_FORMAT_51CHN8, FmtX51, FmtUByte }, { AL_FORMAT_51CHN16, FmtX51, FmtShort }, { AL_FORMAT_51CHN32, FmtX51, FmtFloat }, { AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw }, - { AL_FORMAT_61CHN8, FmtX61, FmtByte }, + { AL_FORMAT_61CHN8, FmtX61, FmtUByte }, { AL_FORMAT_61CHN16, FmtX61, FmtShort }, { AL_FORMAT_61CHN32, FmtX61, FmtFloat }, { AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw }, - { AL_FORMAT_71CHN8, FmtX71, FmtByte }, + { AL_FORMAT_71CHN8, FmtX71, FmtUByte }, { AL_FORMAT_71CHN16, FmtX71, FmtShort }, { AL_FORMAT_71CHN32, FmtX71, FmtFloat }, { AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw }, - { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte }, + { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtUByte }, { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, - { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte }, + { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtUByte }, { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, -- cgit v1.2.3 From 4e647bda07dd56479ea62de7a53b70c0154734e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Jan 2018 21:00:53 -0800 Subject: Return the effective alignment from SanitizeAlignment --- OpenAL32/alBuffer.c | 54 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index d063b071..ac755688 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -50,7 +50,7 @@ static ALboolean IsValidType(ALenum type); static ALboolean IsValidChannels(ALenum channels); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type); -static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align); +static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) @@ -162,9 +162,9 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - if(SanitizeAlignment(srctype, &align) == AL_FALSE) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); + if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + switch(srctype) { case UserFmtByte: @@ -288,8 +288,8 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - if(SanitizeAlignment(srctype, &align) == AL_FALSE) + align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); + if(align < 1) { WriteUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -367,9 +367,9 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - if(SanitizeAlignment(type, &align) == AL_FALSE) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); + if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if((samples%align) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -405,8 +405,8 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); - if(SanitizeAlignment(type, &align) == AL_FALSE) + align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); + if(align < 1) { WriteUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -460,8 +460,8 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); ReadLock(&albuf->lock); - align = ATOMIC_LOAD_SEQ(&albuf->PackAlign); - if(SanitizeAlignment(type, &align) == AL_FALSE) + align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->PackAlign)); + if(align < 1) { ReadUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); @@ -1265,12 +1265,12 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm return AL_FALSE; } -static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align) +static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) { - if(*align < 0) - return AL_FALSE; + if(align < 0) + return 0; - if(*align == 0) + if(align == 0) { if(type == UserFmtIMA4) { @@ -1278,29 +1278,27 @@ static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align) * 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 */ - *align = 65; + return 65; } - else if(type == UserFmtMSADPCM) - *align = 64; - else - *align = 1; - return AL_TRUE; + if(type == UserFmtMSADPCM) + return 64; + return 1; } if(type == UserFmtIMA4) { /* IMA4 block alignment must be a multiple of 8, plus 1. */ - return ((*align)&7) == 1; + if((align&7) == 1) return align; + return 0; } if(type == UserFmtMSADPCM) { /* MSADPCM block alignment must be a multiple of 2. */ - /* FIXME: Too strict? Might only require align*channels to be a - * multiple of 2. */ - return ((*align)&1) == 0; + if((align&1) == 0) return align; + return 0; } - return AL_TRUE; + return align; } -- cgit v1.2.3 From 03d4e4acc4c55ed87741b2b9960ac1ac3d4cf0bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Jan 2018 11:49:01 -0800 Subject: Add methods to "map" a buffer's storage Requires the MAP_READ_BIT or MAP_WRITE_BIT flags to be OR'd with the format upon a call to alBufferData, to enable mappable storage for the given access types. This will fail if the format requires internal conversion and doesn't resemble the original input data, so the app can be guaranteed the size, type, and layout of the original data is the same as what's in storage. Then alMapBufferSOFT may be called with appropriate bit flags to get a readable and/or writable pointer to the buffer's sample storage. alUnmapBufferSOFT must be called when access is finished. It is currently invalid to map a buffer that is attached to a source, or to attach a buffer to a source that is currently mapped. This restriction may be eased in the future, at least to allow read- only access while in use (perhaps also to allow writing, if coherency can be achieved). Currently the access flags occupy the upper 8 bits of a 32-bit bitfield to avoid clashing with format enum values, which don't use more than 16 or 17 bits. This means any future formats are limited to 24-bit enum values, and also means only 8 flags are possible when declaring storage. The alternative would be to add a new function (alBufferStorage?) with a separate flags parameter. --- OpenAL32/Include/alBuffer.h | 3 ++ OpenAL32/Include/alMain.h | 12 +++++ OpenAL32/alBuffer.c | 121 +++++++++++++++++++++++++++++++++++++++----- OpenAL32/alSource.c | 13 +++++ 4 files changed, 137 insertions(+), 12 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 852a8782..60a047c9 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -76,6 +76,7 @@ typedef struct ALbuffer { ALsizei Frequency; ALenum Format; + ALbitfieldSOFT Access; ALsizei SampleLen; enum FmtChannels FmtChannels; @@ -93,6 +94,8 @@ typedef struct ALbuffer { ATOMIC(ALsizei) UnpackAlign; ATOMIC(ALsizei) PackAlign; + ALbitfieldSOFT MappedAccess; + /* Number of times buffer was attached to a source (deletion can only occur when 0) */ RefCount ref; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 50c9decf..dbb4f14b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -47,6 +47,18 @@ #define ALC_N3D_SOFT 0xfff7 #endif +#ifndef AL_SOFT_map_buffer +typedef unsigned int ALbitfieldSOFT; +#define AL_MAP_READ_BIT_SOFT 0x01000000 +#define AL_MAP_WRITE_BIT_SOFT 0x02000000 +typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +typedef void* (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); +#endif +#endif + #if defined(_WIN64) #define SZFMT "%I64u" diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index ac755688..1c9b2650 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,7 +45,7 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc); +static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access, ALboolean storesrc); static ALboolean IsValidType(ALenum type); static ALboolean IsValidChannels(ALenum channels); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); @@ -53,6 +53,11 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); +#define FORMAT_MASK 0x00ffffff +#define ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) +#define INVALID_FLAG_MASK ~(FORMAT_MASK | ACCESS_FLAGS) + + AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) { ALCcontext *context; @@ -157,9 +162,9 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(size >= 0 && freq > 0)) + if(!(size >= 0 && freq > 0) || (format&INVALID_FLAG_MASK) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) + if(DecomposeUserFormat(format&FORMAT_MASK, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); @@ -178,8 +183,9 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi if((size%framesize) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - err = LoadData(albuf, freq, format, size/framesize*align, - srcchannels, srctype, data, align, AL_TRUE); + err = LoadData(albuf, freq, format&FORMAT_MASK, size/framesize*align, + srcchannels, srctype, data, align, format&ACCESS_FLAGS, + AL_TRUE); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -204,7 +210,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, AL_TRUE); + srcchannels, srctype, data, align, format&ACCESS_FLAGS, + AL_TRUE); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -228,7 +235,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, AL_TRUE); + srcchannels, srctype, data, align, format&ACCESS_FLAGS, + AL_TRUE); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -252,7 +260,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, AL_TRUE); + srcchannels, srctype, data, align, format&ACCESS_FLAGS, + AL_TRUE); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -263,6 +272,80 @@ done: ALCcontext_DecRef(context); } +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access) +{ + void *retval = NULL; + ALCdevice *device; + ALCcontext *context; + ALbuffer *albuf; + + context = GetContextRef(); + if(!context) return retval; + + device = context->Device; + LockBuffersRead(device); + if((albuf=LookupBuffer(device, buffer)) == NULL) + SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + if(!access || (access&~(AL_MAP_READ_BIT_SOFT|AL_MAP_WRITE_BIT_SOFT)) != 0) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&albuf->lock); + if(((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) || + ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT))) + { + WriteUnlock(&albuf->lock); + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + } + if(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset) + { + WriteUnlock(&albuf->lock); + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + } + if(ReadRef(&albuf->ref) != 0 || albuf->MappedAccess != 0) + { + WriteUnlock(&albuf->lock); + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + } + + retval = (ALbyte*)albuf->data + offset; + albuf->MappedAccess = access; + if((access&AL_MAP_WRITE_BIT_SOFT) && !(access&AL_MAP_READ_BIT_SOFT)) + memset(retval, 0x55, length); + WriteUnlock(&albuf->lock); + +done: + UnlockBuffersRead(device); + ALCcontext_DecRef(context); + + return retval; +} + +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) +{ + ALCdevice *device; + ALCcontext *context; + ALbuffer *albuf; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + LockBuffersRead(device); + if((albuf=LookupBuffer(device, buffer)) == NULL) + SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + + WriteLock(&albuf->lock); + if(albuf->MappedAccess == 0) + alSetError(context, AL_INVALID_OPERATION); + else + albuf->MappedAccess = 0; + WriteUnlock(&albuf->lock); + +done: + UnlockBuffersRead(device); + ALCcontext_DecRef(context); +} + AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) { enum UserFmtChannels srcchannels = UserFmtMono; @@ -304,6 +387,11 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons WriteUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } + if(albuf->MappedAccess != 0) + { + WriteUnlock(&albuf->lock); + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + } if(albuf->OriginalType == UserFmtIMA4) { @@ -362,7 +450,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(samples >= 0 && samplerate != 0)) + if(!(samples >= 0 && samplerate != 0) || (internalformat&~FORMAT_MASK) != 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); @@ -374,7 +462,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, samplerate, internalformat, samples, - channels, type, data, align, AL_FALSE); + channels, type, data, align, 0, AL_FALSE); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); @@ -956,7 +1044,7 @@ done: * Currently, the new format must have the same channel configuration as the * original format. */ -static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc) +static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access, ALboolean storesrc) { enum FmtChannels DstChannels = FmtMono; enum FmtType DstType = FmtUByte; @@ -968,6 +1056,12 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f if((long)SrcChannels != (long)DstChannels) return AL_INVALID_ENUM; + if(access != 0) + { + if(!storesrc || (long)SrcType != (long)DstType) + return AL_INVALID_VALUE; + } + NewChannels = ChannelsFromFmt(DstChannels); NewBytes = BytesFromFmt(DstType); @@ -978,7 +1072,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f return AL_OUT_OF_MEMORY; WriteLock(&ALBuf->lock); - if(ReadRef(&ALBuf->ref) != 0) + if(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) { WriteUnlock(&ALBuf->lock); return AL_INVALID_OPERATION; @@ -1041,6 +1135,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f ALBuf->FmtChannels = DstChannels; ALBuf->FmtType = DstType; ALBuf->Format = NewFormat; + ALBuf->Access = access; ALBuf->SampleLen = frames; ALBuf->LoopStart = 0; @@ -1346,6 +1441,8 @@ ALbuffer *NewBuffer(ALCcontext *context) if(!buffer) SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL); RWLockInit(&buffer->lock); + buffer->Access = 0; + buffer->MappedAccess = 0; err = NewThunkEntry(&buffer->id); if(err == AL_NO_ERROR) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 83233b3f..5f21b991 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -760,6 +760,13 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } WriteLock(&Source->queue_lock); + if(buffer && buffer->MappedAccess != 0) + { + WriteUnlock(&Source->queue_lock); + UnlockBuffersRead(device); + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + } + else { ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); if(state == AL_PLAYING || state == AL_PAUSED) @@ -2881,6 +2888,12 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu ReadLock(&buffer->lock); IncrementRef(&buffer->ref); + if(buffer->MappedAccess != 0) + { + WriteUnlock(&source->queue_lock); + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error); + } + if(BufferFmt == NULL) BufferFmt = buffer; else if(BufferFmt->Frequency != buffer->Frequency || -- cgit v1.2.3 From c2c38469304b15a5fa91282084ffe3aea9e97588 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Jan 2018 13:37:43 -0800 Subject: Expose a preliminary AL_SOFT_map_buffer extension for testing --- Alc/ALc.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 9a494c36..fb345b08 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -286,6 +286,9 @@ static const struct { DECL(alIsBufferFormatSupportedSOFT), DECL(alGetStringiSOFT), + + DECL(alMapBufferSOFT), + DECL(alUnmapBufferSOFT), }; #undef DECL @@ -692,6 +695,9 @@ static const struct { DECL(AL_SOURCE_SPATIALIZE_SOFT), DECL(AL_AUTO_SOFT), + + DECL(AL_MAP_READ_BIT_SOFT), + DECL(AL_MAP_WRITE_BIT_SOFT), }; #undef DECL @@ -719,14 +725,33 @@ static ALCchar *alcCaptureDefaultDeviceSpecifier; /* Default context extensions */ static const ALchar alExtList[] = - "AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE " - "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS " - "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " - "AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES " - "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_deferred_updates " - "AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points " - "AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length " - "AL_SOFT_source_resampler AL_SOFT_source_spatialize"; + "AL_EXT_ALAW " + "AL_EXT_BFORMAT " + "AL_EXT_DOUBLE " + "AL_EXT_EXPONENT_DISTANCE " + "AL_EXT_FLOAT32 " + "AL_EXT_IMA4 " + "AL_EXT_LINEAR_DISTANCE " + "AL_EXT_MCFORMATS " + "AL_EXT_MULAW " + "AL_EXT_MULAW_BFORMAT " + "AL_EXT_MULAW_MCFORMATS " + "AL_EXT_OFFSET " + "AL_EXT_source_distance_model " + "AL_EXT_SOURCE_RADIUS " + "AL_EXT_STEREO_ANGLES " + "AL_LOKI_quadriphonic " + "AL_SOFT_block_alignment " + "AL_SOFT_deferred_updates " + "AL_SOFT_direct_channels " + "AL_SOFT_gain_clamp_ex " + "AL_SOFT_loop_points " + "AL_SOFTX_map_buffer " + "AL_SOFT_MSADPCM " + "AL_SOFT_source_latency " + "AL_SOFT_source_length " + "AL_SOFT_source_resampler " + "AL_SOFT_source_spatialize"; static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); -- cgit v1.2.3 From dcb934fc2e46728d9a9d04e8e1e583518942a238 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 10:32:48 -0800 Subject: Avoid repeating some code --- OpenAL32/alBuffer.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 1c9b2650..72750360 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -288,29 +288,23 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!access || (access&~(AL_MAP_READ_BIT_SOFT|AL_MAP_WRITE_BIT_SOFT)) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + WriteLock(&albuf->lock); if(((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) || ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT))) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); if(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); if(ReadRef(&albuf->ref) != 0 || albuf->MappedAccess != 0) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; if((access&AL_MAP_WRITE_BIT_SOFT) && !(access&AL_MAP_READ_BIT_SOFT)) memset(retval, 0x55, length); + +unlock_done: WriteUnlock(&albuf->lock); done: -- cgit v1.2.3 From f6276164f3fc6f8ee06dfd65bf3676b0b0bbb8b0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 16:32:37 -0800 Subject: Fix the return type of the LPALUNMAPBUFFERSOFT typedef --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index dbb4f14b..358b0bf6 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -52,7 +52,7 @@ typedef unsigned int ALbitfieldSOFT; #define AL_MAP_READ_BIT_SOFT 0x01000000 #define AL_MAP_WRITE_BIT_SOFT 0x02000000 typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -typedef void* (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); #ifdef AL_ALEXT_PROTOTYPES AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); -- cgit v1.2.3 From 427212705f90feecb03ce224168a91c72d6290ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 17:19:57 -0800 Subject: Remove the old buffer_samples functions The symbols are still there and exported to retain ABI compatibility, but they no longer do anything except set an AL_INVALID_OPERATION error. They're also removed from the function and enum tables, since they're not part of any supported extension. --- Alc/ALc.c | 45 ----------- OpenAL32/Include/alBuffer.h | 34 ++++----- OpenAL32/alBuffer.c | 176 ++++---------------------------------------- 3 files changed, 32 insertions(+), 223 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index fb345b08..51bbc182 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -281,10 +281,6 @@ static const struct { DECL(alGetSource3i64SOFT), DECL(alGetSourcei64vSOFT), - DECL(alBufferSamplesSOFT), - DECL(alGetBufferSamplesSOFT), - DECL(alIsBufferFormatSupportedSOFT), - DECL(alGetStringiSOFT), DECL(alMapBufferSOFT), @@ -475,47 +471,6 @@ static const struct { DECL(AL_FORMAT_BFORMAT3D_FLOAT32), DECL(AL_FORMAT_BFORMAT3D_MULAW), - DECL(AL_MONO8_SOFT), - DECL(AL_MONO16_SOFT), - DECL(AL_MONO32F_SOFT), - DECL(AL_STEREO8_SOFT), - DECL(AL_STEREO16_SOFT), - DECL(AL_STEREO32F_SOFT), - DECL(AL_QUAD8_SOFT), - DECL(AL_QUAD16_SOFT), - DECL(AL_QUAD32F_SOFT), - DECL(AL_REAR8_SOFT), - DECL(AL_REAR16_SOFT), - DECL(AL_REAR32F_SOFT), - DECL(AL_5POINT1_8_SOFT), - DECL(AL_5POINT1_16_SOFT), - DECL(AL_5POINT1_32F_SOFT), - DECL(AL_6POINT1_8_SOFT), - DECL(AL_6POINT1_16_SOFT), - DECL(AL_6POINT1_32F_SOFT), - DECL(AL_7POINT1_8_SOFT), - DECL(AL_7POINT1_16_SOFT), - DECL(AL_7POINT1_32F_SOFT), - - DECL(AL_MONO_SOFT), - DECL(AL_STEREO_SOFT), - DECL(AL_QUAD_SOFT), - DECL(AL_REAR_SOFT), - DECL(AL_5POINT1_SOFT), - DECL(AL_6POINT1_SOFT), - DECL(AL_7POINT1_SOFT), - - DECL(AL_BYTE_SOFT), - DECL(AL_UNSIGNED_BYTE_SOFT), - DECL(AL_SHORT_SOFT), - DECL(AL_UNSIGNED_SHORT_SOFT), - DECL(AL_INT_SOFT), - DECL(AL_UNSIGNED_INT_SOFT), - DECL(AL_FLOAT_SOFT), - DECL(AL_DOUBLE_SOFT), - DECL(AL_BYTE3_SOFT), - DECL(AL_UNSIGNED_BYTE3_SOFT), - DECL(AL_FREQUENCY), DECL(AL_BITS), DECL(AL_CHANNELS), diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 60a047c9..7f206ed8 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -9,28 +9,28 @@ extern "C" { /* User formats */ enum UserFmtType { - UserFmtByte = AL_BYTE_SOFT, - UserFmtUByte = AL_UNSIGNED_BYTE_SOFT, - UserFmtShort = AL_SHORT_SOFT, - UserFmtUShort = AL_UNSIGNED_SHORT_SOFT, - UserFmtInt = AL_INT_SOFT, - UserFmtUInt = AL_UNSIGNED_INT_SOFT, - UserFmtFloat = AL_FLOAT_SOFT, - UserFmtDouble = AL_DOUBLE_SOFT, - UserFmtMulaw = 0x10000000, + UserFmtByte, + UserFmtUByte, + UserFmtShort, + UserFmtUShort, + UserFmtInt, + UserFmtUInt, + UserFmtFloat, + UserFmtDouble, + UserFmtMulaw, UserFmtAlaw, UserFmtIMA4, UserFmtMSADPCM, }; enum UserFmtChannels { - UserFmtMono = AL_MONO_SOFT, - UserFmtStereo = AL_STEREO_SOFT, - UserFmtRear = AL_REAR_SOFT, - UserFmtQuad = AL_QUAD_SOFT, - UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ - UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ - UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ - UserFmtBFormat2D = 0x20000000, /* WXY */ + UserFmtMono, + UserFmtStereo, + UserFmtRear, + UserFmtQuad, + UserFmtX51, /* (WFX order) */ + UserFmtX61, /* (WFX order) */ + UserFmtX71, /* (WFX order) */ + UserFmtBFormat2D, /* WXY */ UserFmtBFormat3D, /* WXYZ */ }; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 72750360..186097cc 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -46,8 +46,6 @@ extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum User extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access, ALboolean storesrc); -static ALboolean IsValidType(ALenum type); -static ALboolean IsValidChannels(ALenum channels); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); @@ -427,169 +425,59 @@ done: } -AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, - ALuint samplerate, ALenum internalformat, ALsizei samples, - ALenum channels, ALenum type, const ALvoid *data) +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), + ALuint UNUSED(samplerate), ALenum UNUSED(internalformat), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) { - ALCdevice *device; ALCcontext *context; - ALbuffer *albuf; - ALsizei align; - ALenum err; context = GetContextRef(); if(!context) return; - device = context->Device; - LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(samples >= 0 && samplerate != 0) || (internalformat&~FORMAT_MASK) != 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); - - align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - if((samples%align) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - err = LoadData(albuf, samplerate, internalformat, samples, - channels, type, data, align, 0, AL_FALSE); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); + alSetError(context, AL_INVALID_OPERATION); -done: - UnlockBuffersRead(device); ALCcontext_DecRef(context); } -AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, - ALsizei offset, ALsizei samples, - ALenum channels, ALenum type, const ALvoid *data) +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), + ALsizei UNUSED(offset), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), const ALvoid *UNUSED(data)) { - ALCdevice *device; ALCcontext *context; - ALbuffer *albuf; - ALsizei align; context = GetContextRef(); if(!context) return; - device = context->Device; - LockBuffersRead(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); + alSetError(context, AL_INVALID_OPERATION); - WriteLock(&albuf->lock); - align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - if(channels != (ALenum)albuf->FmtChannels) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - if((samples%align) != 0) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - - /* offset -> byte offset */ - offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); - ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType, - data, type, ChannelsFromFmt(albuf->FmtChannels), samples, align); - WriteUnlock(&albuf->lock); - -done: - UnlockBuffersRead(device); ALCcontext_DecRef(context); } -AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, - ALsizei offset, ALsizei samples, - ALenum channels, ALenum type, ALvoid *data) +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), + ALsizei UNUSED(offset), ALsizei UNUSED(samples), + ALenum UNUSED(channels), ALenum UNUSED(type), ALvoid *UNUSED(data)) { - ALCdevice *device; ALCcontext *context; - ALbuffer *albuf; - ALsizei align; context = GetContextRef(); if(!context) return; - device = context->Device; - LockBuffersRead(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); - align = SanitizeAlignment(type, ATOMIC_LOAD_SEQ(&albuf->PackAlign)); - if(align < 1) - { - ReadUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - if(channels != (ALenum)albuf->FmtChannels) - { - 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((samples%align) != 0) - { - ReadUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - - /* offset -> byte offset */ - offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); - ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType, - ChannelsFromFmt(albuf->FmtChannels), samples, align); - ReadUnlock(&albuf->lock); + alSetError(context, AL_INVALID_OPERATION); -done: - UnlockBuffersRead(device); ALCcontext_DecRef(context); } -AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format) +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format)) { - enum FmtChannels dstchannels; - enum FmtType dsttype; ALCcontext *context; - ALboolean ret; context = GetContextRef(); if(!context) return AL_FALSE; - ret = DecomposeFormat(format, &dstchannels, &dsttype); + alSetError(context, AL_INVALID_OPERATION); ALCcontext_DecRef(context); - - return ret; + return AL_FALSE; } @@ -1391,40 +1279,6 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) } -static ALboolean IsValidType(ALenum type) -{ - switch(type) - { - case AL_BYTE_SOFT: - case AL_UNSIGNED_BYTE_SOFT: - case AL_SHORT_SOFT: - case AL_UNSIGNED_SHORT_SOFT: - case AL_INT_SOFT: - case AL_UNSIGNED_INT_SOFT: - case AL_FLOAT_SOFT: - case AL_DOUBLE_SOFT: - return AL_TRUE; - } - return AL_FALSE; -} - -static ALboolean IsValidChannels(ALenum channels) -{ - switch(channels) - { - case AL_MONO_SOFT: - case AL_STEREO_SOFT: - case AL_REAR_SOFT: - case AL_QUAD_SOFT: - case AL_5POINT1_SOFT: - case AL_6POINT1_SOFT: - case AL_7POINT1_SOFT: - return AL_TRUE; - } - return AL_FALSE; -} - - ALbuffer *NewBuffer(ALCcontext *context) { ALCdevice *device = context->Device; -- cgit v1.2.3 From 6489fb586b7f7776ade4adb48910599fc8528802 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 17:55:35 -0800 Subject: Remove (u)int32 sample storage conversion Unused without the buffer_samples extension --- OpenAL32/Include/alBuffer.h | 2 -- OpenAL32/alBuffer.c | 4 --- OpenAL32/sample_cvt.c | 70 +++++---------------------------------------- 3 files changed, 7 insertions(+), 69 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 7f206ed8..3e4268e0 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -13,8 +13,6 @@ enum UserFmtType { UserFmtUByte, UserFmtShort, UserFmtUShort, - UserFmtInt, - UserFmtUInt, UserFmtFloat, UserFmtDouble, UserFmtMulaw, diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 186097cc..37266570 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -188,8 +188,6 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, err, done); break; - case UserFmtInt: - case UserFmtUInt: case UserFmtDouble: framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; if((size%framesize) != 0) @@ -1036,8 +1034,6 @@ ALsizei BytesFromUserFmt(enum UserFmtType type) case UserFmtUByte: return sizeof(ALubyte); case UserFmtShort: return sizeof(ALshort); case UserFmtUShort: return sizeof(ALushort); - case UserFmtInt: return sizeof(ALint); - case UserFmtUInt: return sizeof(ALuint); case UserFmtFloat: return sizeof(ALfloat); case UserFmtDouble: return sizeof(ALdouble); case UserFmtMulaw: return sizeof(ALubyte); diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index af73695b..8f67548b 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -506,8 +506,6 @@ DECL_TEMPLATE(ALbyte); DECL_TEMPLATE(ALubyte); DECL_TEMPLATE(ALshort); DECL_TEMPLATE(ALushort); -DECL_TEMPLATE(ALint); -DECL_TEMPLATE(ALuint); DECL_TEMPLATE(ALalaw); DECL_TEMPLATE(ALmulaw); @@ -532,26 +530,19 @@ static inline T2 Conv_##T2##_##T1(T1 val) { return (T2)val + O; } DECL_TEMPLATE(ALbyte, ALubyte, 128); DECL_TEMPLATE(ALshort, ALushort, 32768); -DECL_TEMPLATE(ALint, ALuint, 2147483648u); #undef DECL_TEMPLATE /* Define int-type to int-type functions */ -#define DECL_TEMPLATE(T, ST, UT, SH) \ -static inline T Conv_##T##_##ST(ST val){ return val >> SH; } \ -static inline T Conv_##T##_##UT(UT val){ return Conv_##ST##_##UT(val) >> SH; }\ -static inline ST Conv_##ST##_##T(T val){ return val << SH; } \ -static inline UT Conv_##UT##_##T(T val){ return Conv_##UT##_##ST(val << SH); } +#define DECL_TEMPLATE(T, T1, T2, SH) \ +static inline T Conv_##T##_##T1(T1 val){ return val >> SH; } \ +static inline T Conv_##T##_##T2(T2 val){ return Conv_##T1##_##T2(val) >> SH; }\ +static inline T1 Conv_##T1##_##T(T val){ return val << SH; } \ +static inline T2 Conv_##T2##_##T(T val){ return Conv_##T2##_##T1(val << SH); } -#define DECL_TEMPLATE2(T1, T2, SH) \ -DECL_TEMPLATE(AL##T1, AL##T2, ALu##T2, SH) \ -DECL_TEMPLATE(ALu##T1, ALu##T2, AL##T2, SH) +DECL_TEMPLATE(ALbyte, ALshort, ALushort, 8) +DECL_TEMPLATE(ALubyte, ALushort, ALshort, 8) -DECL_TEMPLATE2(byte, short, 8) -DECL_TEMPLATE2(short, int, 16) -DECL_TEMPLATE2(byte, int, 24) - -#undef DECL_TEMPLATE2 #undef DECL_TEMPLATE /* Define int-type to fp functions */ @@ -566,13 +557,6 @@ DECL_TEMPLATE2(ALfloat, byte, (1.0f/128.0f)) DECL_TEMPLATE2(ALdouble, byte, (1.0/128.0)) DECL_TEMPLATE2(ALfloat, short, (1.0f/32768.0f)) DECL_TEMPLATE2(ALdouble, short, (1.0/32768.0)) -DECL_TEMPLATE2(ALdouble, int, (1.0/2147483648.0)) - -/* Special handling for int32 to float32, since it would overflow. */ -static inline ALfloat Conv_ALfloat_ALint(ALint val) -{ return (ALfloat)(val>>7) * (1.0f/16777216.0f); } -static inline ALfloat Conv_ALfloat_ALuint(ALuint val) -{ return (ALfloat)(Conv_ALint_ALuint(val)>>7) * (1.0f/16777216.0f); } #undef DECL_TEMPLATE2 #undef DECL_TEMPLATE @@ -593,18 +577,6 @@ DECL_TEMPLATE(ALfloat, byte, -128, 127) DECL_TEMPLATE(ALdouble, byte, -128, 127) DECL_TEMPLATE(ALfloat, short, -32768, 32767) DECL_TEMPLATE(ALdouble, short, -32768, 32767) -DECL_TEMPLATE(ALdouble, int, -2147483647-1, 2147483647) - -/* Special handling for float32 to int32, since it would overflow. */ -static inline ALint Conv_ALint_ALfloat(ALfloat val) -{ - val *= 16777216.0f; - if(val >= 16777215.0f) return 0x7fffff80/*16777215 << 7*/; - if(val <= -16777216.0f) return 0x80000000/*-16777216 << 7*/; - return (ALint)val << 7; -} -static inline ALuint Conv_ALuint_ALfloat(ALfloat val) -{ return Conv_ALuint_ALint(Conv_ALint_ALfloat(val)); } #undef DECL_TEMPLATE @@ -624,8 +596,6 @@ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) @@ -653,8 +623,6 @@ DECL_TEMPLATE(T, ALbyte) \ DECL_TEMPLATE(T, ALubyte) \ DECL_TEMPLATE(T, ALshort) \ DECL_TEMPLATE(T, ALushort) \ -DECL_TEMPLATE(T, ALint) \ -DECL_TEMPLATE(T, ALuint) \ DECL_TEMPLATE(T, ALfloat) \ DECL_TEMPLATE(T, ALdouble) \ DECL_TEMPLATE(T, ALmulaw) \ @@ -664,8 +632,6 @@ DECL_TEMPLATE2(ALbyte) DECL_TEMPLATE2(ALubyte) DECL_TEMPLATE2(ALshort) DECL_TEMPLATE2(ALushort) -DECL_TEMPLATE2(ALint) -DECL_TEMPLATE2(ALuint) DECL_TEMPLATE2(ALfloat) DECL_TEMPLATE2(ALdouble) DECL_TEMPLATE2(ALmulaw) @@ -713,8 +679,6 @@ static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numc } } DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -764,8 +728,6 @@ static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src, } } DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -815,8 +777,6 @@ static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, } } DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -865,8 +825,6 @@ static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src, } } DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -923,12 +881,6 @@ static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ case UserFmtUShort: \ Convert_##T##_ALushort(dst, src, numchans, len, align); \ break; \ - case UserFmtInt: \ - Convert_##T##_ALint(dst, src, numchans, len, align); \ - break; \ - case UserFmtUInt: \ - Convert_##T##_ALuint(dst, src, numchans, len, align); \ - break; \ case UserFmtFloat: \ Convert_##T##_ALfloat(dst, src, numchans, len, align); \ break; \ @@ -954,8 +906,6 @@ DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) DECL_TEMPLATE(ALushort) -DECL_TEMPLATE(ALint) -DECL_TEMPLATE(ALuint) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -983,12 +933,6 @@ void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, case UserFmtUShort: Convert_ALushort(dst, src, srcType, numchans, len, align); break; - case UserFmtInt: - Convert_ALint(dst, src, srcType, numchans, len, align); - break; - case UserFmtUInt: - Convert_ALuint(dst, src, srcType, numchans, len, align); - break; case UserFmtFloat: Convert_ALfloat(dst, src, srcType, numchans, len, align); break; -- cgit v1.2.3 From efd11f32a20c8fa06161a42facc5b97180c0c1a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 18:15:25 -0800 Subject: Remove support for (signed) byte and ushort sample storage Also not used without buffer_samples --- OpenAL32/Include/alBuffer.h | 2 - OpenAL32/alBuffer.c | 8 +--- OpenAL32/sample_cvt.c | 103 ++++++++++---------------------------------- 3 files changed, 24 insertions(+), 89 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 3e4268e0..35c880c9 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -9,10 +9,8 @@ extern "C" { /* User formats */ enum UserFmtType { - UserFmtByte, UserFmtUByte, UserFmtShort, - UserFmtUShort, UserFmtFloat, UserFmtDouble, UserFmtMulaw, diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 37266570..e0f2160d 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -144,7 +144,7 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) { enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtByte; + enum UserFmtType srctype = UserFmtUByte; ALCdevice *device; ALCcontext *context; ALbuffer *albuf; @@ -170,10 +170,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi switch(srctype) { - case UserFmtByte: case UserFmtUByte: case UserFmtShort: - case UserFmtUShort: case UserFmtFloat: case UserFmtMulaw: case UserFmtAlaw: @@ -339,7 +337,7 @@ done: AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) { enum UserFmtChannels srcchannels = UserFmtMono; - enum UserFmtType srctype = UserFmtByte; + enum UserFmtType srctype = UserFmtUByte; ALCdevice *device; ALCcontext *context; ALbuffer *albuf; @@ -1030,10 +1028,8 @@ ALsizei BytesFromUserFmt(enum UserFmtType type) { switch(type) { - case UserFmtByte: return sizeof(ALbyte); case UserFmtUByte: return sizeof(ALubyte); case UserFmtShort: return sizeof(ALshort); - case UserFmtUShort: return sizeof(ALushort); case UserFmtFloat: return sizeof(ALfloat); case UserFmtDouble: return sizeof(ALdouble); case UserFmtMulaw: return sizeof(ALubyte); diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 8f67548b..0bbfb86c 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -502,10 +502,8 @@ static void EncodeMSADPCMBlock(ALmsadpcm *dst, const ALshort *src, ALint *sample #define DECL_TEMPLATE(T) \ static inline T Conv_##T##_##T(T val) { return val; } -DECL_TEMPLATE(ALbyte); DECL_TEMPLATE(ALubyte); DECL_TEMPLATE(ALshort); -DECL_TEMPLATE(ALushort); DECL_TEMPLATE(ALalaw); DECL_TEMPLATE(ALmulaw); @@ -523,62 +521,33 @@ static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val) #undef DECL_TEMPLATE -/* Define alternate-sign functions. */ -#define DECL_TEMPLATE(T1, T2, O) \ -static inline T1 Conv_##T1##_##T2(T2 val) { return (T1)val - O; } \ -static inline T2 Conv_##T2##_##T1(T1 val) { return (T2)val + O; } - -DECL_TEMPLATE(ALbyte, ALubyte, 128); -DECL_TEMPLATE(ALshort, ALushort, 32768); - -#undef DECL_TEMPLATE - /* Define int-type to int-type functions */ -#define DECL_TEMPLATE(T, T1, T2, SH) \ -static inline T Conv_##T##_##T1(T1 val){ return val >> SH; } \ -static inline T Conv_##T##_##T2(T2 val){ return Conv_##T1##_##T2(val) >> SH; }\ -static inline T1 Conv_##T1##_##T(T val){ return val << SH; } \ -static inline T2 Conv_##T2##_##T(T val){ return Conv_##T2##_##T1(val << SH); } - -DECL_TEMPLATE(ALbyte, ALshort, ALushort, 8) -DECL_TEMPLATE(ALubyte, ALushort, ALshort, 8) - -#undef DECL_TEMPLATE +static inline ALubyte Conv_ALubyte_ALshort(ALshort val) { return (val>>8) + 128; } +static inline ALshort Conv_ALshort_ALubyte(ALubyte val) { return (val-128) << 8; } /* Define int-type to fp functions */ -#define DECL_TEMPLATE(T, ST, UT, OP) \ -static inline T Conv_##T##_##ST(ST val) { return (T)val * OP; } \ -static inline T Conv_##T##_##UT(UT val) { return (T)Conv_##ST##_##UT(val) * OP; } - -#define DECL_TEMPLATE2(T1, T2, OP) \ -DECL_TEMPLATE(T1, AL##T2, ALu##T2, OP) - -DECL_TEMPLATE2(ALfloat, byte, (1.0f/128.0f)) -DECL_TEMPLATE2(ALdouble, byte, (1.0/128.0)) -DECL_TEMPLATE2(ALfloat, short, (1.0f/32768.0f)) -DECL_TEMPLATE2(ALdouble, short, (1.0/32768.0)) - -#undef DECL_TEMPLATE2 -#undef DECL_TEMPLATE +static inline ALfloat Conv_ALfloat_ALubyte(ALubyte val) { return (val-128) * (1.0f/128.0f); } +static inline ALdouble Conv_ALdouble_ALubyte(ALubyte val) { return (val-128) * (1.0/128.0); } +static inline ALfloat Conv_ALfloat_ALshort(ALshort val) { return val * (1.0f/32768.0f); } +static inline ALdouble Conv_ALdouble_ALshort(ALshort val) { return val * (1.0/32768.0); } /* Define fp to int-type functions */ -#define DECL_TEMPLATE(FT, T, smin, smax) \ -static inline AL##T Conv_AL##T##_##FT(FT val) \ -{ \ - val *= (FT)smax + 1; \ - if(val >= (FT)smax) return smax; \ - if(val <= (FT)smin) return smin; \ - return (AL##T)val; \ -} \ -static inline ALu##T Conv_ALu##T##_##FT(FT val) \ -{ return Conv_ALu##T##_AL##T(Conv_AL##T##_##FT(val)); } - -DECL_TEMPLATE(ALfloat, byte, -128, 127) -DECL_TEMPLATE(ALdouble, byte, -128, 127) -DECL_TEMPLATE(ALfloat, short, -32768, 32767) -DECL_TEMPLATE(ALdouble, short, -32768, 32767) - -#undef DECL_TEMPLATE +static inline ALubyte Conv_ALubyte_ALfloat(ALfloat val) +{ + val *= 128.0f; + if(val >= 127.0f) return 255; + if(val <= -128.0f) return 0; + return (ALbyte)val + 128; +} +static inline ALubyte Conv_ALubyte_ALdouble(ALdouble val) { return Conv_ALubyte_ALfloat(val); } +static inline ALshort Conv_ALshort_ALfloat(ALfloat val) +{ + val *= 32768.0f; + if(val >= 32767.0f) return 32767; + if(val <= -32768.0f) return -32768; + return (ALshort)val; +} +static inline ALshort Conv_ALshort_ALdouble(ALdouble val) { return Conv_ALshort_ALfloat(val); } /* Define muLaw and aLaw functions (goes through short functions). */ #define DECL_TEMPLATE(T) \ @@ -592,10 +561,8 @@ static inline ALalaw Conv_ALalaw_##T(T val) \ static inline T Conv_##T##_ALalaw(ALalaw val) \ { return Conv_##T##_ALshort(DecodeALaw(val)); } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) @@ -619,19 +586,15 @@ static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALsizei numchans, \ } #define DECL_TEMPLATE2(T) \ -DECL_TEMPLATE(T, ALbyte) \ DECL_TEMPLATE(T, ALubyte) \ DECL_TEMPLATE(T, ALshort) \ -DECL_TEMPLATE(T, ALushort) \ DECL_TEMPLATE(T, ALfloat) \ DECL_TEMPLATE(T, ALdouble) \ DECL_TEMPLATE(T, ALmulaw) \ DECL_TEMPLATE(T, ALalaw) -DECL_TEMPLATE2(ALbyte) DECL_TEMPLATE2(ALubyte) DECL_TEMPLATE2(ALshort) -DECL_TEMPLATE2(ALushort) DECL_TEMPLATE2(ALfloat) DECL_TEMPLATE2(ALdouble) DECL_TEMPLATE2(ALmulaw) @@ -662,7 +625,6 @@ static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALsizei numchans, \ } \ } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numchans, ALsizei len, ALsizei align) @@ -678,7 +640,6 @@ static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numc dst += align*numchans; } } -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -709,7 +670,6 @@ static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALsizei numchans, \ } \ } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src, ALsizei numchans, ALsizei len, ALsizei align) @@ -727,7 +687,6 @@ static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src, dst += byte_align; } } -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -759,7 +718,6 @@ static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \ } \ } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, ALsizei numchans, ALsizei len, @@ -776,7 +734,6 @@ static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, dst += align*numchans; } } -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -807,7 +764,6 @@ static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \ } \ } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src, ALsizei numchans, ALsizei len, ALsizei align) @@ -824,7 +780,6 @@ static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src, dst += byte_align; } } -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -869,18 +824,12 @@ static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ { \ switch(srcType) \ { \ - case UserFmtByte: \ - Convert_##T##_ALbyte(dst, src, numchans, len, align); \ - break; \ case UserFmtUByte: \ Convert_##T##_ALubyte(dst, src, numchans, len, align); \ break; \ case UserFmtShort: \ Convert_##T##_ALshort(dst, src, numchans, len, align); \ break; \ - case UserFmtUShort: \ - Convert_##T##_ALushort(dst, src, numchans, len, align); \ - break; \ case UserFmtFloat: \ Convert_##T##_ALfloat(dst, src, numchans, len, align); \ break; \ @@ -902,10 +851,8 @@ static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ } \ } -DECL_TEMPLATE(ALbyte) DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALushort) DECL_TEMPLATE(ALfloat) DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) @@ -921,18 +868,12 @@ void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, { switch(dstType) { - case UserFmtByte: - Convert_ALbyte(dst, src, srcType, numchans, len, align); - break; case UserFmtUByte: Convert_ALubyte(dst, src, srcType, numchans, len, align); break; case UserFmtShort: Convert_ALshort(dst, src, srcType, numchans, len, align); break; - case UserFmtUShort: - Convert_ALushort(dst, src, srcType, numchans, len, align); - break; case UserFmtFloat: Convert_ALfloat(dst, src, srcType, numchans, len, align); break; -- cgit v1.2.3 From db13af1935f969bb579fca9d79c6600d91c0fe32 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 18:34:03 -0800 Subject: Handle double-precision buffers in the mixer --- Alc/mixer.c | 5 +++++ OpenAL32/Include/alBuffer.h | 11 ++++++----- OpenAL32/alBuffer.c | 26 ++------------------------ 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index fe4bcd78..b54e840e 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -202,6 +202,9 @@ static inline ALfloat Sample_ALshort(ALshort val) static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } +static inline ALfloat Sample_ALdouble(ALdouble val) +{ return (ALfloat)val; } + typedef ALubyte ALmulaw; static inline ALfloat Sample_ALmulaw(ALmulaw val) { return muLawDecompressionTable[val] * (1.0f/32768.0f); } @@ -222,6 +225,7 @@ static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ DECL_TEMPLATE(ALubyte) DECL_TEMPLATE(ALshort) DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) DECL_TEMPLATE(ALmulaw) DECL_TEMPLATE(ALalaw) @@ -236,6 +240,7 @@ static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint HANDLE_FMT(FmtUByte, ALubyte); HANDLE_FMT(FmtShort, ALshort); HANDLE_FMT(FmtFloat, ALfloat); + HANDLE_FMT(FmtDouble, ALdouble); HANDLE_FMT(FmtMulaw, ALmulaw); HANDLE_FMT(FmtAlaw, ALalaw); } diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 35c880c9..5f1e6826 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -40,11 +40,12 @@ inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType /* Storable formats */ enum FmtType { - FmtUByte = UserFmtUByte, - FmtShort = UserFmtShort, - FmtFloat = UserFmtFloat, - FmtMulaw = UserFmtMulaw, - FmtAlaw = UserFmtAlaw, + FmtUByte = UserFmtUByte, + FmtShort = UserFmtShort, + FmtFloat = UserFmtFloat, + FmtDouble = UserFmtDouble, + FmtMulaw = UserFmtMulaw, + FmtAlaw = UserFmtAlaw, }; enum FmtChannels { FmtMono = UserFmtMono, diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index e0f2160d..e9efd2c8 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -173,6 +173,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtUByte: case UserFmtShort: case UserFmtFloat: + case UserFmtDouble: case UserFmtMulaw: case UserFmtAlaw: framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; @@ -186,30 +187,6 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, err, done); break; - case UserFmtDouble: - framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; - if((size%framesize) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - 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; - case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break; - case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break; - } - err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, format&ACCESS_FLAGS, - AL_TRUE); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); - break; - case UserFmtIMA4: framesize = (align-1)/2 + 4; framesize *= ChannelsFromUserFmt(srcchannels); @@ -1141,6 +1118,7 @@ ALsizei BytesFromFmt(enum FmtType type) case FmtUByte: return sizeof(ALubyte); case FmtShort: return sizeof(ALshort); case FmtFloat: return sizeof(ALfloat); + case FmtDouble: return sizeof(ALdouble); case FmtMulaw: return sizeof(ALubyte); case FmtAlaw: return sizeof(ALubyte); } -- cgit v1.2.3 From 5f3ae527c92fa1fda0ea87be9629db2c320831ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 23:35:28 -0800 Subject: More cleanup for buffer loading Don't bother with unnecessary and unused converters, and remove some unsupported queries. --- Alc/ALc.c | 4 - OpenAL32/Include/alBuffer.h | 14 +- OpenAL32/Include/sample_cvt.h | 5 +- OpenAL32/alBuffer.c | 276 ++++++------------ OpenAL32/alSource.c | 13 +- OpenAL32/sample_cvt.c | 633 +----------------------------------------- 6 files changed, 112 insertions(+), 833 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 51bbc182..dbdc2986 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -475,10 +475,6 @@ static const struct { DECL(AL_BITS), DECL(AL_CHANNELS), DECL(AL_SIZE), - DECL(AL_INTERNAL_FORMAT_SOFT), - DECL(AL_BYTE_LENGTH_SOFT), - DECL(AL_SAMPLE_LENGTH_SOFT), - DECL(AL_SEC_LENGTH_SOFT), DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 5f1e6826..e89d3c96 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -71,19 +71,17 @@ inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type) typedef struct ALbuffer { ALvoid *data; - ALsizei Frequency; - ALenum Format; + ALsizei Frequency; ALbitfieldSOFT Access; - ALsizei SampleLen; + ALsizei SampleLen; enum FmtChannels FmtChannels; enum FmtType FmtType; - ALuint BytesAlloc; + ALsizei BytesAlloc; - enum UserFmtChannels OriginalChannels; - enum UserFmtType OriginalType; - ALsizei OriginalSize; - ALsizei OriginalAlign; + enum UserFmtType OriginalType; + ALsizei OriginalSize; + ALsizei OriginalAlign; ALsizei LoopStart; ALsizei LoopEnd; diff --git a/OpenAL32/Include/sample_cvt.h b/OpenAL32/Include/sample_cvt.h index 35ead20c..c041760e 100644 --- a/OpenAL32/Include/sample_cvt.h +++ b/OpenAL32/Include/sample_cvt.h @@ -7,6 +7,9 @@ extern const ALshort muLawDecompressionTable[256]; extern const ALshort aLawDecompressionTable[256]; -void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align); +void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align); +void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align); #endif /* SAMPLE_CVT_H */ diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index e9efd2c8..9acbb148 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,9 +45,8 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access, ALboolean storesrc); +static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); -static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); @@ -148,7 +147,6 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi ALCdevice *device; ALCcontext *context; ALbuffer *albuf; - ALenum newformat = AL_NONE; ALsizei framesize; ALsizei align; ALenum err; @@ -180,59 +178,30 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi if((size%framesize) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - err = LoadData(albuf, freq, format&FORMAT_MASK, size/framesize*align, - srcchannels, srctype, data, align, format&ACCESS_FLAGS, - AL_TRUE); + err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, + data, align, format&ACCESS_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; case UserFmtIMA4: - framesize = (align-1)/2 + 4; - framesize *= ChannelsFromUserFmt(srcchannels); + framesize = ((align-1)/2 + 4) * ChannelsFromUserFmt(srcchannels); if((size%framesize) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - 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; - case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; - case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; - } - err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, format&ACCESS_FLAGS, - AL_TRUE); + err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, + data, align, format&ACCESS_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; case UserFmtMSADPCM: - framesize = (align-2)/2 + 7; - framesize *= ChannelsFromUserFmt(srcchannels); + framesize = ((align-2)/2 + 7) * ChannelsFromUserFmt(srcchannels); if((size%framesize) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - 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; - case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; - case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; - } - err = LoadData(albuf, freq, newformat, size/framesize*align, - srcchannels, srctype, data, align, format&ACCESS_FLAGS, - AL_TRUE); + err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, + data, align, format&ACCESS_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -319,9 +288,10 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALCcontext *context; ALbuffer *albuf; ALsizei byte_align; - ALsizei channels; - ALsizei bytes; + ALsizei frame_size; + ALsizei num_chans; ALsizei align; + void *dst; context = GetContextRef(); if(!context) return; @@ -342,7 +312,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons WriteUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } - if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType) + if((long)srcchannels != (long)albuf->FmtChannels || srctype != albuf->OriginalType) { WriteUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); @@ -361,18 +331,17 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons if(albuf->OriginalType == UserFmtIMA4) { byte_align = (albuf->OriginalAlign-1)/2 + 4; - byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels); + byte_align *= ChannelsFromFmt(albuf->FmtChannels); } else if(albuf->OriginalType == UserFmtMSADPCM) { byte_align = (albuf->OriginalAlign-2)/2 + 7; - byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels); + byte_align *= ChannelsFromFmt(albuf->FmtChannels); } else { byte_align = albuf->OriginalAlign; - byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels, - albuf->OriginalType); + byte_align *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); } if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset || @@ -382,14 +351,22 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } - channels = ChannelsFromFmt(albuf->FmtChannels); - bytes = BytesFromFmt(albuf->FmtType); + num_chans = ChannelsFromFmt(albuf->FmtChannels); + frame_size = num_chans * BytesFromFmt(albuf->FmtType); /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * channels*bytes; + offset = offset/byte_align * frame_size; length = length/byte_align * albuf->OriginalAlign; - ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType, - data, srctype, channels, length, align); + dst = (ALbyte*)albuf->data + offset; + if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) + Convert_ALshort_ALima4(dst, data, num_chans, length, align); + else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) + Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align); + else + { + assert((long)srctype == (long)albuf->FmtType); + memcpy(dst, data, length*frame_size); + } WriteUnlock(&albuf->lock); done: @@ -668,15 +645,6 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val 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: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -785,18 +753,6 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value ReadUnlock(&albuf->lock); break; - case AL_INTERNAL_FORMAT_SOFT: - *value = albuf->Format; - break; - - case AL_BYTE_LENGTH_SOFT: - *value = albuf->OriginalSize; - break; - - case AL_SAMPLE_LENGTH_SOFT: - *value = albuf->SampleLen; - break; - case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); break; @@ -899,32 +855,54 @@ done: * Currently, the new format must have the same channel configuration as the * original format. */ -static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access, ALboolean storesrc) +static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access) { enum FmtChannels DstChannels = FmtMono; enum FmtType DstType = FmtUByte; - ALuint NewChannels, NewBytes; - ALuint64 newsize; + ALsizei NumChannels, FrameSize; + ALsizei newsize; - if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE) - return AL_INVALID_ENUM; + /* Currently no channels need to be converted. */ + switch(SrcChannels) + { + case UserFmtMono: DstChannels = FmtMono; break; + case UserFmtStereo: DstChannels = FmtStereo; break; + case UserFmtRear: DstChannels = FmtRear; break; + case UserFmtQuad: DstChannels = FmtQuad; break; + case UserFmtX51: DstChannels = FmtX51; break; + case UserFmtX61: DstChannels = FmtX61; break; + case UserFmtX71: DstChannels = FmtX71; break; + case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; + case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; + } if((long)SrcChannels != (long)DstChannels) return AL_INVALID_ENUM; + /* IMA4 and MSADPCM convert to 16-bit short. */ + switch(SrcType) + { + case UserFmtUByte: DstType = FmtUByte; break; + case UserFmtShort: DstType = FmtShort; break; + case UserFmtFloat: DstType = FmtFloat; break; + case UserFmtDouble: DstType = FmtDouble; break; + case UserFmtAlaw: DstType = FmtAlaw; break; + case UserFmtMulaw: DstType = FmtMulaw; break; + case UserFmtIMA4: DstType = FmtShort; break; + case UserFmtMSADPCM: DstType = FmtShort; break; + } + if(access != 0) { - if(!storesrc || (long)SrcType != (long)DstType) + if((long)SrcType != (long)DstType) return AL_INVALID_VALUE; } - NewChannels = ChannelsFromFmt(DstChannels); - NewBytes = BytesFromFmt(DstType); + NumChannels = ChannelsFromFmt(DstChannels); + FrameSize = NumChannels * BytesFromFmt(DstType); - newsize = frames; - newsize *= NewBytes; - newsize *= NewChannels; - if(newsize > INT_MAX) + if(frames > INT_MAX/FrameSize) return AL_OUT_OF_MEMORY; + newsize = frames*FrameSize; WriteLock(&ALBuf->lock); if(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) @@ -939,7 +917,8 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f * usage, and reporting the real size could cause problems for apps that * use AL_SIZE to try to get the buffer's play length. */ - newsize = (newsize+15) & ~0xf; + if(newsize <= INT_MAX-15) + newsize = (newsize+15) & ~0xf; if(newsize != ALBuf->BytesAlloc) { void *temp = al_calloc(16, (size_t)newsize); @@ -950,46 +929,42 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f } al_free(ALBuf->data); ALBuf->data = temp; - ALBuf->BytesAlloc = (ALuint)newsize; + ALBuf->BytesAlloc = newsize; } - if(data != NULL) - ConvertData(ALBuf->data, (enum UserFmtType)DstType, data, SrcType, NewChannels, frames, align); - - if(storesrc) + ALBuf->OriginalType = SrcType; + if(SrcType == UserFmtIMA4) { - ALBuf->OriginalChannels = SrcChannels; - ALBuf->OriginalType = SrcType; - if(SrcType == UserFmtIMA4) - { - ALsizei byte_align = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels); - ALBuf->OriginalSize = frames / align * byte_align; - ALBuf->OriginalAlign = align; - } - else if(SrcType == UserFmtMSADPCM) - { - ALsizei byte_align = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels); - ALBuf->OriginalSize = frames / align * byte_align; - ALBuf->OriginalAlign = align; - } - else - { - ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType); - ALBuf->OriginalAlign = 1; - } + ALsizei byte_align = ((align-1)/2 + 4) * NumChannels; + ALBuf->OriginalSize = frames / align * byte_align; + ALBuf->OriginalAlign = align; + assert(DstType == FmtShort); + if(data != NULL) + Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align); + } + else if(SrcType == UserFmtMSADPCM) + { + ALsizei byte_align = ((align-2)/2 + 7) * NumChannels; + ALBuf->OriginalSize = frames / align * byte_align; + ALBuf->OriginalAlign = align; + assert(DstType == FmtShort); + if(data != NULL) + Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align); } else { - ALBuf->OriginalChannels = (enum UserFmtChannels)DstChannels; - ALBuf->OriginalType = (enum UserFmtType)DstType; - ALBuf->OriginalSize = frames * NewBytes * NewChannels; - ALBuf->OriginalAlign = 1; + ALBuf->OriginalSize = frames * FrameSize; + ALBuf->OriginalAlign = 1; + if(data != NULL) + { + assert((long)SrcType == (long)DstType); + memcpy(ALBuf->data, data, frames*FrameSize); + } } ALBuf->Frequency = freq; ALBuf->FmtChannels = DstChannels; ALBuf->FmtType = DstType; - ALBuf->Format = NewFormat; ALBuf->Access = access; ALBuf->SampleLen = frames; @@ -1140,77 +1115,6 @@ ALsizei ChannelsFromFmt(enum FmtChannels chans) } return 0; } -static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type) -{ - static const struct { - ALenum format; - enum FmtChannels channels; - enum FmtType type; - } list[] = { - { AL_FORMAT_MONO8, FmtMono, FmtUByte }, - { AL_FORMAT_MONO16, FmtMono, FmtShort }, - { AL_FORMAT_MONO_FLOAT32, FmtMono, FmtFloat }, - { AL_FORMAT_MONO_MULAW, FmtMono, FmtMulaw }, - { AL_FORMAT_MONO_ALAW_EXT, FmtMono, FmtAlaw }, - - { AL_FORMAT_STEREO8, FmtStereo, FmtUByte }, - { AL_FORMAT_STEREO16, FmtStereo, FmtShort }, - { AL_FORMAT_STEREO_FLOAT32, FmtStereo, FmtFloat }, - { AL_FORMAT_STEREO_MULAW, FmtStereo, FmtMulaw }, - { AL_FORMAT_STEREO_ALAW_EXT, FmtStereo, FmtAlaw }, - - { AL_FORMAT_REAR8, FmtRear, FmtUByte }, - { AL_FORMAT_REAR16, FmtRear, FmtShort }, - { AL_FORMAT_REAR32, FmtRear, FmtFloat }, - { AL_FORMAT_REAR_MULAW, FmtRear, FmtMulaw }, - - { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtUByte }, - { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, - - { AL_FORMAT_QUAD8, FmtQuad, FmtUByte }, - { AL_FORMAT_QUAD16, FmtQuad, FmtShort }, - { AL_FORMAT_QUAD32, FmtQuad, FmtFloat }, - { AL_FORMAT_QUAD_MULAW, FmtQuad, FmtMulaw }, - - { AL_FORMAT_51CHN8, FmtX51, FmtUByte }, - { AL_FORMAT_51CHN16, FmtX51, FmtShort }, - { AL_FORMAT_51CHN32, FmtX51, FmtFloat }, - { AL_FORMAT_51CHN_MULAW, FmtX51, FmtMulaw }, - - { AL_FORMAT_61CHN8, FmtX61, FmtUByte }, - { AL_FORMAT_61CHN16, FmtX61, FmtShort }, - { AL_FORMAT_61CHN32, FmtX61, FmtFloat }, - { AL_FORMAT_61CHN_MULAW, FmtX61, FmtMulaw }, - - { AL_FORMAT_71CHN8, FmtX71, FmtUByte }, - { AL_FORMAT_71CHN16, FmtX71, FmtShort }, - { AL_FORMAT_71CHN32, FmtX71, FmtFloat }, - { AL_FORMAT_71CHN_MULAW, FmtX71, FmtMulaw }, - - { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtUByte }, - { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, - { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, - { AL_FORMAT_BFORMAT2D_MULAW, FmtBFormat2D, FmtMulaw }, - - { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtUByte }, - { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, - { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, - { AL_FORMAT_BFORMAT3D_MULAW, FmtBFormat3D, FmtMulaw }, - }; - size_t i; - - for(i = 0;i < COUNTOF(list);i++) - { - if(list[i].format == format) - { - *chans = list[i].channels; - *type = list[i].type; - return AL_TRUE; - } - } - - return AL_FALSE; -} static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 5f21b991..24f48895 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2897,7 +2897,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(BufferFmt == NULL) BufferFmt = buffer; else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->OriginalChannels != buffer->OriginalChannels || + BufferFmt->FmtChannels != buffer->FmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { WriteUnlock(&source->queue_lock); @@ -3493,8 +3493,8 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte } else { - ALuint FrameSize = FrameSizeFromUserFmt(BufferFmt->OriginalChannels, - BufferFmt->OriginalType); + ALuint FrameSize = FrameSizeFromFmt(BufferFmt->FmtChannels, + BufferFmt->FmtType); offset = (ALdouble)(readPos * FrameSize); } break; @@ -3593,18 +3593,17 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac if(BufferFmt->OriginalType == UserFmtIMA4) { ALsizei align = (BufferFmt->OriginalAlign-1)/2 + 4; - *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels); + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); *offset *= BufferFmt->OriginalAlign; } else if(BufferFmt->OriginalType == UserFmtMSADPCM) { ALsizei align = (BufferFmt->OriginalAlign-2)/2 + 7; - *offset /= align * ChannelsFromUserFmt(BufferFmt->OriginalChannels); + *offset /= align * ChannelsFromFmt(BufferFmt->FmtChannels); *offset *= BufferFmt->OriginalAlign; } else - *offset /= FrameSizeFromUserFmt(BufferFmt->OriginalChannels, - BufferFmt->OriginalType); + *offset /= FrameSizeFromFmt(BufferFmt->FmtChannels, BufferFmt->FmtType); *frac = 0; break; diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index 0bbfb86c..ff7c8776 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -3,25 +3,11 @@ #include "sample_cvt.h" -#ifdef HAVE_ALLOCA_H -#include -#endif -#ifdef HAVE_MALLOC_H -#include -#endif - #include "AL/al.h" #include "alu.h" #include "alBuffer.h" -#ifdef HAVE_C99_VLA -#define DECL_VLA(T, _name, _size) T _name[(_size)] -#else -#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T)) -#endif - - /* IMA ADPCM Stepsize table */ static const int IMAStep_size[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, @@ -103,28 +89,6 @@ const ALshort muLawDecompressionTable[256] = { 56, 48, 40, 32, 24, 16, 8, 0 }; -/* Values used when encoding a muLaw sample */ -static const int muLawBias = 0x84; -static const int muLawClip = 32635; -static const char muLawCompressTable[256] = { - 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - /* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a * signed 16-bit sample */ @@ -163,80 +127,8 @@ const ALshort aLawDecompressionTable[256] = { 944, 912, 1008, 976, 816, 784, 880, 848 }; -/* Values used when encoding an aLaw sample */ -static const int aLawClip = 32635; -static const char aLawCompressTable[128] = { - 1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - -typedef ALubyte ALmulaw; -typedef ALubyte ALalaw; -typedef ALubyte ALima4; -typedef ALubyte ALmsadpcm; - -static inline ALshort DecodeMuLaw(ALmulaw val) -{ return muLawDecompressionTable[val]; } - -static ALmulaw EncodeMuLaw(ALshort val) -{ - ALint mant, exp, sign; - - sign = (val>>8) & 0x80; - if(sign) - { - /* -32768 doesn't properly negate on a short; it results in itself. - * So clamp to -32767 */ - val = maxi(val, -32767); - val = -val; - } - - val = mini(val, muLawClip); - val += muLawBias; - - exp = muLawCompressTable[(val>>7) & 0xff]; - mant = (val >> (exp+3)) & 0x0f; - - return ~(sign | (exp<<4) | mant); -} - -static inline ALshort DecodeALaw(ALalaw val) -{ return aLawDecompressionTable[val]; } - -static ALalaw EncodeALaw(ALshort val) -{ - ALint mant, exp, sign; - - sign = ((~val) >> 8) & 0x80; - if(!sign) - { - val = maxi(val, -32767); - val = -val; - } - val = mini(val, aLawClip); - - if(val >= 256) - { - exp = aLawCompressTable[(val>>8) & 0x7f]; - mant = (val >> (exp+3)) & 0x0f; - } - else - { - exp = 0; - mant = val >> 4; - } - - return ((exp<<4) | mant) ^ (sign^0x55); -} - -static void DecodeIMA4Block(ALshort *dst, const ALima4 *src, ALint numchans, ALsizei align) +static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) { ALint sample[MAX_INPUT_CHANNELS], index[MAX_INPUT_CHANNELS]; ALuint code[MAX_INPUT_CHANNELS]; @@ -285,73 +177,7 @@ static void DecodeIMA4Block(ALshort *dst, const ALima4 *src, ALint numchans, ALs } } -static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans, ALsizei align) -{ - ALsizei j,k,c; - - for(c = 0;c < numchans;c++) - { - int diff = src[c] - sample[c]; - int step = IMAStep_size[index[c]]; - int nibble; - - nibble = 0; - if(diff < 0) - { - nibble = 0x8; - diff = -diff; - } - - diff = mini(step*2, diff); - nibble |= (diff*8/step - 1) / 2; - - sample[c] += IMA4Codeword[nibble] * step / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - *(dst++) = sample[c] & 0xff; - *(dst++) = (sample[c]>>8) & 0xff; - *(dst++) = index[c] & 0xff; - *(dst++) = (index[c]>>8) & 0xff; - } - - for(j = 1;j < align;j += 8) - { - for(c = 0;c < numchans;c++) - { - for(k = 0;k < 8;k++) - { - int diff = src[(j+k)*numchans + c] - sample[c]; - int step = IMAStep_size[index[c]]; - int nibble; - - nibble = 0; - if(diff < 0) - { - nibble = 0x8; - diff = -diff; - } - - diff = mini(step*2, diff); - nibble |= (diff*8/step - 1) / 2; - - sample[c] += IMA4Codeword[nibble] * step / 8; - sample[c] = clampi(sample[c], -32768, 32767); - - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); - - if(!(k&1)) *dst = nibble; - else *(dst++) |= nibble<<4; - } - } - } -} - - -static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchans, ALsizei align) +static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) { ALubyte blockpred[MAX_INPUT_CHANNELS]; ALint delta[MAX_INPUT_CHANNELS]; @@ -417,217 +243,9 @@ static void DecodeMSADPCMBlock(ALshort *dst, const ALmsadpcm *src, ALint numchan } } -/* NOTE: This encoder is pretty dumb/simplistic. Some kind of pre-processing - * that tries to find the optimal block predictors would be nice, at least. A - * multi-pass method that can generate better deltas would be good, too. */ -static void EncodeMSADPCMBlock(ALmsadpcm *dst, const ALshort *src, ALint *sample, ALint numchans, ALsizei align) -{ - ALubyte blockpred[MAX_INPUT_CHANNELS]; - ALint delta[MAX_INPUT_CHANNELS]; - ALshort samples[MAX_INPUT_CHANNELS][2]; - ALint i, j; - /* Block predictor */ - for(i = 0;i < numchans;i++) - { - /* FIXME: Calculate something better. */ - blockpred[i] = 0; - *(dst++) = blockpred[i]; - } - /* Initial delta */ - for(i = 0;i < numchans;i++) - { - delta[i] = 16; - *(dst++) = (delta[i] ) & 0xff; - *(dst++) = (delta[i]>>8) & 0xff; - } - /* Initial sample 1 */ - for(i = 0;i < numchans;i++) - { - samples[i][0] = src[1*numchans + i]; - *(dst++) = (samples[i][0] ) & 0xff; - *(dst++) = (samples[i][0]>>8) & 0xff; - } - /* Initial sample 2 */ - for(i = 0;i < numchans;i++) - { - samples[i][1] = src[i]; - *(dst++) = (samples[i][1] ) & 0xff; - *(dst++) = (samples[i][1]>>8) & 0xff; - } - - for(j = 2;j < align;j++) - { - for(i = 0;i < numchans;i++) - { - const ALint num = (j*numchans) + i; - ALint nibble = 0; - ALint bias; - - sample[i] = (samples[i][0]*MSADPCMAdaptionCoeff[blockpred[i]][0] + - samples[i][1]*MSADPCMAdaptionCoeff[blockpred[i]][1]) / 256; - - nibble = src[num] - sample[i]; - if(nibble >= 0) - bias = delta[i] / 2; - else - bias = -delta[i] / 2; - - nibble = (nibble + bias) / delta[i]; - nibble = clampi(nibble, -8, 7)&0x0f; - - sample[i] += ((nibble^0x08)-0x08) * delta[i]; - sample[i] = clampi(sample[i], -32768, 32767); - - samples[i][1] = samples[i][0]; - samples[i][0] = sample[i]; - - delta[i] = (MSADPCMAdaption[nibble] * delta[i]) / 256; - delta[i] = maxi(16, delta[i]); - - if(!(num&1)) - *dst = nibble << 4; - else - { - *dst |= nibble; - dst++; - } - } - } -} - - -/* Define same-type pass-through sample conversion functions (excludes ADPCM, - * which are block-based). */ -#define DECL_TEMPLATE(T) \ -static inline T Conv_##T##_##T(T val) { return val; } - -DECL_TEMPLATE(ALubyte); -DECL_TEMPLATE(ALshort); -DECL_TEMPLATE(ALalaw); -DECL_TEMPLATE(ALmulaw); - -/* Slightly special handling for floats and doubles (converts NaN to 0, and - * allows float<->double pass-through). - */ -static inline ALfloat Conv_ALfloat_ALfloat(ALfloat val) -{ return (val==val) ? val : 0.0f; } -static inline ALfloat Conv_ALfloat_ALdouble(ALdouble val) -{ return (val==val) ? (ALfloat)val : 0.0f; } -static inline ALdouble Conv_ALdouble_ALfloat(ALfloat val) -{ return (val==val) ? (ALdouble)val : 0.0; } -static inline ALdouble Conv_ALdouble_ALdouble(ALdouble val) -{ return (val==val) ? val : 0.0; } - -#undef DECL_TEMPLATE - -/* Define int-type to int-type functions */ -static inline ALubyte Conv_ALubyte_ALshort(ALshort val) { return (val>>8) + 128; } -static inline ALshort Conv_ALshort_ALubyte(ALubyte val) { return (val-128) << 8; } - -/* Define int-type to fp functions */ -static inline ALfloat Conv_ALfloat_ALubyte(ALubyte val) { return (val-128) * (1.0f/128.0f); } -static inline ALdouble Conv_ALdouble_ALubyte(ALubyte val) { return (val-128) * (1.0/128.0); } -static inline ALfloat Conv_ALfloat_ALshort(ALshort val) { return val * (1.0f/32768.0f); } -static inline ALdouble Conv_ALdouble_ALshort(ALshort val) { return val * (1.0/32768.0); } - -/* Define fp to int-type functions */ -static inline ALubyte Conv_ALubyte_ALfloat(ALfloat val) -{ - val *= 128.0f; - if(val >= 127.0f) return 255; - if(val <= -128.0f) return 0; - return (ALbyte)val + 128; -} -static inline ALubyte Conv_ALubyte_ALdouble(ALdouble val) { return Conv_ALubyte_ALfloat(val); } -static inline ALshort Conv_ALshort_ALfloat(ALfloat val) -{ - val *= 32768.0f; - if(val >= 32767.0f) return 32767; - if(val <= -32768.0f) return -32768; - return (ALshort)val; -} -static inline ALshort Conv_ALshort_ALdouble(ALdouble val) { return Conv_ALshort_ALfloat(val); } - -/* Define muLaw and aLaw functions (goes through short functions). */ -#define DECL_TEMPLATE(T) \ -static inline ALmulaw Conv_ALmulaw_##T(T val) \ -{ return EncodeMuLaw(Conv_ALshort_##T(val)); } \ -static inline T Conv_##T##_ALmulaw(ALmulaw val) \ -{ return Conv_##T##_ALshort(DecodeMuLaw(val)); } \ - \ -static inline ALalaw Conv_ALalaw_##T(T val) \ -{ return EncodeALaw(Conv_ALshort_##T(val)); } \ -static inline T Conv_##T##_ALalaw(ALalaw val) \ -{ return Conv_##T##_ALshort(DecodeALaw(val)); } - -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) - -#undef DECL_TEMPLATE - -/* Define muLaw <-> aLaw functions. */ -static inline ALalaw Conv_ALalaw_ALmulaw(ALmulaw val) -{ return EncodeALaw(DecodeMuLaw(val)); } -static inline ALmulaw Conv_ALmulaw_ALalaw(ALalaw val) -{ return EncodeMuLaw(DecodeALaw(val)); } - - -#define DECL_TEMPLATE(T1, T2) \ -static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALsizei numchans, \ - ALsizei len, ALsizei UNUSED(align)) \ -{ \ - ALsizei i; \ - len *= numchans; \ - for(i = 0;i < len;i++) \ - *(dst++) = Conv_##T1##_##T2(*(src++)); \ -} - -#define DECL_TEMPLATE2(T) \ -DECL_TEMPLATE(T, ALubyte) \ -DECL_TEMPLATE(T, ALshort) \ -DECL_TEMPLATE(T, ALfloat) \ -DECL_TEMPLATE(T, ALdouble) \ -DECL_TEMPLATE(T, ALmulaw) \ -DECL_TEMPLATE(T, ALalaw) - -DECL_TEMPLATE2(ALubyte) -DECL_TEMPLATE2(ALshort) -DECL_TEMPLATE2(ALfloat) -DECL_TEMPLATE2(ALdouble) -DECL_TEMPLATE2(ALmulaw) -DECL_TEMPLATE2(ALalaw) - -#undef DECL_TEMPLATE2 -#undef DECL_TEMPLATE - -#define DECL_TEMPLATE(T) \ -static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALsizei numchans, \ - ALsizei len, ALsizei align) \ -{ \ - ALsizei byte_align = ((align-1)/2 + 4) * numchans; \ - DECL_VLA(ALshort, tmp, align*numchans); \ - ALsizei i, j, k; \ - \ - assert(align > 0 && (len%align) == 0); \ - for(i = 0;i < len;i += align) \ - { \ - DecodeIMA4Block(tmp, src, numchans, align); \ - src += byte_align; \ - \ - for(j = 0;j < align;j++) \ - { \ - for(k = 0;k < numchans;k++) \ - *(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \ - } \ - } \ -} - -DECL_TEMPLATE(ALubyte) -static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numchans, - ALsizei len, ALsizei align) +void Convert_ALshort_ALima4(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align) { ALsizei byte_align = ((align-1)/2 + 4) * numchans; ALsizei i; @@ -640,88 +258,9 @@ static void Convert_ALshort_ALima4(ALshort *dst, const ALima4 *src, ALsizei numc dst += align*numchans; } } -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - -#define DECL_TEMPLATE(T) \ -static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALsizei numchans, \ - ALsizei len, ALsizei align) \ -{ \ - ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ - ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ - ALsizei byte_align = ((align-1)/2 + 4) * numchans; \ - DECL_VLA(ALshort, tmp, align*numchans); \ - ALsizei i, j, k; \ - \ - assert(align > 0 && (len%align) == 0); \ - for(i = 0;i < len;i += align) \ - { \ - for(j = 0;j < align;j++) \ - { \ - for(k = 0;k < numchans;k++) \ - tmp[j*numchans + k] = Conv_ALshort_##T(*(src++)); \ - } \ - EncodeIMA4Block(dst, tmp, sample, index, numchans, align); \ - dst += byte_align; \ - } \ -} - -DECL_TEMPLATE(ALubyte) -static void Convert_ALima4_ALshort(ALima4 *dst, const ALshort *src, - ALsizei numchans, ALsizei len, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; - ALint index[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; - ALsizei byte_align = ((align-1)/2 + 4) * numchans; - ALsizei i; - - assert(align > 0 && (len%align) == 0); - for(i = 0;i < len;i += align) - { - EncodeIMA4Block(dst, src, sample, index, numchans, align); - src += align*numchans; - dst += byte_align; - } -} -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - - -#define DECL_TEMPLATE(T) \ -static void Convert_##T##_ALmsadpcm(T *dst, const ALmsadpcm *src, \ - ALsizei numchans, ALsizei len, \ - ALsizei align) \ -{ \ - ALsizei byte_align = ((align-2)/2 + 7) * numchans; \ - DECL_VLA(ALshort, tmp, align*numchans); \ - ALsizei i, j, k; \ - \ - assert(align > 1 && (len%align) == 0); \ - for(i = 0;i < len;i += align) \ - { \ - DecodeMSADPCMBlock(tmp, src, numchans, align); \ - src += byte_align; \ - \ - for(j = 0;j < align;j++) \ - { \ - for(k = 0;k < numchans;k++) \ - *(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \ - } \ - } \ -} -DECL_TEMPLATE(ALubyte) -static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, - ALsizei numchans, ALsizei len, - ALsizei align) +void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALubyte *src, ALsizei numchans, ALsizei len, + ALsizei align) { ALsizei byte_align = ((align-2)/2 + 7) * numchans; ALsizei i; @@ -734,163 +273,3 @@ static void Convert_ALshort_ALmsadpcm(ALshort *dst, const ALmsadpcm *src, dst += align*numchans; } } -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - -#define DECL_TEMPLATE(T) \ -static void Convert_ALmsadpcm_##T(ALmsadpcm *dst, const T *src, \ - ALsizei numchans, ALsizei len, \ - ALsizei align) \ -{ \ - ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; \ - ALsizei byte_align = ((align-2)/2 + 7) * numchans; \ - DECL_VLA(ALshort, tmp, align*numchans); \ - ALsizei i, j, k; \ - \ - assert(align > 1 && (len%align) == 0); \ - for(i = 0;i < len;i += align) \ - { \ - for(j = 0;j < align;j++) \ - { \ - for(k = 0;k < numchans;k++) \ - tmp[j*numchans + k] = Conv_ALshort_##T(*(src++)); \ - } \ - EncodeMSADPCMBlock(dst, tmp, sample, numchans, align); \ - dst += byte_align; \ - } \ -} - -DECL_TEMPLATE(ALubyte) -static void Convert_ALmsadpcm_ALshort(ALmsadpcm *dst, const ALshort *src, - ALsizei numchans, ALsizei len, ALsizei align) -{ - ALint sample[MAX_INPUT_CHANNELS] = {0,0,0,0,0,0,0,0}; - ALsizei byte_align = ((align-2)/2 + 7) * numchans; - ALsizei i; - - assert(align > 1 && (len%align) == 0); - for(i = 0;i < len;i += align) - { - EncodeMSADPCMBlock(dst, src, sample, numchans, align); - src += align*numchans; - dst += byte_align; - } -} -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - -/* NOTE: We don't store compressed samples internally, so these conversions - * should never happen. */ -static void Convert_ALima4_ALima4(ALima4* UNUSED(dst), const ALima4* UNUSED(src), - ALsizei UNUSED(numchans), ALsizei UNUSED(len), - ALsizei UNUSED(align)) -{ - ERR("Unexpected IMA4-to-IMA4 conversion!\n"); -} - -static void Convert_ALmsadpcm_ALmsadpcm(ALmsadpcm* UNUSED(dst), const ALmsadpcm* UNUSED(src), - ALsizei UNUSED(numchans), ALsizei UNUSED(len), - ALsizei UNUSED(align)) -{ - ERR("Unexpected MSADPCM-to-MSADPCM conversion!\n"); -} - -static void Convert_ALmsadpcm_ALima4(ALmsadpcm* UNUSED(dst), const ALima4* UNUSED(src), - ALsizei UNUSED(numchans), ALsizei UNUSED(len), - ALsizei UNUSED(align)) -{ - ERR("Unexpected IMA4-to-MSADPCM conversion!\n"); -} - -static void Convert_ALima4_ALmsadpcm(ALima4* UNUSED(dst), const ALmsadpcm* UNUSED(src), - ALsizei UNUSED(numchans), ALsizei UNUSED(len), - ALsizei UNUSED(align)) -{ - ERR("Unexpected MSADPCM-to-IMA4 conversion!\n"); -} - - -#define DECL_TEMPLATE(T) \ -static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ - ALsizei numchans, ALsizei len, ALsizei align) \ -{ \ - switch(srcType) \ - { \ - case UserFmtUByte: \ - Convert_##T##_ALubyte(dst, src, numchans, len, align); \ - break; \ - case UserFmtShort: \ - Convert_##T##_ALshort(dst, src, numchans, len, align); \ - break; \ - case UserFmtFloat: \ - Convert_##T##_ALfloat(dst, src, numchans, len, align); \ - break; \ - case UserFmtDouble: \ - Convert_##T##_ALdouble(dst, src, numchans, len, align); \ - break; \ - case UserFmtMulaw: \ - Convert_##T##_ALmulaw(dst, src, numchans, len, align); \ - break; \ - case UserFmtAlaw: \ - Convert_##T##_ALalaw(dst, src, numchans, len, align); \ - break; \ - case UserFmtIMA4: \ - Convert_##T##_ALima4(dst, src, numchans, len, align); \ - break; \ - case UserFmtMSADPCM: \ - Convert_##T##_ALmsadpcm(dst, src, numchans, len, align); \ - break; \ - } \ -} - -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) -DECL_TEMPLATE(ALima4) -DECL_TEMPLATE(ALmsadpcm) - -#undef DECL_TEMPLATE - - -void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, - enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align) -{ - switch(dstType) - { - case UserFmtUByte: - Convert_ALubyte(dst, src, srcType, numchans, len, align); - break; - case UserFmtShort: - Convert_ALshort(dst, src, srcType, numchans, len, align); - break; - case UserFmtFloat: - Convert_ALfloat(dst, src, srcType, numchans, len, align); - break; - case UserFmtDouble: - Convert_ALdouble(dst, src, srcType, numchans, len, align); - break; - case UserFmtMulaw: - Convert_ALmulaw(dst, src, srcType, numchans, len, align); - break; - case UserFmtAlaw: - Convert_ALalaw(dst, src, srcType, numchans, len, align); - break; - case UserFmtIMA4: - Convert_ALima4(dst, src, srcType, numchans, len, align); - break; - case UserFmtMSADPCM: - Convert_ALmsadpcm(dst, src, srcType, numchans, len, align); - break; - } -} -- cgit v1.2.3 From ca07e210a7790272718305529a3e2e5ee0ea6df2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Jan 2018 23:50:47 -0800 Subject: Remove now-unused alloca and VLA checks --- CMakeLists.txt | 16 ---------------- config.h.in | 6 ------ 2 files changed, 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd371f70..76aa19b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,16 +228,6 @@ IF(HAVE_LIBLOG) SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} log) ENDIF() -# Check if we have C99 variable length arrays -CHECK_C_SOURCE_COMPILES( -"int main(int argc, char *argv[]) - { - volatile int tmp[argc]; - tmp[0] = argv[0][0]; - return tmp[0]; - }" -HAVE_C99_VLA) - # Check if we have C99 bool CHECK_C_SOURCE_COMPILES( "int main(int argc, char *argv[]) @@ -506,12 +496,6 @@ CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F) -IF(NOT HAVE_C99_VLA) - CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA) - IF(NOT HAVE_ALLOCA) - MESSAGE(FATAL_ERROR "No alloca function found, please report!") - ENDIF() -ENDIF() IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP) diff --git a/config.h.in b/config.h.in index 0bee5c98..bc4e6432 100644 --- a/config.h.in +++ b/config.h.in @@ -104,9 +104,6 @@ /* Define to the size of a long long int type */ #cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} -/* Define if we have C99 variable-length array support */ -#cmakedefine HAVE_C99_VLA - /* Define if we have C99 _Bool support */ #cmakedefine HAVE_C99_BOOL @@ -143,9 +140,6 @@ /* Define if we have pthread_np.h */ #cmakedefine HAVE_PTHREAD_NP_H -/* Define if we have alloca.h */ -#cmakedefine HAVE_ALLOCA_H - /* Define if we have malloc.h */ #cmakedefine HAVE_MALLOC_H -- cgit v1.2.3 From f1f7fba3b97c9523a6bd9a12d0edf799f457b602 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 00:23:19 -0800 Subject: Don't convert/copy samples with a NULL dest buffer Only happens with a 0 size, so there's nothing to copy or convert anyway. --- OpenAL32/alBuffer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 9acbb148..2189f015 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -939,7 +939,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm ALBuf->OriginalSize = frames / align * byte_align; ALBuf->OriginalAlign = align; assert(DstType == FmtShort); - if(data != NULL) + if(data != NULL && ALBuf->data != NULL) Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align); } else if(SrcType == UserFmtMSADPCM) @@ -948,18 +948,16 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm ALBuf->OriginalSize = frames / align * byte_align; ALBuf->OriginalAlign = align; assert(DstType == FmtShort); - if(data != NULL) + if(data != NULL && ALBuf->data != NULL) Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align); } else { ALBuf->OriginalSize = frames * FrameSize; ALBuf->OriginalAlign = 1; - if(data != NULL) - { - assert((long)SrcType == (long)DstType); + assert((long)SrcType == (long)DstType); + if(data != NULL && ALBuf->data != NULL) memcpy(ALBuf->data, data, frames*FrameSize); - } } ALBuf->Frequency = freq; -- cgit v1.2.3 From 4a368ab9059fef78eb9c664052eab92cd6ea6096 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 10:48:55 -0800 Subject: Fix the return type of the al_fwrite wrapper --- utils/openal-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/openal-info.c b/utils/openal-info.c index 617550f2..12dc6311 100644 --- a/utils/openal-info.c +++ b/utils/openal-info.c @@ -81,7 +81,7 @@ static void al_fprintf(FILE *file, const char *fmt, ...) #define fprintf al_fprintf #define printf(...) al_fprintf(stdout, __VA_ARGS__) -static int al_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *file) +static size_t al_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *file) { char str[1024]; WCHAR *wstr; -- cgit v1.2.3 From fce72610bbed5705c12e38b84a2e088f1039e375 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 11:34:16 -0800 Subject: Add a flag for alBufferData to non-destructively resize the data Requires having the same format as the last call to alBufferData. Also only makes sense when given a NULL data pointer, as otherwise the internal data will be overwritten anyway. --- OpenAL32/Include/alMain.h | 2 ++ OpenAL32/alBuffer.c | 30 +++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 358b0bf6..6c30776b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -48,9 +48,11 @@ #endif #ifndef AL_SOFT_map_buffer +#define AL_SOFT_map_buffer 1 typedef unsigned int ALbitfieldSOFT; #define AL_MAP_READ_BIT_SOFT 0x01000000 #define AL_MAP_WRITE_BIT_SOFT 0x02000000 +#define AL_PRESERVE_DATA_BIT_SOFT 0x04000000 typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); #ifdef AL_ALEXT_PROTOTYPES diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 2189f015..d6014cc6 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -51,8 +51,9 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); #define FORMAT_MASK 0x00ffffff -#define ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) -#define INVALID_FLAG_MASK ~(FORMAT_MASK | ACCESS_FLAGS) +#define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT) +#define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS) +#define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) @@ -158,7 +159,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(size >= 0 && freq > 0) || (format&INVALID_FLAG_MASK) != 0) + if(!(size >= 0 && freq > 0) || (format&INVALID_FORMAT_MASK) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if(DecomposeUserFormat(format&FORMAT_MASK, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); @@ -179,7 +180,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&ACCESS_FLAGS); + data, align, format&CONSTRUCT_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -190,7 +191,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&ACCESS_FLAGS); + data, align, format&CONSTRUCT_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -201,7 +202,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&ACCESS_FLAGS); + data, align, format&CONSTRUCT_FLAGS); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -226,7 +227,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!access || (access&~(AL_MAP_READ_BIT_SOFT|AL_MAP_WRITE_BIT_SOFT)) != 0) + if(!access || (access&~MAP_ACCESS_FLAGS) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); WriteLock(&albuf->lock); @@ -911,6 +912,16 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm return AL_INVALID_OPERATION; } + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + /* Can only preserve data with the same format. */ + if(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType) + { + WriteUnlock(&ALBuf->lock); + return AL_INVALID_VALUE; + } + } + /* Round up to the next 16-byte multiple. This could reallocate only when * increasing or the new size is less than half the current, but then the * buffer's AL_SIZE would not be very reliable for accounting buffer memory @@ -927,6 +938,11 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm WriteUnlock(&ALBuf->lock); return AL_OUT_OF_MEMORY; } + if((access&AL_PRESERVE_DATA_BIT_SOFT)) + { + ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc); + if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); + } al_free(ALBuf->data); ALBuf->data = temp; ALBuf->BytesAlloc = newsize; -- cgit v1.2.3 From d6d6ec03f16dca3000fdc74dddda5e9a37dfdc6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 15:46:46 -0800 Subject: Don't bother allocating cleared memory for buffer storage --- OpenAL32/alBuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index d6014cc6..0fda943f 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -932,7 +932,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm newsize = (newsize+15) & ~0xf; if(newsize != ALBuf->BytesAlloc) { - void *temp = al_calloc(16, (size_t)newsize); + void *temp = al_malloc(16, (size_t)newsize); if(!temp && newsize) { WriteUnlock(&ALBuf->lock); -- cgit v1.2.3 From a852ecf8cec2a8ae8deba78213891232ac4dd1ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 15:52:53 -0800 Subject: Ensure proper alignment when preserving data too --- OpenAL32/alBuffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 0fda943f..7e8bf606 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -914,8 +914,9 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm if((access&AL_PRESERVE_DATA_BIT_SOFT)) { - /* Can only preserve data with the same format. */ - if(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType) + /* Can only preserve data with the same format and alignment. */ + if(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType || + ALBuf->OriginalAlign != align) { WriteUnlock(&ALBuf->lock); return AL_INVALID_VALUE; -- cgit v1.2.3 From ad61392318d3054d1c3810a6cc0ac0924dddab6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Jan 2018 16:17:45 -0800 Subject: Slightly simplify alBufferSubDataSOFT --- OpenAL32/alBuffer.c | 49 +++++++++++++------------------------------------ 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 7e8bf606..9e4249ec 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -305,55 +305,30 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons 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); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } + if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + if((long)srcchannels != (long)albuf->FmtChannels || srctype != albuf->OriginalType) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, unlock_done); if(align != albuf->OriginalAlign) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); if(albuf->MappedAccess != 0) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); + num_chans = ChannelsFromFmt(albuf->FmtChannels); + frame_size = num_chans * BytesFromFmt(albuf->FmtType); if(albuf->OriginalType == UserFmtIMA4) - { - byte_align = (albuf->OriginalAlign-1)/2 + 4; - byte_align *= ChannelsFromFmt(albuf->FmtChannels); - } + byte_align = ((align-1)/2 + 4) * num_chans; else if(albuf->OriginalType == UserFmtMSADPCM) - { - byte_align = (albuf->OriginalAlign-2)/2 + 7; - byte_align *= ChannelsFromFmt(albuf->FmtChannels); - } + byte_align = ((align-2)/2 + 7) * num_chans; else - { - byte_align = albuf->OriginalAlign; - byte_align *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); - } + byte_align = align * frame_size; if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset || (offset%byte_align) != 0 || (length%byte_align) != 0) - { - WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); - num_chans = ChannelsFromFmt(albuf->FmtChannels); - frame_size = num_chans * BytesFromFmt(albuf->FmtType); /* offset -> byte offset, length -> sample count */ offset = offset/byte_align * frame_size; length = length/byte_align * albuf->OriginalAlign; @@ -368,6 +343,8 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons assert((long)srctype == (long)albuf->FmtType); memcpy(dst, data, length*frame_size); } + +unlock_done: WriteUnlock(&albuf->lock); done: -- cgit v1.2.3 From 4f9a0460c4a0fc6df5dba8b98ee6ac4e3ed7d90a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 10:38:27 -0800 Subject: Add a flag for persistent mapping And a function to "flush" a mapped buffer --- OpenAL32/Include/alMain.h | 3 +++ OpenAL32/alBuffer.c | 49 +++++++++++++++++++++++++++++++++++++++++------ OpenAL32/alSource.c | 5 +++-- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6c30776b..d986adde 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -53,11 +53,14 @@ typedef unsigned int ALbitfieldSOFT; #define AL_MAP_READ_BIT_SOFT 0x01000000 #define AL_MAP_WRITE_BIT_SOFT 0x02000000 #define AL_PRESERVE_DATA_BIT_SOFT 0x04000000 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x08000000 typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); #ifdef AL_ALEXT_PROTOTYPES AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); #endif #endif diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 9e4249ec..b2302933 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -51,9 +51,9 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); #define FORMAT_MASK 0x00ffffff -#define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT) +#define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) #define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS) -#define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) +#define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) @@ -232,18 +232,18 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei WriteLock(&albuf->lock); if(((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) || - ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT))) + ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) || + ((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT))) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); if(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); - if(ReadRef(&albuf->ref) != 0 || albuf->MappedAccess != 0) + if(albuf->MappedAccess != 0 || + (!(access&AL_MAP_PERSISTENT_BIT_SOFT) && ReadRef(&albuf->ref) != 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; - if((access&AL_MAP_WRITE_BIT_SOFT) && !(access&AL_MAP_READ_BIT_SOFT)) - memset(retval, 0x55, length); unlock_done: WriteUnlock(&albuf->lock); @@ -281,6 +281,43 @@ done: ALCcontext_DecRef(context); } +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length) +{ + ALCdevice *device; + ALCcontext *context; + ALbuffer *albuf; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + LockBuffersRead(device); + if((albuf=LookupBuffer(device, buffer)) == NULL) + SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + + WriteLock(&albuf->lock); + if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) + alSetError(context, AL_INVALID_OPERATION); + /* TODO: Should check mapped range. */ + else if(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset) + alSetError(context, AL_INVALID_VALUE); + else + { + /* FIXME: Need to use some method of double-buffering for the mixer and + * app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write where + * OpenAL's reading, and hope for the best... + */ + ATOMIC_THREAD_FENCE(almemory_order_seq_cst); + } + WriteUnlock(&albuf->lock); + +done: + UnlockBuffersRead(device); + ALCcontext_DecRef(context); +} + AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length) { enum UserFmtChannels srcchannels = UserFmtMono; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 24f48895..8b3cb305 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -760,7 +760,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } WriteLock(&Source->queue_lock); - if(buffer && buffer->MappedAccess != 0) + if(buffer && buffer->MappedAccess != 0 && + !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -2888,7 +2889,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu ReadLock(&buffer->lock); IncrementRef(&buffer->ref); - if(buffer->MappedAccess != 0) + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { WriteUnlock(&source->queue_lock); SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error); -- cgit v1.2.3 From 9ee58fd454dae3cab7d9413e84ce4e22dd6c49ef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 10:51:23 -0800 Subject: Track the buffer's mapped section --- OpenAL32/Include/alBuffer.h | 2 ++ OpenAL32/alBuffer.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index e89d3c96..b6d77436 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -90,6 +90,8 @@ typedef struct ALbuffer { ATOMIC(ALsizei) PackAlign; ALbitfieldSOFT MappedAccess; + ALsizei MappedOffset; + ALsizei MappedSize; /* Number of times buffer was attached to a source (deletion can only occur when 0) */ RefCount ref; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index b2302933..d5e6790a 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -244,6 +244,8 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; + albuf->MappedOffset = offset; + albuf->MappedSize = length; unlock_done: WriteUnlock(&albuf->lock); @@ -273,7 +275,11 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) if(albuf->MappedAccess == 0) alSetError(context, AL_INVALID_OPERATION); else + { albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; + } WriteUnlock(&albuf->lock); done: @@ -298,9 +304,8 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A WriteLock(&albuf->lock); if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) alSetError(context, AL_INVALID_OPERATION); - /* TODO: Should check mapped range. */ - else if(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset) + else if(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) alSetError(context, AL_INVALID_VALUE); else { -- cgit v1.2.3 From b05592b0ab75372531684405b25b0b7105250bc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 10:59:51 -0800 Subject: Ensure read or write flags are specified with persistent mappings --- OpenAL32/alBuffer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index d5e6790a..45f63832 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -53,6 +53,7 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); #define FORMAT_MASK 0x00ffffff #define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) #define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS) +#define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) #define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) @@ -161,6 +162,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(size >= 0 && freq > 0) || (format&INVALID_FORMAT_MASK) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if((format&AL_MAP_PERSISTENT_BIT_SOFT) && !(format&MAP_READ_WRITE_FLAGS)) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if(DecomposeUserFormat(format&FORMAT_MASK, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); @@ -227,10 +230,13 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!access || (access&~MAP_ACCESS_FLAGS) != 0) + if(!(access&MAP_READ_WRITE_FLAGS) || (access&~MAP_ACCESS_FLAGS) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); WriteLock(&albuf->lock); + if((ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) || + albuf->MappedAccess != 0) + SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); if(((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) || ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) || ((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT))) @@ -238,9 +244,6 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei if(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); - if(albuf->MappedAccess != 0 || - (!(access&AL_MAP_PERSISTENT_BIT_SOFT) && ReadRef(&albuf->ref) != 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; -- cgit v1.2.3 From 4ebb97bf737713b07642266ab54055f13dbd9833 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 11:15:25 -0800 Subject: Test mapped buffers in alffplay --- examples/alffplay.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 65719807..f9ca8324 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -37,6 +37,25 @@ extern "C" { #include "AL/al.h" #include "AL/alext.h" +extern "C" { +#ifndef AL_SOFT_map_buffer +#define AL_SOFT_map_buffer 1 +typedef unsigned int ALbitfieldSOFT; +#define AL_MAP_READ_BIT_SOFT 0x01000000 +#define AL_MAP_WRITE_BIT_SOFT 0x02000000 +#define AL_PRESERVE_DATA_BIT_SOFT 0x04000000 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x08000000 +typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); +#endif +#endif +} + namespace { using nanoseconds = std::chrono::nanoseconds; @@ -51,6 +70,9 @@ bool EnableDirectOut = false; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT; +LPALMAPBUFFERSOFT alMapBufferSOFT; +LPALUNMAPBUFFERSOFT alUnmapBufferSOFT; + const seconds AVNoSyncThreshold(10); const milliseconds VideoSyncThreshold(10); @@ -225,7 +247,7 @@ struct AudioState { int getSync(); int decodeFrame(); - int readAudio(uint8_t *samples, int length); + bool readAudio(uint8_t *samples, int length); int handler(); }; @@ -564,7 +586,7 @@ static void sample_dup(uint8_t *out, const uint8_t *in, int count, int frame_siz } -int AudioState::readAudio(uint8_t *samples, int length) +bool AudioState::readAudio(uint8_t *samples, int length) { int sample_skip = getSync(); int audio_size = 0; @@ -619,8 +641,10 @@ int AudioState::readAudio(uint8_t *samples, int length) samples += rem*mFrameSize; audio_size += rem; } + if(audio_size <= 0) + return false; - if(audio_size < length && audio_size > 0) + if(audio_size < length) { int rem = length - audio_size; std::fill_n(samples, rem*mFrameSize, @@ -628,8 +652,7 @@ int AudioState::readAudio(uint8_t *samples, int length) mCurrentPts += nanoseconds(seconds(rem)) / mCodecCtx->sample_rate; audio_size += rem; } - - return audio_size * mFrameSize; + return true; } @@ -743,9 +766,9 @@ int AudioState::handler() mFormat = AL_FORMAT_STEREO16; } } + void *samples = nullptr; ALsizei buffer_len = std::chrono::duration_cast>( mCodecCtx->sample_rate * AudioBufferTime).count() * mFrameSize; - void *samples = av_malloc(buffer_len); mSamples = NULL; mSamplesMax = 0; @@ -779,6 +802,23 @@ int AudioState::handler() if(EnableDirectOut) alSourcei(mSource, AL_DIRECT_CHANNELS_SOFT, AL_TRUE); + if(alGetError() != AL_NO_ERROR) + goto finish; + + if(!alMapBufferSOFT) + samples = av_malloc(buffer_len); + else + { + for(ALuint bufid : mBuffers) + alBufferData(bufid, mFormat | AL_MAP_WRITE_BIT_SOFT, nullptr, buffer_len, + mCodecCtx->sample_rate); + if(alGetError() != AL_NO_ERROR) + { + fprintf(stderr, "Failed to use mapped buffers\n"); + samples = av_malloc(buffer_len); + } + } + while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed)) { /* First remove any processed buffers. */ @@ -797,19 +837,25 @@ int AudioState::handler() alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); while((ALuint)queued < mBuffers.size()) { - int audio_size; + ALuint bufid = mBuffers[mBufferIdx]; - /* Read the next chunk of data, fill the buffer, and queue it on + uint8_t *ptr = reinterpret_cast( + samples ? samples : alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT) + ); + if(!ptr) break; + + /* Read the next chunk of data, filling the buffer, and queue it on * the source */ - audio_size = readAudio(reinterpret_cast(samples), buffer_len); - if(audio_size <= 0) break; + bool got_audio = readAudio(ptr, buffer_len); + if(!samples) alUnmapBufferSOFT(bufid); + if(!got_audio) break; - ALuint bufid = mBuffers[mBufferIdx++]; - mBufferIdx %= mBuffers.size(); + if(samples) + alBufferData(bufid, mFormat, samples, buffer_len, mCodecCtx->sample_rate); - alBufferData(bufid, mFormat, samples, audio_size, mCodecCtx->sample_rate); alSourceQueueBuffers(mSource, 1, &bufid); - queued++; + mBufferIdx = (mBufferIdx+1) % mBuffers.size(); + ++queued; } if(queued == 0) break; @@ -1590,6 +1636,14 @@ int main(int argc, char *argv[]) alGetProcAddress("alGetSourcei64vSOFT") ); } + if(alIsExtensionPresent("AL_SOFTX_map_buffer")) + { + std::cout<< "Found AL_SOFT_map_buffer" <( + alGetProcAddress("alMapBufferSOFT")); + alUnmapBufferSOFT = reinterpret_cast( + alGetProcAddress("alUnmapBufferSOFT")); + } if(fileidx < argc && strcmp(argv[fileidx], "-direct") == 0) { -- cgit v1.2.3 From 2ac0adaebbc9b7378f1ec85d7495a044c7580239 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 14:33:30 -0800 Subject: Use a new proper buffer function with a flags parameter Rather than hackily combining bit flags with the format, to increase the number of potential flags. alBufferData now behaves as if calling alBufferStorageSOFT with a flags value of 0. --- Alc/ALc.c | 4 ++++ OpenAL32/Include/alMain.h | 10 ++++++---- OpenAL32/alBuffer.c | 19 ++++++++++--------- examples/alffplay.cpp | 23 +++++++++++------------ 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dbdc2986..0d8bbe86 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -283,8 +283,10 @@ static const struct { DECL(alGetStringiSOFT), + DECL(alBufferStorageSOFT), DECL(alMapBufferSOFT), DECL(alUnmapBufferSOFT), + DECL(alFlushMappedBufferSOFT), }; #undef DECL @@ -649,6 +651,8 @@ static const struct { DECL(AL_MAP_READ_BIT_SOFT), DECL(AL_MAP_WRITE_BIT_SOFT), + DECL(AL_MAP_PERSISTENT_BIT_SOFT), + DECL(AL_PRESERVE_DATA_BIT_SOFT), }; #undef DECL diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d986adde..17bff871 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -50,14 +50,16 @@ #ifndef AL_SOFT_map_buffer #define AL_SOFT_map_buffer 1 typedef unsigned int ALbitfieldSOFT; -#define AL_MAP_READ_BIT_SOFT 0x01000000 -#define AL_MAP_WRITE_BIT_SOFT 0x02000000 -#define AL_PRESERVE_DATA_BIT_SOFT 0x04000000 -#define AL_MAP_PERSISTENT_BIT_SOFT 0x08000000 +#define AL_MAP_READ_BIT_SOFT 0x00000001 +#define AL_MAP_WRITE_BIT_SOFT 0x00000002 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 +#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 +typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); #ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 45f63832..1290ca23 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -50,9 +50,7 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); -#define FORMAT_MASK 0x00ffffff -#define CONSTRUCT_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) -#define INVALID_FORMAT_MASK ~(FORMAT_MASK | CONSTRUCT_FLAGS) +#define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) #define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) @@ -143,6 +141,9 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq) +{ alBufferStorageSOFT(buffer, format, data, size, freq, 0); } + +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags) { enum UserFmtChannels srcchannels = UserFmtMono; enum UserFmtType srctype = UserFmtUByte; @@ -160,11 +161,11 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(size >= 0 && freq > 0) || (format&INVALID_FORMAT_MASK) != 0) + if(!(size >= 0 && freq > 0) || (flags&INVALID_STORAGE_MASK) != 0) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if((format&AL_MAP_PERSISTENT_BIT_SOFT) && !(format&MAP_READ_WRITE_FLAGS)) + if((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if(DecomposeUserFormat(format&FORMAT_MASK, &srcchannels, &srctype) == AL_FALSE) + if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); @@ -183,7 +184,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&CONSTRUCT_FLAGS); + data, align, flags); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -194,7 +195,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&CONSTRUCT_FLAGS); + data, align, flags); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; @@ -205,7 +206,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, format&CONSTRUCT_FLAGS); + data, align, flags); if(err != AL_NO_ERROR) SET_ERROR_AND_GOTO(context, err, done); break; diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index f9ca8324..f372983a 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -41,18 +41,14 @@ extern "C" { #ifndef AL_SOFT_map_buffer #define AL_SOFT_map_buffer 1 typedef unsigned int ALbitfieldSOFT; -#define AL_MAP_READ_BIT_SOFT 0x01000000 -#define AL_MAP_WRITE_BIT_SOFT 0x02000000 -#define AL_PRESERVE_DATA_BIT_SOFT 0x04000000 -#define AL_MAP_PERSISTENT_BIT_SOFT 0x08000000 +#define AL_MAP_READ_BIT_SOFT 0x00000001 +#define AL_MAP_WRITE_BIT_SOFT 0x00000002 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 +#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 +typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); -#endif #endif } @@ -70,6 +66,7 @@ bool EnableDirectOut = false; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT; +LPALBUFFERSTORAGESOFT alBufferStorageSOFT; LPALMAPBUFFERSOFT alMapBufferSOFT; LPALUNMAPBUFFERSOFT alUnmapBufferSOFT; @@ -805,13 +802,13 @@ int AudioState::handler() if(alGetError() != AL_NO_ERROR) goto finish; - if(!alMapBufferSOFT) + if(!alBufferStorageSOFT) samples = av_malloc(buffer_len); else { for(ALuint bufid : mBuffers) - alBufferData(bufid, mFormat | AL_MAP_WRITE_BIT_SOFT, nullptr, buffer_len, - mCodecCtx->sample_rate); + alBufferStorageSOFT(bufid, mFormat, nullptr, buffer_len, mCodecCtx->sample_rate, + AL_MAP_WRITE_BIT_SOFT); if(alGetError() != AL_NO_ERROR) { fprintf(stderr, "Failed to use mapped buffers\n"); @@ -1639,6 +1636,8 @@ int main(int argc, char *argv[]) if(alIsExtensionPresent("AL_SOFTX_map_buffer")) { std::cout<< "Found AL_SOFT_map_buffer" <( + alGetProcAddress("alBufferStorageSOFT")); alMapBufferSOFT = reinterpret_cast( alGetProcAddress("alMapBufferSOFT")); alUnmapBufferSOFT = reinterpret_cast( -- cgit v1.2.3 From def2547e4078cd92c86bb5225e1e2cc498a73778 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 16:03:06 -0800 Subject: Fix some 'may be used initialized' warnings --- OpenAL32/sample_cvt.c | 107 +++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/OpenAL32/sample_cvt.c b/OpenAL32/sample_cvt.c index ff7c8776..4a85f74a 100644 --- a/OpenAL32/sample_cvt.c +++ b/OpenAL32/sample_cvt.c @@ -130,9 +130,10 @@ const ALshort aLawDecompressionTable[256] = { static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) { - ALint sample[MAX_INPUT_CHANNELS], index[MAX_INPUT_CHANNELS]; - ALuint code[MAX_INPUT_CHANNELS]; - ALsizei j,k,c; + ALint sample[MAX_INPUT_CHANNELS] = { 0 }; + ALint index[MAX_INPUT_CHANNELS] = { 0 }; + ALuint code[MAX_INPUT_CHANNELS] = { 0 }; + ALsizei c, i; for(c = 0;c < numchans;c++) { @@ -148,77 +149,77 @@ static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans, AL dst[c] = sample[c]; } - for(j = 1;j < align;j += 8) + for(i = 1;i < align;i++) { - for(c = 0;c < numchans;c++) + if((i&7) == 1) { - code[c] = *(src++); - code[c] |= *(src++) << 8; - code[c] |= *(src++) << 16; - code[c] |= *(src++) << 24; + for(c = 0;c < numchans;c++) + { + code[c] = *(src++); + code[c] |= *(src++) << 8; + code[c] |= *(src++) << 16; + code[c] |= *(src++) << 24; + } } - for(k = 0;k < 8;k++) + for(c = 0;c < numchans;c++) { - for(c = 0;c < numchans;c++) - { - int nibble = code[c]&0xf; - code[c] >>= 4; + int nibble = code[c]&0xf; + code[c] >>= 4; - sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; - sample[c] = clampi(sample[c], -32768, 32767); + sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8; + sample[c] = clampi(sample[c], -32768, 32767); - index[c] += IMA4Index_adjust[nibble]; - index[c] = clampi(index[c], 0, 88); + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); - dst[(j+k)*numchans + c] = sample[c]; - } + *(dst++) = sample[c]; } } } static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, ALsizei align) { - ALubyte blockpred[MAX_INPUT_CHANNELS]; - ALint delta[MAX_INPUT_CHANNELS]; - ALshort samples[MAX_INPUT_CHANNELS][2]; - ALint i, j; + ALubyte blockpred[MAX_INPUT_CHANNELS] = { 0 }; + ALint delta[MAX_INPUT_CHANNELS] = { 0 }; + ALshort samples[MAX_INPUT_CHANNELS][2] = { { 0, 0 } }; + ALint c, i; - for(i = 0;i < numchans;i++) + for(c = 0;c < numchans;c++) { - blockpred[i] = *(src++); - blockpred[i] = minu(blockpred[i], 6); + blockpred[c] = *(src++); + blockpred[c] = minu(blockpred[c], 6); } - for(i = 0;i < numchans;i++) + for(c = 0;c < numchans;c++) { - delta[i] = *(src++); - delta[i] |= *(src++) << 8; - delta[i] = (delta[i]^0x8000) - 0x8000; + delta[c] = *(src++); + delta[c] |= *(src++) << 8; + delta[c] = (delta[c]^0x8000) - 32768; } - for(i = 0;i < numchans;i++) + for(c = 0;c < numchans;c++) { - samples[i][0] = *(src++); - samples[i][0] |= *(src++) << 8; - samples[i][0] = (samples[i][0]^0x8000) - 0x8000; + samples[c][0] = *(src++); + samples[c][0] |= *(src++) << 8; + samples[c][0] = (samples[c][0]^0x8000) - 32768; } - for(i = 0;i < numchans;i++) + for(c = 0;c < numchans;c++) { - samples[i][1] = *(src++); - samples[i][1] |= *(src++) << 8; - samples[i][1] = (samples[i][1]^0x8000) - 0x8000; + samples[c][1] = *(src++); + samples[c][1] |= *(src++) << 8; + samples[c][1] = (samples[c][1]^0x8000) - 0x8000; } /* Second sample is written first. */ - for(i = 0;i < numchans;i++) - *(dst++) = samples[i][1]; - for(i = 0;i < numchans;i++) - *(dst++) = samples[i][0]; + for(c = 0;c < numchans;c++) + *(dst++) = samples[c][1]; + for(c = 0;c < numchans;c++) + *(dst++) = samples[c][0]; - for(j = 2;j < align;j++) + for(i = 2;i < align;i++) { - for(i = 0;i < numchans;i++) + for(c = 0;c < numchans;c++) { - const ALint num = (j*numchans) + i; + const ALint num = (i*numchans) + c; ALint nibble, pred; /* Read the nibble (first is in the upper bits). */ @@ -227,16 +228,16 @@ static void DecodeMSADPCMBlock(ALshort *dst, const ALubyte *src, ALint numchans, else nibble = (*(src++))&0x0f; - pred = (samples[i][0]*MSADPCMAdaptionCoeff[blockpred[i]][0] + - samples[i][1]*MSADPCMAdaptionCoeff[blockpred[i]][1]) / 256; - pred += ((nibble^0x08) - 0x08) * delta[i]; + pred = (samples[c][0]*MSADPCMAdaptionCoeff[blockpred[c]][0] + + samples[c][1]*MSADPCMAdaptionCoeff[blockpred[c]][1]) / 256; + pred += ((nibble^0x08) - 0x08) * delta[c]; pred = clampi(pred, -32768, 32767); - samples[i][1] = samples[i][0]; - samples[i][0] = pred; + samples[c][1] = samples[c][0]; + samples[c][0] = pred; - delta[i] = (MSADPCMAdaption[nibble] * delta[i]) / 256; - delta[i] = maxi(16, delta[i]); + delta[c] = (MSADPCMAdaption[nibble] * delta[c]) / 256; + delta[c] = maxi(16, delta[c]); *(dst++) = pred; } -- cgit v1.2.3 From 2266a9e01ef68f112e87eb49bf1621a6456531a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 17:42:39 -0800 Subject: Declare the beginnings of an event extension --- OpenAL32/Include/alMain.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 17bff871..4b0f3b81 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -66,6 +66,29 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A #endif #endif +#ifndef AL_SOFT_events +#define AL_SOFT_events 1 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0xffe0 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0xffe1 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0xffe2 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0xffe3 +#define AL_EVENT_TYPE_ERROR_SOFT 0xffe4 +#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0xffe5 +typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **params); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **params); +#endif +#endif + #if defined(_WIN64) #define SZFMT "%I64u" -- cgit v1.2.3 From caa3b4f7f833278498a78f261e8badb85fd2896b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Jan 2018 18:25:59 -0800 Subject: Handle event properties This just implements the event methods insofar as tracked state. No events are generated/reported yet. --- Alc/ALc.c | 18 +++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alMain.h | 16 ++++++++++-- OpenAL32/alState.c | 58 ++++++++++++++++++++++++++++++++++++++++++ OpenAL32/event.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 OpenAL32/event.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 0d8bbe86..aa4634a0 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -287,6 +287,11 @@ static const struct { DECL(alMapBufferSOFT), DECL(alUnmapBufferSOFT), DECL(alFlushMappedBufferSOFT), + + DECL(alEventControlSOFT), + DECL(alEventCallbackSOFT), + DECL(alGetPointerSOFT), + DECL(alGetPointervSOFT), }; #undef DECL @@ -653,6 +658,13 @@ static const struct { DECL(AL_MAP_WRITE_BIT_SOFT), DECL(AL_MAP_PERSISTENT_BIT_SOFT), DECL(AL_PRESERVE_DATA_BIT_SOFT), + + DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), + DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), + DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), + DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), + DECL(AL_EVENT_TYPE_ERROR_SOFT), + DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), }; #undef DECL @@ -2534,6 +2546,10 @@ static ALvoid InitContext(ALCcontext *Context) Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); + almtx_init(&Context->EventLock, almtx_plain); + Context->EnabledEvts = 0; + Context->EventCb = NULL; + Context->EventParam = NULL; ATOMIC_INIT(&Context->Update, NULL); ATOMIC_INIT(&Context->FreeContextProps, NULL); @@ -2662,6 +2678,8 @@ static void FreeContext(ALCcontext *context) } TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); + almtx_destroy(&context->EventLock); + ALCdevice_DecRef(context->Device); context->Device = NULL; diff --git a/CMakeLists.txt b/CMakeLists.txt index 76aa19b9..29c0a3b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -694,6 +694,7 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c OpenAL32/alSource.c OpenAL32/alState.c OpenAL32/alThunk.c + OpenAL32/event.c OpenAL32/sample_cvt.c ) SET(ALC_OBJS Alc/ALc.c diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4b0f3b81..438f7ed5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -80,12 +80,12 @@ typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALui typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); -typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **params); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); #ifdef AL_ALEXT_PROTOTYPES AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **params); +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); #endif #endif @@ -565,6 +565,13 @@ struct ALCdevice_struct #define RECORD_THREAD_NAME "alsoft-record" +enum { + EventType_SourceStateChange = 1<<0, + EventType_BufferCompleted = 1<<1, + EventType_Error = 1<<2, + EventType_Performance = 1<<3, +}; + struct ALCcontext_struct { RefCount ref; @@ -612,6 +619,11 @@ struct ALCcontext_struct { ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; + almtx_t EventLock; + ALbitfieldSOFT EnabledEvts; + ALEVENTPROCSOFT EventCb; + void *EventParam; + /* Default effect slot */ struct ALeffectslot *DefaultSlot; diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index c8c81065..36afd46e 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -415,6 +415,64 @@ done: return value; } +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) +{ + ALCcontext *context; + void *value = NULL; + + context = GetContextRef(); + if(!context) return NULL; + + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + value = context->EventCb; + break; + + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + value = context->EventParam; + break; + + default: + SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + } + +done: + ALCcontext_DecRef(context); + + return value; +} + +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) +{ + ALCcontext *context; + + if(values) + { + switch(pname) + { + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + values[0] = alGetPointerSOFT(pname); + return; + } + } + + context = GetContextRef(); + if(!context) return; + + if(!(values)) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + switch(pname) + { + default: + SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + } + +done: + ALCcontext_DecRef(context); +} + AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) { ALCcontext *context; diff --git a/OpenAL32/event.c b/OpenAL32/event.c new file mode 100644 index 00000000..4e844ce9 --- /dev/null +++ b/OpenAL32/event.c @@ -0,0 +1,65 @@ + +#include "config.h" + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" +#include "alMain.h" +#include "alError.h" + + +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) +{ + ALCcontext *context; + ALbitfieldSOFT flags = 0; + ALsizei i; + + context = GetContextRef(); + if(!context) return; + + if(count < 0) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(count == 0) goto done; + if(!types) + SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + + for(i = 0;i < count;i++) + { + if(types[i] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) + flags |= EventType_BufferCompleted; + else if(types[i] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) + flags |= EventType_SourceStateChange; + else if(types[i] == AL_EVENT_TYPE_ERROR_SOFT) + flags |= EventType_Error; + else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT) + flags |= EventType_Performance; + else + SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + } + + almtx_lock(&context->EventLock); + + if(enable) + context->EnabledEvts |= flags; + else + context->EnabledEvts &= ~flags; + + almtx_unlock(&context->EventLock); +done: + ALCcontext_DecRef(context); +} + +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) +{ + ALCcontext *context; + + context = GetContextRef(); + if(!context) return; + + almtx_lock(&context->EventLock); + context->EventCb = callback; + context->EventParam = userParam; + almtx_unlock(&context->EventLock); + + ALCcontext_DecRef(context); +} -- cgit v1.2.3 From 786a05876e492074aba245209d11fb73d05ad60a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 12:10:48 -0800 Subject: Call the event callback when an error is generated Most errors don't yet provide correct object IDs or text messages for the AL error. --- OpenAL32/Include/alError.h | 8 +-- OpenAL32/alBuffer.c | 15 +++--- OpenAL32/alEffect.c | 18 +++---- OpenAL32/alError.c | 31 +++++++---- OpenAL32/alFilter.c | 18 +++---- OpenAL32/alSource.c | 128 ++++++++++++++++++++++----------------------- 6 files changed, 114 insertions(+), 104 deletions(-) diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index ab91d27b..f94802b3 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -9,20 +9,20 @@ extern "C" { extern ALboolean TrapALError; -ALvoid alSetError(ALCcontext *Context, ALenum errorCode); +ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const char *msg); #define SET_ERROR_AND_RETURN(ctx, err) do { \ - alSetError((ctx), (err)); \ + alSetError((ctx), (err), 0, "Unimplemented message"); \ return; \ } while(0) #define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \ - alSetError((ctx), (err)); \ + alSetError((ctx), (err), 0, "Unimplemented message"); \ return (val); \ } while(0) #define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \ - alSetError((ctx), (err)); \ + alSetError((ctx), (err), 0, "Unimplemented message"); \ goto lbl; \ } while(0) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 1290ca23..e707dc36 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -277,7 +277,7 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) WriteLock(&albuf->lock); if(albuf->MappedAccess == 0) - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, albuf->id, "Unmapping an unmapped buffer"); else { albuf->MappedAccess = 0; @@ -307,10 +307,11 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A WriteLock(&albuf->lock); if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, albuf->id, + "Flushing a buffer not mapped for writing"); else if(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) - alSetError(context, AL_INVALID_VALUE); + alSetError(context, AL_INVALID_VALUE, albuf->id, "Flushing an invalid range"); else { /* FIXME: Need to use some method of double-buffering for the mixer and @@ -408,7 +409,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, 0, "alBufferSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -422,7 +423,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, 0, "alBufferSubSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -436,7 +437,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, 0, "alGetBufferSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -448,7 +449,7 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format) context = GetContextRef(); if(!context) return AL_FALSE; - alSetError(context, AL_INVALID_OPERATION); + alSetError(context, AL_INVALID_OPERATION, 0, "alIsBufferFormatSupportedSOFT not supported"); ALCcontext_DecRef(context); return AL_FALSE; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index bb56e6a3..755d792e 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -167,7 +167,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { if(param == AL_EFFECT_TYPE) @@ -184,7 +184,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(isOk) InitEffectParams(ALEffect, value); else - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, effect, "Effect type not supported"); } else { @@ -216,7 +216,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ @@ -239,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ @@ -262,7 +262,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ @@ -285,7 +285,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { if(param == AL_EFFECT_TYPE) @@ -320,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ @@ -343,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ @@ -366,7 +366,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); else { /* Call the appropriate handler */ diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index 6c953977..8d138aa2 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -33,11 +33,12 @@ ALboolean TrapALError = AL_FALSE; -ALvoid alSetError(ALCcontext *Context, ALenum errorCode) +ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const char *msg) { ALenum curerr = AL_NO_ERROR; - WARN("Error generated on context %p, code 0x%04x\n", Context, errorCode); + WARN("Error generated on context %p, code 0x%04x, object %u, \"%s\"\n", + context, errorCode, objid, msg); if(TrapALError) { #ifdef _WIN32 @@ -49,19 +50,27 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode) #endif } - (void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&Context->LastError, &curerr, errorCode)); + ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode); + if((context->EnabledEvts&EventType_Error)) + { + almtx_lock(&context->EventLock); + if((context->EnabledEvts&EventType_Error) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, objid, errorCode, strlen(msg), msg, + context->EventParam); + almtx_unlock(&context->EventLock); + } } AL_API ALenum AL_APIENTRY alGetError(void) { - ALCcontext *Context; + ALCcontext *context; ALenum errorCode; - Context = GetContextRef(); - if(!Context) + context = GetContextRef(); + if(!context) { - WARN("Querying error state on null context (implicitly 0x%04x)\n", - AL_INVALID_OPERATION); + const ALenum deferror = AL_INVALID_OPERATION; + WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror); if(TrapALError) { #ifdef _WIN32 @@ -71,12 +80,12 @@ AL_API ALenum AL_APIENTRY alGetError(void) raise(SIGTRAP); #endif } - return AL_INVALID_OPERATION; + return deferror; } - errorCode = ATOMIC_EXCHANGE_SEQ(&Context->LastError, AL_NO_ERROR); + errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR); - ALCcontext_DecRef(Context); + ALCcontext_DecRef(context); return errorCode; } diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 4771414a..16796760 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -152,7 +152,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { if(param == AL_FILTER_TYPE) @@ -161,7 +161,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) InitFilterParams(ALFilter, value); else - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, filter, "Filter type not supported"); } else { @@ -193,7 +193,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ @@ -216,7 +216,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ @@ -239,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ @@ -262,7 +262,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { if(param == AL_FILTER_TYPE) @@ -297,7 +297,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ @@ -320,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ @@ -343,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); else { /* Call the appropriate handler */ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 8b3cb305..2b561597 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1844,9 +1844,9 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid float property"); else SetSourcefv(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -1866,9 +1866,9 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-float property"); else { ALfloat fvals[3] = { value1, value2, value3 }; @@ -1891,11 +1891,11 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(FloatValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid float-vector property"); else SetSourcefv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -1916,9 +1916,9 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid double property"); else { ALfloat fval = (ALfloat)value; @@ -1941,9 +1941,9 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-double property"); else { ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; @@ -1967,11 +1967,11 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid double-vector property"); else { ALfloat fvals[6]; @@ -1999,9 +1999,9 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer property"); else SetSourceiv(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -2021,9 +2021,9 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer property"); else { ALint ivals[3] = { value1, value2, value3 }; @@ -2046,11 +2046,11 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer-vector property"); else SetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2071,9 +2071,9 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64 property"); else SetSourcei64v(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -2093,9 +2093,9 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer64 property"); else { ALint64SOFT i64vals[3] = { value1, value2, value3 }; @@ -2118,11 +2118,11 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64-vector property"); else SetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2143,11 +2143,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!value) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid float property"); else { ALdouble dval; @@ -2172,11 +2172,11 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-float property"); else { ALdouble dvals[3]; @@ -2206,11 +2206,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!((count=FloatValsByProp(param)) > 0 && count <= 6)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid float-vector property"); else { ALdouble dvals[6]; @@ -2239,11 +2239,11 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!value) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid double property"); else GetSourcedv(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2263,11 +2263,11 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-double property"); else { ALdouble dvals[3]; @@ -2295,11 +2295,11 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(DoubleValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid double-vector property"); else GetSourcedv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2320,11 +2320,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!value) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer property"); else GetSourceiv(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2345,11 +2345,11 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer property"); else { ALint ivals[3]; @@ -2378,11 +2378,11 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer-vector property"); else GetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2403,11 +2403,11 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!value) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64 property"); else GetSourcei64v(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2427,11 +2427,11 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer64 property"); else { ALint64 i64vals[3]; @@ -2459,11 +2459,11 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); + alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); else if(!values) - alSetError(Context, AL_INVALID_VALUE); + alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); + alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64-vector property"); else GetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); -- cgit v1.2.3 From 395278fcdb2f83ba35b5fba9341bb868af4330b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 12:45:56 -0800 Subject: Set the buffer load error in LoadData --- OpenAL32/Include/alError.h | 5 ++++ OpenAL32/alBuffer.c | 74 ++++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 42 deletions(-) diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index f94802b3..9fb7a7e3 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -26,6 +26,11 @@ ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const cha goto lbl; \ } while(0) +#define SET_ERR_AND_RETURN(ctx, err, objid, msg) do { \ + alSetError((ctx), (err), (objid), (msg)); \ + return; \ +} while(0) + #ifdef __cplusplus } #endif diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index e707dc36..754368b7 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,7 +45,9 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -static ALenum LoadData(ALbuffer *buffer, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access); +static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei frames, + enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, + const ALvoid *data, ALsizei align, ALbitfieldSOFT access); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); @@ -150,9 +152,8 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALCdevice *device; ALCcontext *context; ALbuffer *albuf; - ALsizei framesize; + ALsizei framesize = 1; ALsizei align; - ALenum err; context = GetContextRef(); if(!context) return; @@ -180,37 +181,21 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const case UserFmtMulaw: case UserFmtAlaw: framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; - if((size%framesize) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, flags); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); break; case UserFmtIMA4: framesize = ((align-1)/2 + 4) * ChannelsFromUserFmt(srcchannels); - if((size%framesize) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, flags); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); break; case UserFmtMSADPCM: framesize = ((align-2)/2 + 7) * ChannelsFromUserFmt(srcchannels); - if((size%framesize) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - err = LoadData(albuf, freq, size/framesize*align, srcchannels, srctype, - data, align, flags); - if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); break; } + if((size%framesize) != 0) + alSetError(context, AL_INVALID_VALUE, buffer, "Data size is not a frame multiple"); + else + LoadData(context, albuf, freq, size/framesize*align, srcchannels, srctype, data, align, + flags); done: UnlockBuffersRead(device); @@ -876,11 +861,9 @@ done: /* * LoadData * - * Loads the specified data into the buffer, using the specified formats. - * Currently, the new format must have the same channel configuration as the - * original format. + * Loads the specified data into the buffer, using the specified format. */ -static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access) +static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access) { enum FmtChannels DstChannels = FmtMono; enum FmtType DstType = FmtUByte; @@ -900,8 +883,8 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm case UserFmtBFormat2D: DstChannels = FmtBFormat2D; break; case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; } - if((long)SrcChannels != (long)DstChannels) - return AL_INVALID_ENUM; + if(UNLIKELY((long)SrcChannels != (long)DstChannels)) + SET_ERR_AND_RETURN(context, AL_INVALID_ENUM, ALBuf->id, "Invalid format"); /* IMA4 and MSADPCM convert to 16-bit short. */ switch(SrcType) @@ -918,32 +901,40 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm if(access != 0) { - if((long)SrcType != (long)DstType) - return AL_INVALID_VALUE; + if(UNLIKELY((long)SrcType != (long)DstType)) + SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Format cannot be mapped or preserved"); } NumChannels = ChannelsFromFmt(DstChannels); FrameSize = NumChannels * BytesFromFmt(DstType); - if(frames > INT_MAX/FrameSize) - return AL_OUT_OF_MEMORY; + if(UNLIKELY(frames > INT_MAX/FrameSize)) + SET_ERR_AND_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Buffer size too large"); newsize = frames*FrameSize; WriteLock(&ALBuf->lock); - if(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0) + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) { WriteUnlock(&ALBuf->lock); - return AL_INVALID_OPERATION; + SET_ERR_AND_RETURN(context, AL_INVALID_OPERATION, ALBuf->id, + "Modifying storage for in-use buffer"); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) { /* Can only preserve data with the same format and alignment. */ - if(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType || - ALBuf->OriginalAlign != align) + if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) + { + WriteUnlock(&ALBuf->lock); + SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Preserving data of mismatched format"); + } + if(UNLIKELY(ALBuf->OriginalAlign != align)) { WriteUnlock(&ALBuf->lock); - return AL_INVALID_VALUE; + SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Preserving data of mismatched alignment"); } } @@ -958,10 +949,10 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm if(newsize != ALBuf->BytesAlloc) { void *temp = al_malloc(16, (size_t)newsize); - if(!temp && newsize) + if(UNLIKELY(!temp && newsize)) { WriteUnlock(&ALBuf->lock); - return AL_OUT_OF_MEMORY; + SET_ERR_AND_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Failed to allocate storage"); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) { @@ -1011,7 +1002,6 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFm ALBuf->LoopEnd = ALBuf->SampleLen; WriteUnlock(&ALBuf->lock); - return AL_NO_ERROR; } -- cgit v1.2.3 From 2ded5547ba431a0859bc08276ab720aea9ca92a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 17:07:01 -0800 Subject: Provide messages for the remaining AL errors --- Alc/effects/chorus.c | 68 +++++++--------- Alc/effects/compressor.c | 37 ++++----- Alc/effects/dedicated.c | 34 +++----- Alc/effects/distortion.c | 42 ++++------ Alc/effects/echo.c | 42 ++++------ Alc/effects/equalizer.c | 52 +++++------- Alc/effects/modulator.c | 30 +++---- Alc/effects/null.c | 32 ++++---- Alc/effects/reverb.c | 112 ++++++++++++-------------- OpenAL32/Include/alError.h | 18 +---- OpenAL32/alAuxEffectSlot.c | 62 ++++++++------ OpenAL32/alBuffer.c | 196 ++++++++++++++++++++++++--------------------- OpenAL32/alEffect.c | 10 +-- OpenAL32/alExtension.c | 4 +- OpenAL32/alFilter.c | 118 +++++++++++++-------------- OpenAL32/alListener.c | 107 ++++++++++++------------- OpenAL32/alSource.c | 115 +++++++++++++++----------- OpenAL32/alState.c | 94 +++++++++------------- OpenAL32/event.c | 11 +-- 19 files changed, 559 insertions(+), 625 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 2592c673..75de6be7 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -317,24 +317,22 @@ void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALi { case AL_CHORUS_WAVEFORM: if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid chorus waveform",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus phase out of range",); props->Chorus.Phase = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus integer property"); } } void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALchorus_setParami(effect, context, param, vals[0]); -} +{ ALchorus_setParami(effect, context, param, vals[0]); } void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -342,36 +340,34 @@ void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALf { case AL_CHORUS_RATE: if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus rate out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus depth out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus feedback out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus delay out of range",); props->Chorus.Delay = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus float property"); } } void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALchorus_setParamf(effect, context, param, vals[0]); -} +{ ALchorus_setParamf(effect, context, param, vals[0]); } void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -387,13 +383,11 @@ void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus integer property"); } } void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALchorus_getParami(effect, context, param, vals); -} +{ ALchorus_getParami(effect, context, param, vals); } void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -416,13 +410,11 @@ void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus float property"); } } void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALchorus_getParamf(effect, context, param, vals); -} +{ ALchorus_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALchorus); @@ -461,24 +453,22 @@ void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, AL { case AL_FLANGER_WAVEFORM: if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid flanger waveform",); props->Chorus.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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger phase out of range",); props->Chorus.Phase = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger integer property"); } } void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALflanger_setParami(effect, context, param, vals[0]); -} +{ ALflanger_setParami(effect, context, param, vals[0]); } void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -486,36 +476,34 @@ void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, AL { case AL_FLANGER_RATE: if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger rate out of range",); props->Chorus.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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger depth out of range",); props->Chorus.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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger feedback out of range",); props->Chorus.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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger delay out of range",); props->Chorus.Delay = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger float property"); } } void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALflanger_setParamf(effect, context, param, vals[0]); -} +{ ALflanger_setParamf(effect, context, param, vals[0]); } void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -531,7 +519,7 @@ void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum par break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger integer property"); } } void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) @@ -560,12 +548,10 @@ void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum par break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger float property"); } } void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALflanger_getParamf(effect, context, param, vals); -} +{ ALflanger_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALflanger); diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 4ae2acdb..330733b3 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -210,24 +210,20 @@ void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_COMPRESSOR_ONOFF: if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Compressor state out of range",); props->Compressor.OnOff = val; break; - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + default: + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor integer property"); } } 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]); -} +{ ALcompressor_setParami(effect, context, param, vals[0]); } +void ALcompressor_setParamf(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float property"); } +void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float-vector property"); } void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -237,19 +233,16 @@ void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum case AL_COMPRESSOR_ONOFF: *val = props->Compressor.OnOff; break; + default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor integer property"); } } 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); -} +{ ALcompressor_getParami(effect, context, param, vals); } +void ALcompressor_getParamf(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float property"); } +void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float-vector property"); } DEFINE_ALEFFECT_VTABLE(ALcompressor); diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 7dc2545b..684e8171 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -139,12 +139,10 @@ ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void) } -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_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer property"); } +void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer-vector property"); } void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -152,25 +150,21 @@ void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_DEDICATED_GAIN: if(!(val >= 0.0f && isfinite(val))) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Dedicated gain out of range",); props->Dedicated.Gain = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated float property"); } } void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALdedicated_setParamf(effect, context, param, vals[0]); -} +{ 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_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer property"); } +void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer-vector property"); } void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -181,12 +175,10 @@ void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated float property"); } } void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALdedicated_getParamf(effect, context, param, vals); -} +{ ALdedicated_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALdedicated); diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 8fba07df..2a7c21ec 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -198,12 +198,10 @@ ALeffectStateFactory *ALdistortionStateFactory_getFactory(void) } -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_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer property"); } +void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer-vector property"); } void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -211,49 +209,45 @@ void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_DISTORTION_EDGE: if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion edge out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion low-pass cutoff out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion EQ center out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion EQ bandwidth out of range",); props->Distortion.EQBandwidth = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion float property"); } } void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALdistortion_setParamf(effect, context, param, vals[0]); -} +{ 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_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer property"); } +void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer-vector property"); } void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -280,12 +274,10 @@ void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion float property"); } } void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALdistortion_getParamf(effect, context, param, vals); -} +{ ALdistortion_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALdistortion); diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index cd556f1a..b59b06b0 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -230,12 +230,10 @@ ALeffectStateFactory *ALechoStateFactory_getFactory(void) } -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_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer property"); } +void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer-vector property"); } void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -243,49 +241,45 @@ void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALflo { case AL_ECHO_DELAY: if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo LR delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo damping out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo feedback out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo spread out of range",); props->Echo.Spread = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo float property"); } } void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALecho_setParamf(effect, context, param, vals[0]); -} +{ 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_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer property"); } +void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer-vector property"); } void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -312,12 +306,10 @@ void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo float property"); } } void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALecho_getParamf(effect, context, param, vals); -} +{ ALecho_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALecho); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index bc84f87f..b800d27a 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -220,12 +220,10 @@ ALeffectStateFactory *ALequalizerStateFactory_getFactory(void) } -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_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer property"); } +void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer-vector property"); } void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -233,79 +231,75 @@ void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer low-band gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer low-band cutoff out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band center out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band width out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band center out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band width out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer high-band gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer high-band cutoff out of range",); props->Equalizer.HighCutoff = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer float property"); } } void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALequalizer_setParamf(effect, context, param, vals[0]); -} +{ 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_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer property"); } +void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer-vector property"); } void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -352,12 +346,10 @@ void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer float property"); } } void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALequalizer_getParamf(effect, context, param, vals); -} +{ ALequalizer_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALequalizer); diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 431941ce..0fb03042 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -217,24 +217,22 @@ void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Modulator frequency out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Modulator high-pass cutoff out of range",); props->Modulator.HighPassCutoff = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator float property"); } } void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALmodulator_setParamf(effect, context, param, vals[0]); -} +{ ALmodulator_setParamf(effect, context, param, vals[0]); } void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) { ALeffectProps *props = &effect->Props; @@ -247,18 +245,16 @@ void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid modulator waveform",); props->Modulator.Waveform = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator integer property"); } } void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALmodulator_setParami(effect, context, param, vals[0]); -} +{ ALmodulator_setParami(effect, context, param, vals[0]); } void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -276,13 +272,11 @@ void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator integer property"); } } void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALmodulator_getParami(effect, context, param, vals); -} +{ ALmodulator_getParami(effect, context, param, vals); } void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -296,12 +290,10 @@ void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator float property"); } } void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALmodulator_getParamf(effect, context, param, vals); -} +{ ALmodulator_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALmodulator); diff --git a/Alc/effects/null.c b/Alc/effects/null.c index f3e8a6df..2dc43870 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -110,69 +110,69 @@ ALeffectStateFactory *ALnullStateFactory_getFactory(void) } -void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALnull_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint UNUSED(val)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer property"); } } -void ALnull_setParamiv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) +void ALnull_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer-vector property"); } } -void ALnull_setParamf(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +void ALnull_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat UNUSED(val)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float property"); } } -void ALnull_setParamfv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) +void ALnull_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float-vector property"); } } -void ALnull_getParami(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val)) +void ALnull_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint* UNUSED(val)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer property"); } } -void ALnull_getParamiv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals)) +void ALnull_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint* UNUSED(vals)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer-vector property"); } } -void ALnull_getParamf(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) +void ALnull_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float property"); } } -void ALnull_getParamfv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) +void ALnull_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) { switch(param) { default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float-vector property"); } } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7729caec..0cebab9b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1775,18 +1775,16 @@ void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay hflimit out of range",); props->Reverb.DecayHFLimit = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb integer property"); } } void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALeaxreverb_setParami(effect, context, param, vals[0]); -} +{ ALeaxreverb_setParami(effect, context, param, vals[0]); } void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -1794,126 +1792,126 @@ void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EAXREVERB_DENSITY: if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb density out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb diffusion out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gainhf out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gainlf out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay time out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay hfratio out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay lfratio out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb air absorption gainhf out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb echo time out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb echo depth out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb modulation time out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb modulation depth out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb hfreference out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb lfreference out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb room rolloff factor out of range",); props->Reverb.RoomRolloffFactor = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb float property"); } } void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -1923,14 +1921,14 @@ void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EAXREVERB_REFLECTIONS_PAN: if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections pan out of range",); props->Reverb.ReflectionsPan[0] = vals[0]; props->Reverb.ReflectionsPan[1] = vals[1]; props->Reverb.ReflectionsPan[2] = vals[2]; 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb pan out of range",); props->Reverb.LateReverbPan[0] = vals[0]; props->Reverb.LateReverbPan[1] = vals[1]; props->Reverb.LateReverbPan[2] = vals[2]; @@ -1952,13 +1950,11 @@ void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb integer property"); } } void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALeaxreverb_getParami(effect, context, param, vals); -} +{ ALeaxreverb_getParami(effect, context, param, vals); } void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -2045,7 +2041,7 @@ void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb float property"); } } void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) @@ -2079,18 +2075,16 @@ void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALi { 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay hflimit out of range",); props->Reverb.DecayHFLimit = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb integer property"); } } void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALreverb_setParami(effect, context, param, vals[0]); -} +{ ALreverb_setParami(effect, context, param, vals[0]); } void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -2098,84 +2092,82 @@ void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALf { case AL_REVERB_DENSITY: if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb density out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb diffusion out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb gainhf out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay time out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay hfratio out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb reflections gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb reflections delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb late reverb gain out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb late reverb delay out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb air absorption gainhf out of range",); 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); + SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb room rolloff factor out of range",); props->Reverb.RoomRolloffFactor = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb float property"); } } void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALreverb_setParamf(effect, context, param, vals[0]); -} +{ ALreverb_setParamf(effect, context, param, vals[0]); } void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -2187,13 +2179,11 @@ void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb integer property"); } } void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALreverb_getParami(effect, context, param, vals); -} +{ ALreverb_getParami(effect, context, param, vals); } void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -2248,12 +2238,10 @@ void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb float property"); } } void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALreverb_getParamf(effect, context, param, vals); -} +{ ALreverb_getParamf(effect, context, param, vals); } DEFINE_ALEFFECT_VTABLE(ALreverb); diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 9fb7a7e3..3dc16103 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -11,24 +11,14 @@ extern ALboolean TrapALError; ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const char *msg); -#define SET_ERROR_AND_RETURN(ctx, err) do { \ - alSetError((ctx), (err), 0, "Unimplemented message"); \ - return; \ -} while(0) - -#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \ - alSetError((ctx), (err), 0, "Unimplemented message"); \ - return (val); \ -} while(0) - -#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \ - alSetError((ctx), (err), 0, "Unimplemented message"); \ +#define SETERR_GOTO(ctx, err, objid, msg, lbl) do { \ + alSetError((ctx), (err), (objid), (msg)); \ goto lbl; \ } while(0) -#define SET_ERR_AND_RETURN(ctx, err, objid, msg) do { \ +#define SETERR_RETURN(ctx, err, objid, msg, retval) do { \ alSetError((ctx), (err), (objid), (msg)); \ - return; \ + return retval; \ } while(0) #ifdef __cplusplus diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 2dcf7125..a8186f07 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -73,7 +73,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(!context) return; if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative effect slots", done); tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); LockEffectSlotsWrite(context); @@ -87,7 +87,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo UnlockEffectSlotsWrite(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Effect slot object allocation failed", done); } err = NewThunkEntry(&slot->id); @@ -103,7 +103,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo UnlockEffectSlotsWrite(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Failed to set effect slot ID", done); } aluInitEffectPanning(slot); @@ -149,13 +149,15 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * LockEffectSlotsWrite(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative effect slots", + done); for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslots[i], "Invalid effect slot ID", done); if(ReadRef(&slot->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + SETERR_GOTO(context, AL_INVALID_OPERATION, effectslots[i], + "Deleting in-use effect slot", done); } // All effectslots are valid @@ -238,7 +240,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param WriteLock(&context->PropLock); LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { case AL_EFFECTSLOT_EFFECT: @@ -249,23 +251,25 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!(value == 0 || effect != NULL)) { UnlockEffectsRead(device); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, "Invalid effect ID", done); } err = InitializeEffect(context, slot, effect); UnlockEffectsRead(device); if(err != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, effectslot, "Effect initialization failed", done); break; case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: if(!(value == AL_TRUE || value == AL_FALSE)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, + "Effect slot auxiliary send auto out of range", done); slot->AuxSendAuto = value; break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + SETERR_GOTO(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot integer property", + done); } DO_UPDATEPROPS(); @@ -292,11 +296,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, + "Invalid effect slot integer-vector property"); } done: @@ -315,17 +320,19 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param WriteLock(&context->PropLock); LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { case AL_EFFECTSLOT_GAIN: if(!(value >= 0.0f && value <= 1.0f)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, "Effect slot gain out of range", + done); slot->Gain = value; break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + SETERR_GOTO(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot float property", + done); } DO_UPDATEPROPS(); @@ -351,11 +358,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, + "Invalid effect slot float-vector property"); } done: @@ -373,7 +381,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: @@ -381,7 +389,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot integer property"); } done: @@ -406,11 +414,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, + "Invalid effect slot integer-vector property"); } done: @@ -428,7 +437,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { case AL_EFFECTSLOT_GAIN: @@ -436,7 +445,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot float property"); } done: @@ -460,11 +469,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, effectslot, + "Invalid effect slot float-vector property"); } done: diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 754368b7..922c379c 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -66,7 +66,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) if(!context) return; if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative buffers", done); for(cur = 0;cur < n;cur++) { @@ -98,7 +98,7 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) LockBuffersWrite(device); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative buffers", done); for(i = 0;i < n;i++) { @@ -107,9 +107,9 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) /* Check for valid Buffer ID */ if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffers[i], "Invalid buffer ID", done); if(ReadRef(&ALBuf->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + SETERR_GOTO(context, AL_INVALID_OPERATION, buffers[i], "Deleting in-use buffer", done); } for(i = 0;i < n;i++) @@ -161,16 +161,19 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(size >= 0 && freq > 0) || (flags&INVALID_STORAGE_MASK) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + if(!(size >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Negative storage size", done); + if(!(freq > 0)) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid sample rate", done); + if((flags&INVALID_STORAGE_MASK) != 0) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid storage flags", done); if((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Declaring persistently mapped storage without read or write access", done); if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Invalid format", done); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid unpack alignment", done); switch(srctype) { @@ -215,21 +218,32 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(!(access&MAP_READ_WRITE_FLAGS) || (access&~MAP_ACCESS_FLAGS) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + if((access&~MAP_ACCESS_FLAGS) != 0) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid map flags", done); + if(!(access&MAP_READ_WRITE_FLAGS)) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Mapping buffer without read or write access", done); WriteLock(&albuf->lock); - if((ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) || - albuf->MappedAccess != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); - if(((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) || - ((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) || - ((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + if(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, + "Mapping in-use buffer without persistent mapping", unlock_done); + if(albuf->MappedAccess != 0) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, "Mapping already-mapped buffer", + unlock_done); + if((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Mapping buffer for reading without read access", unlock_done); + if((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Mapping buffer for writing without write access", unlock_done); + if((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Mapping buffer persistently without persistent access", unlock_done); if(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Mapping out of range", unlock_done); retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; @@ -258,7 +272,7 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); WriteLock(&albuf->lock); if(albuf->MappedAccess == 0) @@ -288,7 +302,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); WriteLock(&albuf->lock); if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) @@ -332,21 +346,22 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons device = context->Device; LockBuffersRead(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); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Invalid format", done); WriteLock(&albuf->lock); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid unpack alignment", done); if((long)srcchannels != (long)albuf->FmtChannels || srctype != albuf->OriginalType) - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, unlock_done); + SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Unpacking data with mismatched format", + unlock_done); if(align != albuf->OriginalAlign) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Unpacking data with mismatched alignment", + unlock_done); if(albuf->MappedAccess != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, unlock_done); + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, "Unpacking data into mapped buffer", + unlock_done); num_chans = ChannelsFromFmt(albuf->FmtChannels); frame_size = num_chans * BytesFromFmt(albuf->FmtType); @@ -357,9 +372,11 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons else byte_align = align * frame_size; - if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset || - (offset%byte_align) != 0 || (length%byte_align) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, unlock_done); + if(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Data sub-range out of range", unlock_done); + if((offset%byte_align) != 0 || (length%byte_align) != 0) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid sub-range alignment", unlock_done); /* offset -> byte offset, length -> sample count */ offset = offset/byte_align * frame_size; @@ -452,12 +469,12 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float property"); } done: @@ -477,12 +494,12 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-float property"); } done: @@ -502,14 +519,13 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float-vector property"); } done: @@ -530,24 +546,26 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); switch(param) { case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, + "Negative buffer unpack block alignment", done); ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Negative buffer pack block alignment", + done); ATOMIC_STORE_SEQ(&albuf->PackAlign, value); break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer property"); } done: @@ -566,12 +584,12 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val device = context->Device; if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-integer property"); } done: @@ -602,10 +620,9 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { case AL_LOOP_POINTS_SOFT: @@ -613,13 +630,14 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val if(ReadRef(&albuf->ref) != 0) { WriteUnlock(&albuf->lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, + "Modifying in-use buffer loop points", 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); + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid loop point range", done); } albuf->LoopStart = values[0]; @@ -628,7 +646,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer-vector property"); } done: @@ -649,14 +667,13 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(value)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float property"); } done: @@ -676,14 +693,14 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(value1 && value2 && value3)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!value1 || !value2 || !value3) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-float property"); } done: @@ -710,14 +727,13 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float-vector property"); } done: @@ -738,10 +754,9 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(value)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { case AL_FREQUENCY: @@ -772,7 +787,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer property"); } done: @@ -792,14 +807,14 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(value1 && value2 && value3)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!value1 || !value2 || !value3) + SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-integer property"); } done: @@ -835,10 +850,9 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); switch(param) { case AL_LOOP_POINTS_SOFT: @@ -849,7 +863,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer-vector property"); } done: @@ -884,7 +898,7 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; } if(UNLIKELY((long)SrcChannels != (long)DstChannels)) - SET_ERR_AND_RETURN(context, AL_INVALID_ENUM, ALBuf->id, "Invalid format"); + SETERR_RETURN(context, AL_INVALID_ENUM, ALBuf->id, "Invalid format",); /* IMA4 and MSADPCM convert to 16-bit short. */ switch(SrcType) @@ -902,23 +916,23 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(access != 0) { if(UNLIKELY((long)SrcType != (long)DstType)) - SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Format cannot be mapped or preserved"); + SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Format cannot be mapped or preserved",); } NumChannels = ChannelsFromFmt(DstChannels); FrameSize = NumChannels * BytesFromFmt(DstType); if(UNLIKELY(frames > INT_MAX/FrameSize)) - SET_ERR_AND_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Buffer size too large"); + SETERR_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Buffer size too large",); newsize = frames*FrameSize; WriteLock(&ALBuf->lock); if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) { WriteUnlock(&ALBuf->lock); - SET_ERR_AND_RETURN(context, AL_INVALID_OPERATION, ALBuf->id, - "Modifying storage for in-use buffer"); + SETERR_RETURN(context, AL_INVALID_OPERATION, ALBuf->id, + "Modifying storage for in-use buffer",); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) @@ -927,14 +941,14 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) { WriteUnlock(&ALBuf->lock); - SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Preserving data of mismatched format"); + SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Preserving data of mismatched format",); } if(UNLIKELY(ALBuf->OriginalAlign != align)) { WriteUnlock(&ALBuf->lock); - SET_ERR_AND_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Preserving data of mismatched alignment"); + SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, + "Preserving data of mismatched alignment",); } } @@ -952,7 +966,7 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(UNLIKELY(!temp && newsize)) { WriteUnlock(&ALBuf->lock); - SET_ERR_AND_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Failed to allocate storage"); + SETERR_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Failed to allocate storage",); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) { @@ -1190,7 +1204,7 @@ ALbuffer *NewBuffer(ALCcontext *context) buffer = al_calloc(16, sizeof(ALbuffer)); if(!buffer) - SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL); + SETERR_RETURN(context, AL_OUT_OF_MEMORY, 0, "Failed to allocate buffer object", NULL); RWLockInit(&buffer->lock); buffer->Access = 0; buffer->MappedAccess = 0; @@ -1204,7 +1218,7 @@ ALbuffer *NewBuffer(ALCcontext *context) memset(buffer, 0, sizeof(ALbuffer)); al_free(buffer); - SET_ERROR_AND_RETURN_VALUE(context, err, NULL); + SETERR_RETURN(context, err, 0, "Failed to set buffer ID", NULL); } return buffer; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 755d792e..5f6e661a 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -69,7 +69,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) if(!context) return; if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative effects", done); device = context->Device; for(cur = 0;cur < n;cur++) @@ -80,7 +80,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) { al_free(effect); alDeleteEffects(cur, effects); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Failed to allocate effect object", done); } err = NewThunkEntry(&effect->id); @@ -93,7 +93,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) al_free(effect); alDeleteEffects(cur, effects); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Failed to set effect ID", done); } effects[cur] = effect->id; @@ -116,11 +116,11 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) device = context->Device; LockEffectsWrite(device); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative effects", done); for(i = 0;i < n;i++) { if(effects[i] && LookupEffect(device, effects[i]) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, effects[i], "Invalid effect ID", done); } for(i = 0;i < n;i++) { diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 7db326a2..9b6e5a97 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -45,8 +45,8 @@ AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) context = GetContextRef(); if(!context) return AL_FALSE; - if(!(extName)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!extName) + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); len = strlen(extName); ptr = context->ExtensionList; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 16796760..24b0e607 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -55,7 +55,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!context) return; if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative filters", done); device = context->Device; for(cur = 0;cur < n;cur++) @@ -64,7 +64,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!filter) { alDeleteFilters(cur, filters); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, 0, "Failed to allocate filter object", done); } InitFilterParams(filter, AL_FILTER_NULL); @@ -78,7 +78,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) al_free(filter); alDeleteFilters(cur, filters); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Failed ot set filter ID", done); } filters[cur] = filter->id; @@ -101,11 +101,11 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) device = context->Device; LockFiltersWrite(device); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative filters", done); for(i = 0;i < n;i++) { if(filters[i] && LookupFilter(device, filters[i]) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, filters[i], "Invalid filter ID", done); } for(i = 0;i < n;i++) { @@ -435,37 +435,37 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g } -static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALlowpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer property"); } +static void ALlowpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer-vector property"); } static void ALlowpass_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)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Low-pass gain out of range",); filter->Gain = val; break; case AL_LOWPASS_GAINHF: if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Low-pass gainhf out of range",); filter->GainHF = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass float property"); } } static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALlowpass_setParamf(filter, context, param, vals[0]); } -static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALlowpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer property"); } +static void ALlowpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer-vector property"); } static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -479,7 +479,7 @@ static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum pa break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass float property"); } } static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -488,37 +488,37 @@ static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum p DEFINE_ALFILTER_VTABLE(ALlowpass); -static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALhighpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer property"); } +static void ALhighpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer-vector property"); } static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { case AL_HIGHPASS_GAIN: if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "High-pass gain out of range",); filter->Gain = val; break; case AL_HIGHPASS_GAINLF: if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "High-pass gainlf out of range",); filter->GainLF = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass float property"); } } static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALhighpass_setParamf(filter, context, param, vals[0]); } -static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALhighpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer property"); } +static void ALhighpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer-vector property"); } static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -532,7 +532,7 @@ static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass float property"); } } static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -541,43 +541,43 @@ static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum DEFINE_ALFILTER_VTABLE(ALhighpass); -static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALbandpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer property"); } +static void ALbandpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer-vector property"); } static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { case AL_BANDPASS_GAIN: if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gain out of range",); filter->Gain = val; break; case AL_BANDPASS_GAINHF: if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gainhf out of range",); filter->GainHF = val; break; case AL_BANDPASS_GAINLF: if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); + SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gainlf out of range",); filter->GainLF = val; break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass float property"); } } static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALbandpass_setParamf(filter, context, param, vals[0]); } -static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALbandpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer property"); } +static void ALbandpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer-vector property"); } static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -595,7 +595,7 @@ static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p break; default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); + alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass float property"); } } static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -604,23 +604,23 @@ static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum DEFINE_ALFILTER_VTABLE(ALbandpass); -static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } - -static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } +static void ALnullfilter_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_setParamf(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_setParamfv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } + +static void ALnullfilter_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_getParamf(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_getParamfv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } DEFINE_ALFILTER_VTABLE(ALnullfilter); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 9a90c16e..51ab6fc9 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -48,14 +48,15 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) { case AL_GAIN: if(!(value >= 0.0f && isfinite(value))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener gain out of range", done); listener->Gain = value; DO_UPDATEPROPS(); break; case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener meters per unit out of range", + done); context->MetersPerUnit = value; if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) UpdateContextProps(context); @@ -64,7 +65,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float property"); } done: @@ -87,7 +88,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val { case AL_POSITION: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener position out of range", done); listener->Position[0] = value1; listener->Position[1] = value2; listener->Position[2] = value3; @@ -96,7 +97,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val case AL_VELOCITY: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener velocity out of range", done); listener->Velocity[0] = value1; listener->Velocity[1] = value2; listener->Velocity[2] = value3; @@ -104,7 +105,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-float property"); } done: @@ -139,14 +140,13 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) listener = context->Listener; WriteLock(&context->PropLock); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); switch(param) { 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); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener orientation out of range", done); /* AT then UP */ listener->Forward[0] = values[0]; listener->Forward[1] = values[1]; @@ -158,7 +158,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float-vector property"); } done: @@ -178,11 +178,10 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer property"); } - -done: WriteUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -206,11 +205,10 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-integer property"); } - -done: WriteUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -245,16 +243,15 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) if(!context) return; WriteLock(&context->PropLock); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer-vector property"); } - -done: WriteUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -267,9 +264,9 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) if(!context) return; ReadLock(&context->PropLock); - if(!(value)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!value) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { case AL_GAIN: *value = context->Listener->Gain; @@ -280,11 +277,10 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -297,9 +293,9 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat if(!context) return; ReadLock(&context->PropLock); - if(!(value1 && value2 && value3)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!value1 || !value2 || !value3) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { case AL_POSITION: *value1 = context->Listener->Position[0]; @@ -314,11 +310,10 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-float property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -344,9 +339,9 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) if(!context) return; ReadLock(&context->PropLock); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { case AL_ORIENTATION: // AT then UP @@ -359,11 +354,10 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float-vector property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -376,16 +370,15 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) if(!context) return; ReadLock(&context->PropLock); - if(!(value)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!value) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -398,9 +391,9 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu if(!context) return; ReadLock(&context->PropLock); - if(!(value1 && value2 && value3)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch (param) + if(!value1 || !value2 || !value3) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { case AL_POSITION: *value1 = (ALint)context->Listener->Position[0]; @@ -415,11 +408,10 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-integer property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -440,9 +432,9 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) if(!context) return; ReadLock(&context->PropLock); - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - switch(param) + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + else switch(param) { case AL_ORIENTATION: // AT then UP @@ -455,11 +447,10 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer-vector property"); } - -done: ReadUnlock(&context->PropLock); + ALCcontext_DecRef(context); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 2b561597..c60b6a01 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -452,7 +452,11 @@ static ALint Int64ValsByProp(ALenum prop) #define CHECKVAL(x) do { \ if(!(x)) \ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \ + { \ + alSetError(Context, AL_INVALID_VALUE, Source->id, \ + "Value out of range"); \ + return AL_FALSE; \ + } \ } while(0) #define DO_UPDATEPROPS() do { \ @@ -477,7 +481,8 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, + "Setting read-only source property", AL_FALSE); case AL_PITCH: CHECKVAL(*values >= 0.0f); @@ -601,7 +606,8 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid offset", + AL_FALSE); } WriteUnlock(&Source->queue_lock); } @@ -694,7 +700,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source float property", AL_FALSE); } static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) @@ -716,7 +722,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, + "Setting read-only source property", AL_FALSE); case AL_SOURCE_RELATIVE: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); @@ -756,7 +763,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) { UnlockBuffersRead(device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid buffer ID", + AL_FALSE); } WriteLock(&Source->queue_lock); @@ -765,7 +773,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, + "Setting non-persistently mapped buffer", AL_FALSE); } else { @@ -774,7 +783,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, + "Setting buffer on playing or paused source", AL_FALSE); } } @@ -839,7 +849,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, + "Invalid source offset", AL_FALSE); } WriteUnlock(&Source->queue_lock); } @@ -852,7 +863,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) { UnlockFiltersRead(device); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid filter ID", + AL_FALSE); } if(!filter) @@ -941,7 +953,9 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { UnlockFiltersRead(device); UnlockEffectSlotsRead(Context); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); + /* TODO: Fix message */ + SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid send parameter", + AL_FALSE); } if(!filter) @@ -1040,7 +1054,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer property", + AL_FALSE); } static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) @@ -1060,8 +1075,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - + SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, + "Setting read-only source property", AL_FALSE); /* 1x int */ case AL_SOURCE_RELATIVE: @@ -1145,7 +1160,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer64 property", + AL_FALSE); } #undef CHECKVAL @@ -1342,7 +1358,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source double property", + AL_FALSE); } static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) @@ -1586,7 +1603,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer property", + AL_FALSE); } static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) @@ -1718,7 +1736,8 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp } ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer64 property", + AL_FALSE); } @@ -1733,7 +1752,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!context) return; if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative sources", done); device = context->Device; for(cur = 0;cur < n;cur++) { @@ -1741,7 +1760,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!source) { alDeleteSources(cur, sources); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY,0, "Failed to allocate source object", done); } InitSourceParams(source, device->NumAuxSends); @@ -1755,7 +1774,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) al_free(source); alDeleteSources(cur, sources); - SET_ERROR_AND_GOTO(context, err, done); + SETERR_GOTO(context, err, 0, "Failed to set source ID", done); } sources[cur] = source->id; @@ -1778,13 +1797,13 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) LockSourcesWrite(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative sources", done); /* 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); + SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); } device = context->Device; for(i = 0;i < n;i++) @@ -2490,11 +2509,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Playing negative sources", done); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); } device = context->Device; @@ -2517,7 +2536,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(context->MaxVoices >= newcount) { ALCdevice_Unlock(device); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, 0, "Max voice count overflow", done); } AllocateVoices(context, newcount, device->NumAuxSends); } @@ -2677,11 +2696,11 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Pausing negative sources", done); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); } device = context->Device; @@ -2724,11 +2743,11 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Stopping negative sources", done); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); } device = context->Device; @@ -2774,11 +2793,11 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Rewinding negative sources", done); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); } device = context->Device; @@ -2828,16 +2847,16 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu LockSourcesRead(context); if(!(nb >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, src, "Queueing negative buffers", done); if((source=LookupSource(context, src)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid source ID", done); WriteLock(&source->queue_lock); if(source->SourceType == AL_STATIC) { WriteUnlock(&source->queue_lock); /* Can't queue on a Static Source */ - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); + SETERR_GOTO(context, AL_INVALID_OPERATION, src, "Queueing onto a static source", done); } /* Check for a valid Buffer, for its frequency and format */ @@ -2862,7 +2881,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) { WriteUnlock(&source->queue_lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error); + SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid buffer ID", buffer_error); } if(!BufferListStart) @@ -2892,7 +2911,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { WriteUnlock(&source->queue_lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error); + SETERR_GOTO(context, AL_INVALID_OPERATION, src, + "Queueing non-persistently mapped buffer", buffer_error); } if(BufferFmt == NULL) @@ -2902,7 +2922,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferFmt->OriginalType != buffer->OriginalType) { WriteUnlock(&source->queue_lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error); + alSetError(context, AL_INVALID_OPERATION, src, + "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release @@ -2973,20 +2994,25 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint LockSourcesRead(context); if(!(nb >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing negative buffers", done); if((source=LookupSource(context, src)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid source ID", done); /* Nothing to unqueue. */ if(nb == 0) goto done; WriteLock(&source->queue_lock); - if(source->Looping || source->SourceType != AL_STREAMING) + if(source->Looping) + { + WriteUnlock(&source->queue_lock); + SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing from a looping source", done); + } + if(source->SourceType != AL_STREAMING) { WriteUnlock(&source->queue_lock); - /* Trying to unqueue buffers on a looping or non-streaming source. */ - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing from a non-streaming source", + done); } /* Find the new buffer queue head */ @@ -3008,8 +3034,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if(i != nb) { WriteUnlock(&source->queue_lock); - /* Trying to unqueue pending buffers. */ - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing pending buffers", done); } /* Swap it, and cut the new head from the old. */ diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 36afd46e..f34f385f 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -88,11 +88,10 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid enable property"); } - -done: WriteUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -112,11 +111,10 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid disable property"); } - -done: WriteUnlock(&context->PropLock); + ALCcontext_DecRef(context); } @@ -135,12 +133,10 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid is enabled property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -194,12 +190,10 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -247,12 +241,10 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid double property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -300,12 +292,10 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid float property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -353,12 +343,10 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -406,12 +394,10 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64 property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -433,13 +419,11 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) value = context->EventParam; break; - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + default: + alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -461,15 +445,14 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) context = GetContextRef(); if(!context) return; - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer-vector property"); } -done: ALCcontext_DecRef(context); } @@ -497,15 +480,14 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) context = GetContextRef(); if(!context) return; - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean-vector property"); } -done: ALCcontext_DecRef(context); } @@ -533,15 +515,14 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) context = GetContextRef(); if(!context) return; - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid double-vector property"); } -done: ALCcontext_DecRef(context); } @@ -569,15 +550,14 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) context = GetContextRef(); if(!context) return; - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid float-vector property"); } -done: ALCcontext_DecRef(context); } @@ -605,13 +585,14 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) context = GetContextRef(); if(!context) return; + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer-vector property"); } -done: ALCcontext_DecRef(context); } @@ -639,13 +620,14 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) context = GetContextRef(); if(!context) return; + if(!values) + alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); switch(pname) { default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64-vector property"); } -done: ALCcontext_DecRef(context); } @@ -700,12 +682,10 @@ AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid string property"); } -done: ALCcontext_DecRef(context); - return value; } @@ -717,7 +697,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) if(!context) return; if(!(value >= 0.0f && isfinite(value))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Doppler factor out of range", done); WriteLock(&context->PropLock); context->DopplerFactor = value; @@ -736,7 +716,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) if(!context) return; if(!(value >= 0.0f && isfinite(value))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Doppler velocity out of range", done); WriteLock(&context->PropLock); context->DopplerVelocity = value; @@ -755,7 +735,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) if(!context) return; if(!(value > 0.0f && isfinite(value))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Speed of sound out of range", done); WriteLock(&context->PropLock); context->SpeedOfSound = value; @@ -777,7 +757,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) 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); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Distance model out of range", done); WriteLock(&context->PropLock); context->DistanceModel = value; @@ -834,12 +814,12 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) { case AL_RESAMPLER_NAME_SOFT: if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Resampler name index out of range", done); value = ResamplerNames[index]; break; default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid string indexed property"); } done: diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 4e844ce9..88885f52 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -17,11 +17,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A context = GetContextRef(); if(!context) return; - if(count < 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Controlling negative events", done); if(count == 0) goto done; - if(!types) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); + if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); for(i = 0;i < count;i++) { @@ -34,17 +32,16 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT) flags |= EventType_Performance; else - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); + SETERR_GOTO(context, AL_INVALID_ENUM, 0, "Invalid event type", done); } almtx_lock(&context->EventLock); - if(enable) context->EnabledEvts |= flags; else context->EnabledEvts &= ~flags; - almtx_unlock(&context->EventLock); + done: ALCcontext_DecRef(context); } -- cgit v1.2.3 From 1d86aea61c3d8b828ac3ceec585de4147f7909bf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 18:30:32 -0800 Subject: Fix ordering of alGetPointervSOFT --- OpenAL32/alState.c | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index f34f385f..67f9aab7 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -427,7 +427,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) return value; } -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) { ALCcontext *context; @@ -435,9 +435,15 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) { switch(pname) { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - values[0] = alGetPointerSOFT(pname); + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + case AL_GAIN_LIMIT_SOFT: + case AL_NUM_RESAMPLERS_SOFT: + case AL_DEFAULT_RESAMPLER_SOFT: + values[0] = alGetBoolean(pname); return; } } @@ -450,13 +456,13 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean-vector property"); } ALCcontext_DecRef(context); } -AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) { ALCcontext *context; @@ -472,7 +478,7 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetBoolean(pname); + values[0] = alGetDouble(pname); return; } } @@ -485,13 +491,13 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid double-vector property"); } ALCcontext_DecRef(context); } -AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) { ALCcontext *context; @@ -507,7 +513,7 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetDouble(pname); + values[0] = alGetFloat(pname); return; } } @@ -520,13 +526,13 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid double-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid float-vector property"); } ALCcontext_DecRef(context); } -AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) { ALCcontext *context; @@ -542,7 +548,7 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetFloat(pname); + values[0] = alGetInteger(pname); return; } } @@ -555,13 +561,13 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid float-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer-vector property"); } ALCcontext_DecRef(context); } -AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) +AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) { ALCcontext *context; @@ -577,7 +583,7 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) case AL_GAIN_LIMIT_SOFT: case AL_NUM_RESAMPLERS_SOFT: case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger(pname); + values[0] = alGetInteger64SOFT(pname); return; } } @@ -590,13 +596,13 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64-vector property"); } ALCcontext_DecRef(context); } -AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) { ALCcontext *context; @@ -604,15 +610,9 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) { switch(pname) { - case AL_DOPPLER_FACTOR: - case AL_DOPPLER_VELOCITY: - case AL_DISTANCE_MODEL: - case AL_SPEED_OF_SOUND: - case AL_DEFERRED_UPDATES_SOFT: - case AL_GAIN_LIMIT_SOFT: - case AL_NUM_RESAMPLERS_SOFT: - case AL_DEFAULT_RESAMPLER_SOFT: - values[0] = alGetInteger64SOFT(pname); + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + values[0] = alGetPointerSOFT(pname); return; } } @@ -625,7 +625,7 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64-vector property"); + alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer-vector property"); } ALCcontext_DecRef(context); -- cgit v1.2.3 From 2a7f5aa569d181a47c28c98e67dcadf275835b15 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 18:42:00 -0800 Subject: Add a deprecated event type for alDopplerVelocity --- Alc/ALc.c | 1 + OpenAL32/Include/alMain.h | 2 ++ OpenAL32/alState.c | 11 +++++++++++ OpenAL32/event.c | 2 ++ 4 files changed, 16 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index aa4634a0..1aa34225 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -665,6 +665,7 @@ static const struct { DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), DECL(AL_EVENT_TYPE_ERROR_SOFT), DECL(AL_EVENT_TYPE_PERFORMANCE_SOFT), + DECL(AL_EVENT_TYPE_DEPRECATED_SOFT), }; #undef DECL diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 438f7ed5..4661b713 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -74,6 +74,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A #define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0xffe3 #define AL_EVENT_TYPE_ERROR_SOFT 0xffe4 #define AL_EVENT_TYPE_PERFORMANCE_SOFT 0xffe5 +#define AL_EVENT_TYPE_DEPRECATED_SOFT 0xffe6 typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam); @@ -570,6 +571,7 @@ enum { EventType_BufferCompleted = 1<<1, EventType_Error = 1<<2, EventType_Performance = 1<<3, + EventType_Deprecated = 1<<4, }; struct ALCcontext_struct { diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 67f9aab7..9c49b2e8 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -715,6 +715,17 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) context = GetContextRef(); if(!context) return; + if((context->EnabledEvts&EventType_Deprecated)) + { + static const ALCchar msg[] = + "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + almtx_lock(&context->EventLock); + if((context->EnabledEvts&EventType_Deprecated) && context->EventCb) + (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, strlen(msg), msg, + context->EventParam); + almtx_unlock(&context->EventLock); + } + if(!(value >= 0.0f && isfinite(value))) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Doppler velocity out of range", done); diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 88885f52..06db8713 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -31,6 +31,8 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A flags |= EventType_Error; else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT) flags |= EventType_Performance; + else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT) + flags |= EventType_Deprecated; else SETERR_GOTO(context, AL_INVALID_ENUM, 0, "Invalid event type", done); } -- cgit v1.2.3 From f5236ab1865eb9456c95743cd6e5d9464bdb44ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 19:25:15 -0800 Subject: Use more appropriate enum values for events --- OpenAL32/Include/alMain.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 4661b713..18dc32dd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -68,13 +68,13 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A #ifndef AL_SOFT_events #define AL_SOFT_events 1 -#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0xffe0 -#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0xffe1 -#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0xffe2 -#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0xffe3 -#define AL_EVENT_TYPE_ERROR_SOFT 0xffe4 -#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0xffe5 -#define AL_EVENT_TYPE_DEPRECATED_SOFT 0xffe6 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 +#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 +#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 +#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam); -- cgit v1.2.3 From 0c9c8465220b1bc6e5ca28549262865b1805982b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 19:59:22 -0800 Subject: Report AL_SOFTX_events as an in-progress extension --- Alc/ALc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1aa34225..255265b5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -712,6 +712,7 @@ static const ALchar alExtList[] = "AL_SOFT_block_alignment " "AL_SOFT_deferred_updates " "AL_SOFT_direct_channels " + "AL_SOFTX_events " "AL_SOFT_gain_clamp_ex " "AL_SOFT_loop_points " "AL_SOFTX_map_buffer " -- cgit v1.2.3 From 932939c5a80971ee155613038c392603d92fdf03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Jan 2018 20:04:57 -0800 Subject: Enable events in alffplay --- examples/alffplay.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index f372983a..6eedcd76 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -50,6 +50,24 @@ typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALs typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); #endif + +#ifndef AL_SOFT_events +#define AL_SOFT_events 1 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 +#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 +#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 +#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 +typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); +#endif } namespace { @@ -70,6 +88,9 @@ LPALBUFFERSTORAGESOFT alBufferStorageSOFT; LPALMAPBUFFERSOFT alMapBufferSOFT; LPALUNMAPBUFFERSOFT alUnmapBufferSOFT; +LPALEVENTCONTROLSOFT alEventControlSOFT; +LPALEVENTCALLBACKSOFT alEventCallbackSOFT; + const seconds AVNoSyncThreshold(10); const milliseconds VideoSyncThreshold(10); @@ -232,6 +253,10 @@ struct AudioState { av_freep(&mSamples); } + static void AL_APIENTRY EventCallback(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); + nanoseconds getClockNoLock(); nanoseconds getClock() { @@ -653,11 +678,45 @@ bool AudioState::readAudio(uint8_t *samples, int length) } +void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam) +{ + AudioState *self = reinterpret_cast(userParam); + + std::cout<< "---- AL Event on AudioState "< lock(mSrcMutex); ALenum fmt; + if(alEventControlSOFT) + { + alEventControlSOFT(5, types, AL_TRUE); + alEventCallbackSOFT(EventCallback, this); + } + /* Find a suitable format for OpenAL. */ mDstChanLayout = 0; if(mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8 || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8P) @@ -887,6 +946,12 @@ int AudioState::handler() finish: av_freep(&samples); + if(alEventControlSOFT) + { + alEventControlSOFT(5, types, AL_FALSE); + alEventCallbackSOFT(nullptr, nullptr); + } + return 0; } @@ -1643,6 +1708,14 @@ int main(int argc, char *argv[]) alUnmapBufferSOFT = reinterpret_cast( alGetProcAddress("alUnmapBufferSOFT")); } + if(alIsExtensionPresent("AL_SOFTX_events")) + { + std::cout<< "Found AL_SOFT_events" <( + alGetProcAddress("alEventControlSOFT")); + alEventCallbackSOFT = reinterpret_cast( + alGetProcAddress("alEventCallbackSOFT")); + } if(fileidx < argc && strcmp(argv[fileidx], "-direct") == 0) { -- cgit v1.2.3 From 99f0377ae3f24ebf3391a09940d888dec1d4b4c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Jan 2018 15:59:59 -0800 Subject: Construct error messages using parameterized values --- Alc/effects/chorus.c | 44 ++++---- Alc/effects/compressor.c | 24 ++-- Alc/effects/dedicated.c | 22 ++-- Alc/effects/distortion.c | 32 +++--- Alc/effects/echo.c | 30 ++--- Alc/effects/equalizer.c | 40 +++---- Alc/effects/modulator.c | 14 +-- Alc/effects/null.c | 48 ++++---- Alc/effects/reverb.c | 92 ++++++++-------- OpenAL32/Include/alError.h | 10 +- OpenAL32/alAuxEffectSlot.c | 71 ++++++------ OpenAL32/alBuffer.c | 208 ++++++++++++++++++----------------- OpenAL32/alEffect.c | 28 ++--- OpenAL32/alError.c | 30 ++++- OpenAL32/alExtension.c | 2 +- OpenAL32/alFilter.c | 136 +++++++++++------------ OpenAL32/alListener.c | 13 +-- OpenAL32/alSource.c | 266 +++++++++++++++++++++++---------------------- OpenAL32/alState.c | 65 +++++------ OpenAL32/event.c | 6 +- 20 files changed, 610 insertions(+), 571 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 75de6be7..666933a8 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -317,18 +317,18 @@ void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALi { case AL_CHORUS_WAVEFORM: if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid chorus waveform",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform"); props->Chorus.Waveform = val; break; case AL_CHORUS_PHASE: if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus phase out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range"); props->Chorus.Phase = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); } } void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) @@ -340,30 +340,30 @@ void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALf { case AL_CHORUS_RATE: if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus rate out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range"); props->Chorus.Rate = val; break; case AL_CHORUS_DEPTH: if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus depth out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range"); props->Chorus.Depth = val; break; case AL_CHORUS_FEEDBACK: if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus feedback out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range"); props->Chorus.Feedback = val; break; case AL_CHORUS_DELAY: if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Chorus delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range"); props->Chorus.Delay = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); } } void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -383,7 +383,7 @@ void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param); } } void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) @@ -410,7 +410,7 @@ void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid chorus float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param); } } void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) @@ -453,18 +453,18 @@ void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, AL { case AL_FLANGER_WAVEFORM: if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid flanger waveform",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform"); props->Chorus.Waveform = val; break; case AL_FLANGER_PHASE: if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger phase out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range"); props->Chorus.Phase = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); } } void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) @@ -476,30 +476,30 @@ void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, AL { case AL_FLANGER_RATE: if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger rate out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range"); props->Chorus.Rate = val; break; case AL_FLANGER_DEPTH: if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger depth out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range"); props->Chorus.Depth = val; break; case AL_FLANGER_FEEDBACK: if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger feedback out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range"); props->Chorus.Feedback = val; break; case AL_FLANGER_DELAY: if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Flanger delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range"); props->Chorus.Delay = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); } } void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -519,13 +519,11 @@ void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum par break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param); } } void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALflanger_getParami(effect, context, param, vals); -} +{ ALflanger_getParami(effect, context, param, vals); } void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -548,7 +546,7 @@ void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum par break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid flanger float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param); } } void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 330733b3..bb9be8b9 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -210,20 +210,21 @@ void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_COMPRESSOR_ONOFF: if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Compressor state out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range"); props->Compressor.OnOff = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); } } void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) { ALcompressor_setParami(effect, context, param, vals[0]); } -void ALcompressor_setParamf(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float property"); } -void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float-vector property"); } +void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void ALcompressor_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) { @@ -235,14 +236,15 @@ void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x", + param); } } void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) { ALcompressor_getParami(effect, context, param, vals); } -void ALcompressor_getParamf(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float property"); } -void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid compressor float-vector property"); } +void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); } +void ALcompressor_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); } DEFINE_ALEFFECT_VTABLE(ALcompressor); diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 684e8171..70a97ea9 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -139,10 +139,10 @@ ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void) } -void ALdedicated_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer property"); } -void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer-vector property"); } +void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void ALdedicated_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -150,21 +150,21 @@ void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_DEDICATED_GAIN: if(!(val >= 0.0f && isfinite(val))) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Dedicated gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range"); props->Dedicated.Gain = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); } } void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) { ALdedicated_setParamf(effect, context, param, vals[0]); } -void ALdedicated_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer property"); } -void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated integer-vector property"); } +void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); } +void ALdedicated_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); } void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -175,7 +175,7 @@ void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid dedicated float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param); } } void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 2a7c21ec..dcb2bfe4 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -198,10 +198,10 @@ ALeffectStateFactory *ALdistortionStateFactory_getFactory(void) } -void ALdistortion_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer property"); } -void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer-vector property"); } +void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void ALdistortion_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -209,45 +209,46 @@ void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_DISTORTION_EDGE: if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion edge out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range"); props->Distortion.Edge = val; break; case AL_DISTORTION_GAIN: if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range"); props->Distortion.Gain = val; break; case AL_DISTORTION_LOWPASS_CUTOFF: if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion low-pass cutoff out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range"); props->Distortion.LowpassCutoff = val; break; case AL_DISTORTION_EQCENTER: if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion EQ center out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range"); props->Distortion.EQCenter = val; break; case AL_DISTORTION_EQBANDWIDTH: if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Distortion EQ bandwidth out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range"); props->Distortion.EQBandwidth = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); } } void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) { ALdistortion_setParamf(effect, context, param, vals[0]); } -void ALdistortion_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer property"); } -void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion integer-vector property"); } +void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); } +void ALdistortion_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); } void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -274,7 +275,8 @@ void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid distortion float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", + param); } } void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index b59b06b0..d8cbd214 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -230,10 +230,10 @@ ALeffectStateFactory *ALechoStateFactory_getFactory(void) } -void ALecho_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer property"); } -void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer-vector property"); } +void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void ALecho_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -241,45 +241,45 @@ void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALflo { case AL_ECHO_DELAY: if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range"); props->Echo.Delay = val; break; case AL_ECHO_LRDELAY: if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo LR delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range"); props->Echo.LRDelay = val; break; case AL_ECHO_DAMPING: if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo damping out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range"); props->Echo.Damping = val; break; case AL_ECHO_FEEDBACK: if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo feedback out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range"); props->Echo.Feedback = val; break; case AL_ECHO_SPREAD: if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Echo spread out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range"); props->Echo.Spread = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); } } void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) { ALecho_setParamf(effect, context, param, vals[0]); } -void ALecho_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer property"); } -void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo integer-vector property"); } +void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); } +void ALecho_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); } void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -306,7 +306,7 @@ void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid echo float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param); } } void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index b800d27a..8c2b31e2 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -220,10 +220,10 @@ ALeffectStateFactory *ALequalizerStateFactory_getFactory(void) } -void ALequalizer_setParami(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer property"); } -void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer-vector property"); } +void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void ALequalizer_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) { ALeffectProps *props = &effect->Props; @@ -231,75 +231,75 @@ void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EQUALIZER_LOW_GAIN: if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer low-band gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range"); props->Equalizer.LowGain = val; break; case AL_EQUALIZER_LOW_CUTOFF: if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer low-band cutoff out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range"); props->Equalizer.LowCutoff = val; break; case AL_EQUALIZER_MID1_GAIN: if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range"); props->Equalizer.Mid1Gain = val; break; case AL_EQUALIZER_MID1_CENTER: if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band center out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range"); props->Equalizer.Mid1Center = val; break; case AL_EQUALIZER_MID1_WIDTH: if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid1-band width out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range"); props->Equalizer.Mid1Width = val; break; case AL_EQUALIZER_MID2_GAIN: if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range"); props->Equalizer.Mid2Gain = val; break; case AL_EQUALIZER_MID2_CENTER: if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band center out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range"); props->Equalizer.Mid2Center = val; break; case AL_EQUALIZER_MID2_WIDTH: if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer mid2-band width out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range"); props->Equalizer.Mid2Width = val; break; case AL_EQUALIZER_HIGH_GAIN: if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer high-band gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range"); props->Equalizer.HighGain = val; break; case AL_EQUALIZER_HIGH_CUTOFF: if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Equalizer high-band cutoff out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range"); props->Equalizer.HighCutoff = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); } } void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) { ALequalizer_setParamf(effect, context, param, vals[0]); } -void ALequalizer_getParami(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer property"); } -void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer integer-vector property"); } +void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); } +void ALequalizer_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); } void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) { const ALeffectProps *props = &effect->Props; @@ -346,7 +346,7 @@ void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid equalizer float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param); } } void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 0fb03042..ed0851d6 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -217,18 +217,18 @@ void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_RING_MODULATOR_FREQUENCY: if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Modulator frequency out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Modulator high-pass cutoff out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range"); props->Modulator.HighPassCutoff = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); } } void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -245,12 +245,12 @@ void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, case AL_RING_MODULATOR_WAVEFORM: if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Invalid modulator waveform",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform"); props->Modulator.Waveform = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); } } void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) @@ -272,7 +272,7 @@ void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param); } } void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) @@ -290,7 +290,7 @@ void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid modulator float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param); } } void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/Alc/effects/null.c b/Alc/effects/null.c index 2dc43870..f9583011 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -110,69 +110,69 @@ ALeffectStateFactory *ALnullStateFactory_getFactory(void) } -void ALnull_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint UNUSED(val)) +void ALnull_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); } } -void ALnull_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) +void ALnull_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer-vector property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); } } -void ALnull_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +void ALnull_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); } } -void ALnull_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) +void ALnull_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float-vector property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); } } -void ALnull_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint* UNUSED(val)) +void ALnull_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param); } } -void ALnull_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint* UNUSED(vals)) +void ALnull_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect integer-vector property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param); } } -void ALnull_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) +void ALnull_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param); } } -void ALnull_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) +void ALnull_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals)) { switch(param) { - default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid null effect float-vector property"); + default: + alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param); } } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0cebab9b..64aa8916 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1775,12 +1775,13 @@ void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EAXREVERB_DECAY_HFLIMIT: if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay hflimit out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hflimit out of range"); props->Reverb.DecayHFLimit = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); } } void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) @@ -1792,126 +1793,127 @@ void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EAXREVERB_DENSITY: if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb density out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb density out of range"); props->Reverb.Density = val; break; case AL_EAXREVERB_DIFFUSION: if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb diffusion out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb diffusion out of range"); props->Reverb.Diffusion = val; break; case AL_EAXREVERB_GAIN: if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gain out of range"); props->Reverb.Gain = val; break; case AL_EAXREVERB_GAINHF: if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainhf out of range"); props->Reverb.GainHF = val; break; case AL_EAXREVERB_GAINLF: if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb gainlf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb gainlf out of range"); props->Reverb.GainLF = val; break; case AL_EAXREVERB_DECAY_TIME: if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay time out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay time out of range"); props->Reverb.DecayTime = val; break; case AL_EAXREVERB_DECAY_HFRATIO: if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay hfratio out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay hfratio out of range"); props->Reverb.DecayHFRatio = val; break; case AL_EAXREVERB_DECAY_LFRATIO: if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb decay lfratio out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb decay lfratio out of range"); props->Reverb.DecayLFRatio = val; break; case AL_EAXREVERB_REFLECTIONS_GAIN: if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections gain out of range"); props->Reverb.ReflectionsGain = val; break; case AL_EAXREVERB_REFLECTIONS_DELAY: if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections delay out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb gain out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb delay out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb air absorption gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb air absorption gainhf out of range"); props->Reverb.AirAbsorptionGainHF = val; break; case AL_EAXREVERB_ECHO_TIME: if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb echo time out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo time out of range"); props->Reverb.EchoTime = val; break; case AL_EAXREVERB_ECHO_DEPTH: if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb echo depth out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb echo depth out of range"); props->Reverb.EchoDepth = val; break; case AL_EAXREVERB_MODULATION_TIME: if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb modulation time out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation time out of range"); props->Reverb.ModulationTime = val; break; case AL_EAXREVERB_MODULATION_DEPTH: if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb modulation depth out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb modulation depth out of range"); props->Reverb.ModulationDepth = val; break; case AL_EAXREVERB_HFREFERENCE: if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb hfreference out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb hfreference out of range"); props->Reverb.HFReference = val; break; case AL_EAXREVERB_LFREFERENCE: if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb lfreference out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb lfreference out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb room rolloff factor out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb room rolloff factor out of range"); props->Reverb.RoomRolloffFactor = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); } } void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -1921,14 +1923,14 @@ void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, { case AL_EAXREVERB_REFLECTIONS_PAN: if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb reflections pan out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb reflections pan out of range"); props->Reverb.ReflectionsPan[0] = vals[0]; props->Reverb.ReflectionsPan[1] = vals[1]; props->Reverb.ReflectionsPan[2] = vals[2]; break; case AL_EAXREVERB_LATE_REVERB_PAN: if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "EAX Reverb late reverb pan out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "EAX Reverb late reverb pan out of range"); props->Reverb.LateReverbPan[0] = vals[0]; props->Reverb.LateReverbPan[1] = vals[1]; props->Reverb.LateReverbPan[2] = vals[2]; @@ -1950,7 +1952,8 @@ void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb integer property 0x%04x", + param); } } void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) @@ -2041,7 +2044,8 @@ void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid EAX reverb float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid EAX reverb float property 0x%04x", + param); } } void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) @@ -2075,12 +2079,12 @@ void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALi { case AL_REVERB_DECAY_HFLIMIT: if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay hflimit out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hflimit out of range"); props->Reverb.DecayHFLimit = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); } } void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) @@ -2092,78 +2096,78 @@ void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALf { case AL_REVERB_DENSITY: if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb density out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb density out of range"); props->Reverb.Density = val; break; case AL_REVERB_DIFFUSION: if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb diffusion out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb diffusion out of range"); props->Reverb.Diffusion = val; break; case AL_REVERB_GAIN: if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gain out of range"); props->Reverb.Gain = val; break; case AL_REVERB_GAINHF: if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb gainhf out of range"); props->Reverb.GainHF = val; break; case AL_REVERB_DECAY_TIME: if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay time out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay time out of range"); props->Reverb.DecayTime = val; break; case AL_REVERB_DECAY_HFRATIO: if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb decay hfratio out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb decay hfratio out of range"); props->Reverb.DecayHFRatio = val; break; case AL_REVERB_REFLECTIONS_GAIN: if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb reflections gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections gain out of range"); props->Reverb.ReflectionsGain = val; break; case AL_REVERB_REFLECTIONS_DELAY: if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb reflections delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb reflections delay out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb late reverb gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb gain out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb late reverb delay out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb late reverb delay out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb air absorption gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb air absorption gainhf out of range"); 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)) - SETERR_RETURN(context, AL_INVALID_VALUE, effect->id, "Reverb room rolloff factor out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Reverb room rolloff factor out of range"); props->Reverb.RoomRolloffFactor = val; break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); } } void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) @@ -2179,7 +2183,7 @@ void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid reverb integer property 0x%04x", param); } } void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) @@ -2238,7 +2242,7 @@ void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para break; default: - alSetError(context, AL_INVALID_ENUM, effect->id, "Invalid reverb float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid reverb float property 0x%04x", param); } } void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 3dc16103..479697f2 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -9,15 +9,15 @@ extern "C" { extern ALboolean TrapALError; -ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const char *msg); +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...); -#define SETERR_GOTO(ctx, err, objid, msg, lbl) do { \ - alSetError((ctx), (err), (objid), (msg)); \ +#define SETERR_GOTO(ctx, err, lbl, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ goto lbl; \ } while(0) -#define SETERR_RETURN(ctx, err, objid, msg, retval) do { \ - alSetError((ctx), (err), (objid), (msg)); \ +#define SETERR_RETURN(ctx, err, retval, ...) do { \ + alSetError((ctx), (err), __VA_ARGS__); \ return retval; \ } while(0) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index a8186f07..d2039097 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -73,7 +73,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative effect slots", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); LockEffectSlotsWrite(context); @@ -87,7 +87,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo UnlockEffectSlotsWrite(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, 0, "Effect slot object allocation failed", done); + SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); } err = NewThunkEntry(&slot->id); @@ -103,7 +103,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo UnlockEffectSlotsWrite(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, 0, "Failed to set effect slot ID", done); + SETERR_GOTO(context, err, done, "Failed to set effect slot ID"); } aluInitEffectPanning(slot); @@ -149,15 +149,15 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * LockEffectSlotsWrite(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative effect slots", - done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslots[i], "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", + effectslots[i]); if(ReadRef(&slot->ref) != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, effectslots[i], - "Deleting in-use effect slot", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u", + effectslots[i]); } // All effectslots are valid @@ -240,7 +240,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param WriteLock(&context->PropLock); LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_EFFECT: @@ -251,25 +251,25 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!(value == 0 || effect != NULL)) { UnlockEffectsRead(device); - SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, "Invalid effect ID", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); } err = InitializeEffect(context, slot, effect); UnlockEffectsRead(device); if(err != AL_NO_ERROR) - SETERR_GOTO(context, err, effectslot, "Effect initialization failed", done); + SETERR_GOTO(context, err, done, "Effect initialization failed"); break; case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: if(!(value == AL_TRUE || value == AL_FALSE)) - SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, - "Effect slot auxiliary send auto out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Effect slot auxiliary send auto out of range"); slot->AuxSendAuto = value; break; default: - SETERR_GOTO(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot integer property", - done); + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x", + param); } DO_UPDATEPROPS(); @@ -296,12 +296,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, effectslot, - "Invalid effect slot integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", + param); } done: @@ -320,19 +320,18 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param WriteLock(&context->PropLock); LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_GAIN: if(!(value >= 0.0f && value <= 1.0f)) - SETERR_GOTO(context, AL_INVALID_VALUE, effectslot, "Effect slot gain out of range", - done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range"); slot->Gain = value; break; default: - SETERR_GOTO(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot float property", - done); + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x", + param); } DO_UPDATEPROPS(); @@ -358,12 +357,12 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, effectslot, - "Invalid effect slot float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", + param); } done: @@ -381,7 +380,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: @@ -389,7 +388,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param); } done: @@ -414,12 +413,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, effectslot, - "Invalid effect slot integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x", + param); } done: @@ -437,7 +436,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa LockEffectSlotsRead(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { case AL_EFFECTSLOT_GAIN: @@ -445,7 +444,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, effectslot, "Invalid effect slot float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param); } done: @@ -469,12 +468,12 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p LockEffectSlotsRead(context); if(LookupEffectSlot(context, effectslot) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effectslot, "Invalid effect slot ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, effectslot, - "Invalid effect slot float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x", + param); } done: diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 922c379c..0ef4bf69 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -66,7 +66,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative buffers", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d buffers", n); for(cur = 0;cur < n;cur++) { @@ -98,7 +98,7 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) LockBuffersWrite(device); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative buffers", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d buffers", n); for(i = 0;i < n;i++) { @@ -107,9 +107,10 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) /* Check for valid Buffer ID */ if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffers[i], "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffers[i]); if(ReadRef(&ALBuf->ref) != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffers[i], "Deleting in-use buffer", done); + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Deleting in-use buffer %u", + buffers[i]); } for(i = 0;i < n;i++) @@ -161,19 +162,20 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); - if(!(size >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Negative storage size", done); - if(!(freq > 0)) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid sample rate", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); + if(!(size >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Negative storage size %d", size); + if(!(freq > 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid sample rate %d", freq); if((flags&INVALID_STORAGE_MASK) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid storage flags", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); if((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Declaring persistently mapped storage without read or write access", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Declaring persistently mapped storage without read or write access"); if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Invalid format", done); + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid format 0x%04x", format); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid unpack alignment", done); + if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid unpack alignment"); switch(srctype) { @@ -195,7 +197,8 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const break; } if((size%framesize) != 0) - alSetError(context, AL_INVALID_VALUE, buffer, "Data size is not a frame multiple"); + alSetError(context, AL_INVALID_VALUE, "Data size %d is not a multiple of frame size %d", + size, framesize); else LoadData(context, albuf, freq, size/framesize*align, srcchannels, srctype, data, align, flags); @@ -218,32 +221,33 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); if((access&~MAP_ACCESS_FLAGS) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid map flags", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid map flags 0x%x", + access&~MAP_ACCESS_FLAGS); if(!(access&MAP_READ_WRITE_FLAGS)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Mapping buffer without read or write access", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Mapping buffer without read or write access"); WriteLock(&albuf->lock); if(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, - "Mapping in-use buffer without persistent mapping", unlock_done); + SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, + "Mapping in-use buffer without persistent mapping"); if(albuf->MappedAccess != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, "Mapping already-mapped buffer", - unlock_done); + SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, "Mapping already-mapped buffer"); if((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Mapping buffer for reading without read access", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, + "Mapping buffer for reading without read access"); if((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Mapping buffer for writing without write access", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, + "Mapping buffer for writing without write access"); if((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Mapping buffer persistently without persistent access", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, + "Mapping buffer persistently without persistent access"); if(offset < 0 || offset >= albuf->OriginalSize || length <= 0 || length > albuf->OriginalSize - offset) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Mapping out of range", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Mapping invalid range %d+%d", + offset, length); retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; @@ -272,11 +276,11 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); WriteLock(&albuf->lock); if(albuf->MappedAccess == 0) - alSetError(context, AL_INVALID_OPERATION, albuf->id, "Unmapping an unmapped buffer"); + alSetError(context, AL_INVALID_OPERATION, "Unmapping an unmapped buffer %u", buffer); else { albuf->MappedAccess = 0; @@ -302,15 +306,15 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); WriteLock(&albuf->lock); if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) - alSetError(context, AL_INVALID_OPERATION, albuf->id, - "Flushing a buffer not mapped for writing"); + alSetError(context, AL_INVALID_OPERATION, "Flushing buffer %u not mapped for writing", + buffer); else if(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) - alSetError(context, AL_INVALID_VALUE, albuf->id, "Flushing an invalid range"); + alSetError(context, AL_INVALID_VALUE, "Flushing an invalid range %d+%d", offset, length); else { /* FIXME: Need to use some method of double-buffering for the mixer and @@ -346,22 +350,22 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Invalid format", done); + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid format 0x%04x", format); WriteLock(&albuf->lock); align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid unpack alignment", done); + if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid unpack alignment"); if((long)srcchannels != (long)albuf->FmtChannels || srctype != albuf->OriginalType) - SETERR_GOTO(context, AL_INVALID_ENUM, buffer, "Unpacking data with mismatched format", - unlock_done); + SETERR_GOTO(context, AL_INVALID_ENUM, unlock_done, + "Unpacking data with mismatched format"); if(align != albuf->OriginalAlign) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Unpacking data with mismatched alignment", - unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, + "Unpacking data with mismatched alignment"); if(albuf->MappedAccess != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, "Unpacking data into mapped buffer", - unlock_done); + SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, + "Unpacking data into mapped buffer"); num_chans = ChannelsFromFmt(albuf->FmtChannels); frame_size = num_chans * BytesFromFmt(albuf->FmtType); @@ -374,9 +378,10 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons if(offset < 0 || length < 0 || offset > albuf->OriginalSize || length > albuf->OriginalSize-offset) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Data sub-range out of range", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid data sub-range %d+%d", + offset, length); if((offset%byte_align) != 0 || (length%byte_align) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid sub-range alignment", unlock_done); + SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid sub-range alignment"); /* offset -> byte offset, length -> sample count */ offset = offset/byte_align * frame_size; @@ -411,7 +416,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION, 0, "alBufferSamplesSOFT not supported"); + alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -425,7 +430,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION, 0, "alBufferSubSamplesSOFT not supported"); + alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -439,7 +444,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint UNUSED(buffer), context = GetContextRef(); if(!context) return; - alSetError(context, AL_INVALID_OPERATION, 0, "alGetBufferSamplesSOFT not supported"); + alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); ALCcontext_DecRef(context); } @@ -451,7 +456,7 @@ AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format) context = GetContextRef(); if(!context) return AL_FALSE; - alSetError(context, AL_INVALID_OPERATION, 0, "alIsBufferFormatSupportedSOFT not supported"); + alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); ALCcontext_DecRef(context); return AL_FALSE; @@ -469,12 +474,12 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } done: @@ -494,12 +499,12 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } done: @@ -519,13 +524,13 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } done: @@ -546,26 +551,26 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); switch(param) { case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, - "Negative buffer unpack block alignment", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Buffer unpack block alignment %d is invalid", value); ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Negative buffer pack block alignment", - done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, + "Buffer pack block alignment %d is invalid", value); ATOMIC_STORE_SEQ(&albuf->PackAlign, value); break; default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } done: @@ -584,12 +589,12 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val device = context->Device; if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } done: @@ -620,9 +625,9 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { case AL_LOOP_POINTS_SOFT: @@ -630,14 +635,15 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val if(ReadRef(&albuf->ref) != 0) { WriteUnlock(&albuf->lock); - SETERR_GOTO(context, AL_INVALID_OPERATION, buffer, - "Modifying in-use buffer loop points", done); + SETERR_GOTO(context, AL_INVALID_OPERATION, done, + "Modifying in-use buffer loop points"); } if(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen) { WriteUnlock(&albuf->lock); - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "Invalid loop point range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid loop point range %d -> %d", + values[0], values[1]); } albuf->LoopStart = values[0]; @@ -646,7 +652,8 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val break; default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); } done: @@ -667,13 +674,13 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } done: @@ -693,14 +700,14 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); if(!value1 || !value2 || !value3) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } done: @@ -727,13 +734,13 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } done: @@ -754,9 +761,9 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { case AL_FREQUENCY: @@ -787,7 +794,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } done: @@ -807,14 +814,14 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 device = context->Device; LockBuffersRead(device); if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); if(!value1 || !value2 || !value3) - SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer 3-integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } done: @@ -850,9 +857,9 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, buffer, "Invalid buffer ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, buffer, "NULL pointer", done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { case AL_LOOP_POINTS_SOFT: @@ -863,7 +870,8 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values break; default: - alSetError(context, AL_INVALID_ENUM, buffer, "Invalid buffer integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + param); } done: @@ -898,7 +906,7 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei case UserFmtBFormat3D: DstChannels = FmtBFormat3D; break; } if(UNLIKELY((long)SrcChannels != (long)DstChannels)) - SETERR_RETURN(context, AL_INVALID_ENUM, ALBuf->id, "Invalid format",); + SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid format"); /* IMA4 and MSADPCM convert to 16-bit short. */ switch(SrcType) @@ -916,23 +924,22 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(access != 0) { if(UNLIKELY((long)SrcType != (long)DstType)) - SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Format cannot be mapped or preserved",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Format cannot be mapped or preserved"); } NumChannels = ChannelsFromFmt(DstChannels); FrameSize = NumChannels * BytesFromFmt(DstType); if(UNLIKELY(frames > INT_MAX/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Buffer size too large",); + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); newsize = frames*FrameSize; WriteLock(&ALBuf->lock); if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) { WriteUnlock(&ALBuf->lock); - SETERR_RETURN(context, AL_INVALID_OPERATION, ALBuf->id, - "Modifying storage for in-use buffer",); + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer"); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) @@ -941,14 +948,12 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) { WriteUnlock(&ALBuf->lock); - SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Preserving data of mismatched format",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); } if(UNLIKELY(ALBuf->OriginalAlign != align)) { WriteUnlock(&ALBuf->lock); - SETERR_RETURN(context, AL_INVALID_VALUE, ALBuf->id, - "Preserving data of mismatched alignment",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); } } @@ -966,7 +971,8 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei if(UNLIKELY(!temp && newsize)) { WriteUnlock(&ALBuf->lock); - SETERR_RETURN(context, AL_OUT_OF_MEMORY, ALBuf->id, "Failed to allocate storage",); + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", + newsize); } if((access&AL_PRESERVE_DATA_BIT_SOFT)) { @@ -1204,7 +1210,7 @@ ALbuffer *NewBuffer(ALCcontext *context) buffer = al_calloc(16, sizeof(ALbuffer)); if(!buffer) - SETERR_RETURN(context, AL_OUT_OF_MEMORY, 0, "Failed to allocate buffer object", NULL); + SETERR_RETURN(context, AL_OUT_OF_MEMORY, NULL, "Failed to allocate buffer object"); RWLockInit(&buffer->lock); buffer->Access = 0; buffer->MappedAccess = 0; @@ -1218,7 +1224,7 @@ ALbuffer *NewBuffer(ALCcontext *context) memset(buffer, 0, sizeof(ALbuffer)); al_free(buffer); - SETERR_RETURN(context, err, 0, "Failed to set buffer ID", NULL); + SETERR_RETURN(context, err, NULL, "Failed to set buffer ID"); } return buffer; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 5f6e661a..ab42112c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -69,7 +69,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative effects", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effects", n); device = context->Device; for(cur = 0;cur < n;cur++) @@ -80,7 +80,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) { al_free(effect); alDeleteEffects(cur, effects); - SETERR_GOTO(context, err, 0, "Failed to allocate effect object", done); + SETERR_GOTO(context, err, done, "Failed to allocate effect object"); } err = NewThunkEntry(&effect->id); @@ -93,7 +93,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) al_free(effect); alDeleteEffects(cur, effects); - SETERR_GOTO(context, err, 0, "Failed to set effect ID", done); + SETERR_GOTO(context, err, done, "Failed to set effect ID"); } effects[cur] = effect->id; @@ -116,11 +116,11 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) device = context->Device; LockEffectsWrite(device); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative effects", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); for(i = 0;i < n;i++) { if(effects[i] && LookupEffect(device, effects[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, effects[i], "Invalid effect ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]); } for(i = 0;i < n;i++) { @@ -167,7 +167,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) @@ -184,7 +184,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(isOk) InitEffectParams(ALEffect, value); else - alSetError(Context, AL_INVALID_VALUE, effect, "Effect type not supported"); + alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value); } else { @@ -216,7 +216,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -239,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -262,7 +262,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat Device = Context->Device; LockEffectsWrite(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -285,7 +285,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { if(param == AL_EFFECT_TYPE) @@ -320,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -343,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ @@ -366,7 +366,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va Device = Context->Device; LockEffectsRead(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) - alSetError(Context, AL_INVALID_NAME, effect, "Invalid effect ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else { /* Call the appropriate handler */ diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index 8d138aa2..fe0e02be 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -21,6 +21,7 @@ #include "config.h" #include +#include #ifdef HAVE_WINDOWS_H #define WIN32_LEAN_AND_MEAN @@ -33,12 +34,32 @@ ALboolean TrapALError = AL_FALSE; -ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const char *msg) +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) { ALenum curerr = AL_NO_ERROR; + char message[1024] = { 0 }; + va_list args; + int msglen; - WARN("Error generated on context %p, code 0x%04x, object %u, \"%s\"\n", - context, errorCode, objid, msg); + va_start(args, msg); + msglen = vsnprintf(message, sizeof(message), msg, args); + va_end(args); + + if(msglen < 0 || (size_t)msglen >= sizeof(message)) + { + message[sizeof(message)-1] = 0; + msglen = strlen(message); + } + if(msglen > 0) + msg = message; + else + { + msg = ""; + msglen = strlen(msg); + } + + WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", + context, errorCode, message); if(TrapALError) { #ifdef _WIN32 @@ -55,7 +76,7 @@ ALvoid alSetError(ALCcontext *context, ALenum errorCode, ALuint objid, const cha { almtx_lock(&context->EventLock); if((context->EnabledEvts&EventType_Error) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, objid, errorCode, strlen(msg), msg, + (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, context->EventParam); almtx_unlock(&context->EventLock); } @@ -86,6 +107,5 @@ AL_API ALenum AL_APIENTRY alGetError(void) errorCode = ATOMIC_EXCHANGE_SEQ(&context->LastError, AL_NO_ERROR); ALCcontext_DecRef(context); - return errorCode; } diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 9b6e5a97..f6378c70 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -46,7 +46,7 @@ AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) if(!context) return AL_FALSE; if(!extName) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); len = strlen(extName); ptr = context->ExtensionList; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 24b0e607..34f2f271 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -55,7 +55,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative filters", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d filters", n); device = context->Device; for(cur = 0;cur < n;cur++) @@ -64,7 +64,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!filter) { alDeleteFilters(cur, filters); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, 0, "Failed to allocate filter object", done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Failed to allocate filter object"); } InitFilterParams(filter, AL_FILTER_NULL); @@ -78,7 +78,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) al_free(filter); alDeleteFilters(cur, filters); - SETERR_GOTO(context, err, 0, "Failed ot set filter ID", done); + SETERR_GOTO(context, err, done, "Failed ot set filter ID"); } filters[cur] = filter->id; @@ -101,11 +101,11 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) device = context->Device; LockFiltersWrite(device); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative filters", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); for(i = 0;i < n;i++) { if(filters[i] && LookupFilter(device, filters[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, filters[i], "Invalid filter ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]); } for(i = 0;i < n;i++) { @@ -152,7 +152,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { if(param == AL_FILTER_TYPE) @@ -161,7 +161,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS) InitFilterParams(ALFilter, value); else - alSetError(Context, AL_INVALID_VALUE, filter, "Filter type not supported"); + alSetError(Context, AL_INVALID_VALUE, "Invalid filter type 0x%04x", value); } else { @@ -193,7 +193,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -216,7 +216,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -239,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat Device = Context->Device; LockFiltersWrite(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -262,7 +262,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { if(param == AL_FILTER_TYPE) @@ -297,7 +297,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -320,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -343,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va Device = Context->Device; LockFiltersRead(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) - alSetError(Context, AL_INVALID_NAME, filter, "Invalid filter ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else { /* Call the appropriate handler */ @@ -435,37 +435,37 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g } -static void ALlowpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer property"); } -static void ALlowpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer-vector property"); } +static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } static void ALlowpass_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)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Low-pass gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); filter->Gain = val; break; case AL_LOWPASS_GAINHF: if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Low-pass gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val); filter->GainHF = val; break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALlowpass_setParamf(filter, context, param, vals[0]); } -static void ALlowpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer property"); } -static void ALlowpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass integer-vector property"); } +static void ALlowpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } +static void ALlowpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); } static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -479,7 +479,7 @@ static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum pa break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid low-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param); } } static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -488,37 +488,37 @@ static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum p DEFINE_ALFILTER_VTABLE(ALlowpass); -static void ALhighpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer property"); } -static void ALhighpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer-vector property"); } +static void ALhighpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +static void ALhighpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { case AL_HIGHPASS_GAIN: if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "High-pass gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); filter->Gain = val; break; case AL_HIGHPASS_GAINLF: if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "High-pass gainlf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range"); filter->GainLF = val; break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALhighpass_setParamf(filter, context, param, vals[0]); } -static void ALhighpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer property"); } -static void ALhighpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass integer-vector property"); } +static void ALhighpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); } +static void ALhighpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); } static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -532,7 +532,7 @@ static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid high-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param); } } static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -541,43 +541,43 @@ static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum DEFINE_ALFILTER_VTABLE(ALhighpass); -static void ALbandpass_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer property"); } -static void ALbandpass_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer-vector property"); } +static void ALbandpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +static void ALbandpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) { switch(param) { case AL_BANDPASS_GAIN: if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gain out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); filter->Gain = val; break; case AL_BANDPASS_GAINHF: if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gainhf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range"); filter->GainHF = val; break; case AL_BANDPASS_GAINLF: if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF)) - SETERR_RETURN(context, AL_INVALID_VALUE, filter->id, "Band-pass gainlf out of range",); + SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range"); filter->GainLF = val; break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) { ALbandpass_setParamf(filter, context, param, vals[0]); } -static void ALbandpass_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer property"); } -static void ALbandpass_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass integer-vector property"); } +static void ALbandpass_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); } +static void ALbandpass_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); } static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) { switch(param) @@ -595,7 +595,7 @@ static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p break; default: - alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid band-pass float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param); } } static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) @@ -604,23 +604,23 @@ static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum DEFINE_ALFILTER_VTABLE(ALbandpass); -static void ALnullfilter_setParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_setParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_setParamf(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_setParamfv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } - -static void ALnullfilter_getParami(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_getParamiv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_getParamf(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } -static void ALnullfilter_getParamfv(ALfilter *filter, ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals)) -{ alSetError(context, AL_INVALID_ENUM, filter->id, "Invalid null filter property"); } +static void ALnullfilter_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_setParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } + +static void ALnullfilter_getParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } +static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ alSetError(context, AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); } DEFINE_ALFILTER_VTABLE(ALnullfilter); diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 51ab6fc9..6d1db2fb 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -48,15 +48,14 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) { case AL_GAIN: if(!(value >= 0.0f && isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener gain out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range"); listener->Gain = value; DO_UPDATEPROPS(); break; case AL_METERS_PER_UNIT: if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener meters per unit out of range", - done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener meters per unit out of range"); context->MetersPerUnit = value; if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) UpdateContextProps(context); @@ -88,7 +87,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val { case AL_POSITION: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener position out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range"); listener->Position[0] = value1; listener->Position[1] = value2; listener->Position[2] = value3; @@ -97,7 +96,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val case AL_VELOCITY: if(!(isfinite(value1) && isfinite(value2) && isfinite(value3))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener velocity out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range"); listener->Velocity[0] = value1; listener->Velocity[1] = value2; listener->Velocity[2] = value3; @@ -140,13 +139,13 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) listener = context->Listener; WriteLock(&context->PropLock); - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); + if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { case AL_ORIENTATION: if(!(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Listener orientation out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range"); /* AT then UP */ listener->Forward[0] = values[0]; listener->Forward[1] = values[1]; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c60b6a01..898e54d6 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -453,8 +453,7 @@ static ALint Int64ValsByProp(ALenum prop) #define CHECKVAL(x) do { \ if(!(x)) \ { \ - alSetError(Context, AL_INVALID_VALUE, Source->id, \ - "Value out of range"); \ + alSetError(Context, AL_INVALID_VALUE, "Value out of range"); \ return AL_FALSE; \ } \ } while(0) @@ -481,8 +480,8 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, - "Setting read-only source property", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); case AL_PITCH: CHECKVAL(*values >= 0.0f); @@ -606,8 +605,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); - SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid offset", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); } WriteUnlock(&Source->queue_lock); } @@ -700,7 +698,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source float property", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source float property 0x%04x", prop); } static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) @@ -722,8 +720,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, - "Setting read-only source property", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); case AL_SOURCE_RELATIVE: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); @@ -763,8 +761,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) { UnlockBuffersRead(device); - SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid buffer ID", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", + *values); } WriteLock(&Source->queue_lock); @@ -773,8 +771,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); - SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, - "Setting non-persistently mapped buffer", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting non-persistently mapped buffer %u", buffer->id); } else { @@ -783,8 +781,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); - SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, - "Setting buffer on playing or paused source", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting buffer on playing or paused source %u", Source->id); } } @@ -849,8 +847,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); - SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, - "Invalid source offset", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, + "Invalid source offset"); } WriteUnlock(&Source->queue_lock); } @@ -863,8 +861,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) { UnlockFiltersRead(device); - SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid filter ID", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + *values); } if(!filter) @@ -946,16 +944,24 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: LockEffectSlotsRead(Context); + if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) + { + UnlockEffectSlotsRead(Context); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", + values[0]); + } + if(!((ALuint)values[1] < (ALuint)device->NumAuxSends)) + { + UnlockEffectSlotsRead(Context); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); + } LockFiltersRead(device); - if(!((ALuint)values[1] < (ALuint)device->NumAuxSends && - (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && - (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) + if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) { UnlockFiltersRead(device); UnlockEffectSlotsRead(Context); - /* TODO: Fix message */ - SETERR_RETURN(Context, AL_INVALID_VALUE, Source->id, "Invalid send parameter", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", + values[2]); } if(!filter) @@ -1054,8 +1060,8 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer property", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); } static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) @@ -1075,8 +1081,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SAMPLE_LENGTH_SOFT: case AL_SEC_LENGTH_SOFT: /* Query only */ - SETERR_RETURN(Context, AL_INVALID_OPERATION, Source->id, - "Setting read-only source property", AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, + "Setting read-only source property 0x%04x", prop); /* 1x int */ case AL_SOURCE_RELATIVE: @@ -1160,8 +1166,8 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer64 property", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); } #undef CHECKVAL @@ -1358,8 +1364,8 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source double property", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source double property 0x%04x", + prop); } static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) @@ -1603,8 +1609,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer property", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer property 0x%04x", + prop); } static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) @@ -1736,8 +1742,8 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp } ERR("Unexpected property: 0x%04x\n", prop); - SETERR_RETURN(Context, AL_INVALID_ENUM, Source->id, "Invalid source integer64 property", - AL_FALSE); + SETERR_RETURN(Context, AL_INVALID_ENUM, AL_FALSE, "Invalid source integer64 property 0x%04x", + prop); } @@ -1752,7 +1758,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Generating negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d sources", n); device = context->Device; for(cur = 0;cur < n;cur++) { @@ -1760,7 +1766,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!source) { alDeleteSources(cur, sources); - SETERR_GOTO(context, AL_OUT_OF_MEMORY,0, "Failed to allocate source object", done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Failed to allocate source object"); } InitSourceParams(source, device->NumAuxSends); @@ -1774,7 +1780,7 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) al_free(source); alDeleteSources(cur, sources); - SETERR_GOTO(context, err, 0, "Failed to set source ID", done); + SETERR_GOTO(context, err, done, "Failed to set source ID"); } sources[cur] = source->id; @@ -1797,13 +1803,13 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) LockSourcesWrite(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Deleting negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); /* Check that all Sources are valid */ for(i = 0;i < n;i++) { if(LookupSource(context, sources[i]) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } device = context->Device; for(i = 0;i < n;i++) @@ -1863,9 +1869,9 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid float property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else SetSourcefv(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -1885,9 +1891,9 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-float property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALfloat fvals[3] = { value1, value2, value3 }; @@ -1910,11 +1916,11 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(FloatValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid float-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else SetSourcefv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -1935,9 +1941,9 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid double property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else { ALfloat fval = (ALfloat)value; @@ -1960,9 +1966,9 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-double property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; @@ -1986,11 +1992,11 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid double-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else { ALfloat fvals[6]; @@ -2018,9 +2024,9 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else SetSourceiv(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -2040,9 +2046,9 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3] = { value1, value2, value3 }; @@ -2065,11 +2071,11 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else SetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2090,9 +2096,9 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64 property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else SetSourcei64v(Source, Context, param, &value); UnlockSourcesRead(Context); @@ -2112,9 +2118,9 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer64 property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64SOFT i64vals[3] = { value1, value2, value3 }; @@ -2137,11 +2143,11 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin WriteLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else SetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2162,11 +2168,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid float property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else { ALdouble dval; @@ -2191,11 +2197,11 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-float property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-float property 0x%04x", param); else { ALdouble dvals[3]; @@ -2225,11 +2231,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!((count=FloatValsByProp(param)) > 0 && count <= 6)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid float-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else { ALdouble dvals[6]; @@ -2258,11 +2264,11 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid double property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else GetSourcedv(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2282,11 +2288,11 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-double property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-double property 0x%04x", param); else { ALdouble dvals[3]; @@ -2314,11 +2320,11 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(DoubleValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid double-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else GetSourcedv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2339,11 +2345,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else GetSourceiv(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2364,11 +2370,11 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer property 0x%04x", param); else { ALint ivals[3]; @@ -2397,11 +2403,11 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else GetSourceiv(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2422,11 +2428,11 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64 property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else GetSourcei64v(Source, Context, param, value); UnlockSourcesRead(Context); @@ -2446,11 +2452,11 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid 3-integer64 property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid 3-integer64 property 0x%04x", param); else { ALint64 i64vals[3]; @@ -2478,11 +2484,11 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 ReadLock(&Context->PropLock); LockSourcesRead(Context); if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME, source, "Invalid source ID"); + alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) - alSetError(Context, AL_INVALID_VALUE, source, "NULL pointer"); + alSetError(Context, AL_INVALID_VALUE, "NULL pointer"); else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM, source, "Invalid integer64-vector property"); + alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else GetSourcei64v(Source, Context, param, values); UnlockSourcesRead(Context); @@ -2509,11 +2515,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Playing negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } device = context->Device; @@ -2536,7 +2542,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(context->MaxVoices >= newcount) { ALCdevice_Unlock(device); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, 0, "Max voice count overflow", done); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, + "Overflow increasing voice count %d -> %d", context->MaxVoices, newcount); } AllocateVoices(context, newcount, device->NumAuxSends); } @@ -2696,11 +2703,11 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Pausing negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } device = context->Device; @@ -2743,11 +2750,11 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Stopping negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } device = context->Device; @@ -2793,11 +2800,11 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) LockSourcesRead(context); if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Rewinding negative sources", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); for(i = 0;i < n;i++) { if(!LookupSource(context, sources[i])) - SETERR_GOTO(context, AL_INVALID_NAME, sources[i], "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } device = context->Device; @@ -2847,16 +2854,16 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu LockSourcesRead(context); if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, src, "Queueing negative buffers", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb); if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); WriteLock(&source->queue_lock); if(source->SourceType == AL_STATIC) { WriteUnlock(&source->queue_lock); /* Can't queue on a Static Source */ - SETERR_GOTO(context, AL_INVALID_OPERATION, src, "Queueing onto a static source", done); + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); } /* Check for a valid Buffer, for its frequency and format */ @@ -2881,7 +2888,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) { WriteUnlock(&source->queue_lock); - SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid buffer ID", buffer_error); + SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", + buffers[i]); } if(!BufferListStart) @@ -2911,8 +2919,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { WriteUnlock(&source->queue_lock); - SETERR_GOTO(context, AL_INVALID_OPERATION, src, - "Queueing non-persistently mapped buffer", buffer_error); + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + "Queueing non-persistently mapped buffer %u", buffer->id); } if(BufferFmt == NULL) @@ -2922,8 +2930,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferFmt->OriginalType != buffer->OriginalType) { WriteUnlock(&source->queue_lock); - alSetError(context, AL_INVALID_OPERATION, src, - "Queueing buffer with mismatched format"); + alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); buffer_error: /* A buffer failed (invalid ID or format), so unlock and release @@ -2994,10 +3001,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint LockSourcesRead(context); if(!(nb >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing negative buffers", done); - + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb); if((source=LookupSource(context, src)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, src, "Invalid source ID", done); + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); /* Nothing to unqueue. */ if(nb == 0) goto done; @@ -3006,13 +3012,13 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if(source->Looping) { WriteUnlock(&source->queue_lock); - SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing from a looping source", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src); } if(source->SourceType != AL_STREAMING) { WriteUnlock(&source->queue_lock); - SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing from a non-streaming source", - done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", + src); } /* Find the new buffer queue head */ @@ -3034,7 +3040,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if(i != nb) { WriteUnlock(&source->queue_lock); - SETERR_GOTO(context, AL_INVALID_VALUE, src, "Unqueueing pending buffers", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); } /* Swap it, and cut the new head from the old. */ diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 9c49b2e8..1d442a1c 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -697,14 +697,15 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) if(!context) return; if(!(value >= 0.0f && isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Doppler factor out of range", done); - - WriteLock(&context->PropLock); - context->DopplerFactor = value; - DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + alSetError(context, AL_INVALID_VALUE, "Doppler factor out of range"); + else + { + WriteLock(&context->PropLock); + context->DopplerFactor = value; + DO_UPDATEPROPS(); + WriteUnlock(&context->PropLock); + } -done: ALCcontext_DecRef(context); } @@ -727,14 +728,15 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) } if(!(value >= 0.0f && isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Doppler velocity out of range", done); - - WriteLock(&context->PropLock); - context->DopplerVelocity = value; - DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + alSetError(context, AL_INVALID_VALUE, "Doppler velocity out of range"); + else + { + WriteLock(&context->PropLock); + context->DopplerVelocity = value; + DO_UPDATEPROPS(); + WriteUnlock(&context->PropLock); + } -done: ALCcontext_DecRef(context); } @@ -746,14 +748,15 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) if(!context) return; if(!(value > 0.0f && isfinite(value))) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Speed of sound out of range", done); - - WriteLock(&context->PropLock); - context->SpeedOfSound = value; - DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + alSetError(context, AL_INVALID_VALUE, "Speed of sound out of range"); + else + { + WriteLock(&context->PropLock); + context->SpeedOfSound = value; + DO_UPDATEPROPS(); + WriteUnlock(&context->PropLock); + } -done: ALCcontext_DecRef(context); } @@ -768,15 +771,16 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || value == AL_NONE)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Distance model out of range", done); - - WriteLock(&context->PropLock); - context->DistanceModel = value; - if(!context->SourceDistanceModel) - DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + alSetError(context, AL_INVALID_VALUE, "Distance model out of range"); + else + { + WriteLock(&context->PropLock); + context->DistanceModel = value; + if(!context->SourceDistanceModel) + DO_UPDATEPROPS(); + WriteUnlock(&context->PropLock); + } -done: ALCcontext_DecRef(context); } @@ -825,7 +829,7 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) { case AL_RESAMPLER_NAME_SOFT: if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) - SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Resampler name index out of range", done); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index out of range"); value = ResamplerNames[index]; break; @@ -835,7 +839,6 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) done: ALCcontext_DecRef(context); - return value; } diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 06db8713..3b70c9f3 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -17,9 +17,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A context = GetContextRef(); if(!context) return; - if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "Controlling negative events", done); + if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Controlling %d events", count); if(count == 0) goto done; - if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, 0, "NULL pointer", done); + if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); for(i = 0;i < count;i++) { @@ -34,7 +34,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT) flags |= EventType_Deprecated; else - SETERR_GOTO(context, AL_INVALID_ENUM, 0, "Invalid event type", done); + SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); } almtx_lock(&context->EventLock); -- cgit v1.2.3 From 6ae7fc5df1184f748b9c71f3f8d0dfe504ae19b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 25 Jan 2018 23:52:09 -0800 Subject: Add the printf-format attribute to alSetError --- OpenAL32/Include/alError.h | 3 ++- OpenAL32/alListener.c | 38 ++++++++++++++--------------- OpenAL32/alState.c | 60 +++++++++++++++++++++++----------------------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h index 479697f2..858f81de 100644 --- a/OpenAL32/Include/alError.h +++ b/OpenAL32/Include/alError.h @@ -2,6 +2,7 @@ #define _AL_ERROR_H_ #include "alMain.h" +#include "logging.h" #ifdef __cplusplus extern "C" { @@ -9,7 +10,7 @@ extern "C" { extern ALboolean TrapALError; -void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...); +void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4); #define SETERR_GOTO(ctx, err, lbl, ...) do { \ alSetError((ctx), (err), __VA_ARGS__); \ diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 6d1db2fb..290ae8ca 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -64,7 +64,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); } done: @@ -104,7 +104,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); } done: @@ -157,7 +157,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); } done: @@ -177,7 +177,7 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) switch(param) { default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); } WriteUnlock(&context->PropLock); @@ -204,7 +204,7 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A switch(param) { default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); } WriteUnlock(&context->PropLock); @@ -243,11 +243,11 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) WriteLock(&context->PropLock); if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); } WriteUnlock(&context->PropLock); @@ -264,7 +264,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) ReadLock(&context->PropLock); if(!value) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_GAIN: @@ -276,7 +276,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); } ReadUnlock(&context->PropLock); @@ -293,7 +293,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat ReadLock(&context->PropLock); if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: @@ -309,7 +309,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-float property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); } ReadUnlock(&context->PropLock); @@ -339,7 +339,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) ReadLock(&context->PropLock); if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: @@ -353,7 +353,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener float-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); } ReadUnlock(&context->PropLock); @@ -370,11 +370,11 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) ReadLock(&context->PropLock); if(!value) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); } ReadUnlock(&context->PropLock); @@ -391,7 +391,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu ReadLock(&context->PropLock); if(!value1 || !value2 || !value3) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_POSITION: @@ -407,7 +407,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener 3-integer property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); } ReadUnlock(&context->PropLock); @@ -432,7 +432,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) ReadLock(&context->PropLock); if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_ORIENTATION: @@ -446,7 +446,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) break; default: - alSetError(context, AL_INVALID_ENUM, 0, "Invalid listener integer-vector property"); + alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); } ReadUnlock(&context->PropLock); diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 1d442a1c..2637aacd 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -88,7 +88,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid enable property"); + alSetError(context, AL_INVALID_VALUE, "Invalid enable property"); } WriteUnlock(&context->PropLock); @@ -111,7 +111,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid disable property"); + alSetError(context, AL_INVALID_VALUE, "Invalid disable property"); } WriteUnlock(&context->PropLock); @@ -133,7 +133,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid is enabled property"); + alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property"); } ALCcontext_DecRef(context); @@ -190,7 +190,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean property"); + alSetError(context, AL_INVALID_VALUE, "Invalid boolean property"); } ALCcontext_DecRef(context); @@ -241,7 +241,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid double property"); + alSetError(context, AL_INVALID_VALUE, "Invalid double property"); } ALCcontext_DecRef(context); @@ -292,7 +292,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid float property"); + alSetError(context, AL_INVALID_VALUE, "Invalid float property"); } ALCcontext_DecRef(context); @@ -343,7 +343,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer property"); } ALCcontext_DecRef(context); @@ -394,7 +394,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64 property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property"); } ALCcontext_DecRef(context); @@ -411,16 +411,16 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) switch(pname) { - case AL_EVENT_CALLBACK_FUNCTION_SOFT: - value = context->EventCb; - break; + case AL_EVENT_CALLBACK_FUNCTION_SOFT: + value = context->EventCb; + break; - case AL_EVENT_CALLBACK_USER_PARAM_SOFT: - value = context->EventParam; - break; + case AL_EVENT_CALLBACK_USER_PARAM_SOFT: + value = context->EventParam; + break; - default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer property"); + default: + alSetError(context, AL_INVALID_VALUE, "Invalid pointer property"); } ALCcontext_DecRef(context); @@ -452,11 +452,11 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid boolean-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid boolean-vector property"); } ALCcontext_DecRef(context); @@ -487,11 +487,11 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid double-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid double-vector property"); } ALCcontext_DecRef(context); @@ -522,11 +522,11 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid float-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid float-vector property"); } ALCcontext_DecRef(context); @@ -557,11 +557,11 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer-vector property"); } ALCcontext_DecRef(context); @@ -592,11 +592,11 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid integer64-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer64-vector property"); } ALCcontext_DecRef(context); @@ -621,11 +621,11 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) if(!context) return; if(!values) - alSetError(context, AL_INVALID_VALUE, 0, "NULL pointer"); + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid pointer-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid pointer-vector property"); } ALCcontext_DecRef(context); @@ -682,7 +682,7 @@ AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid string property"); + alSetError(context, AL_INVALID_VALUE, "Invalid string property"); } ALCcontext_DecRef(context); @@ -834,7 +834,7 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) break; default: - alSetError(context, AL_INVALID_VALUE, 0, "Invalid string indexed property"); + alSetError(context, AL_INVALID_VALUE, "Invalid string indexed property"); } done: -- cgit v1.2.3 From fbafbe627297c44655baa30dc271bd20b833e4bc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jan 2018 00:13:03 -0800 Subject: Improve error reporting for buffers --- OpenAL32/alBuffer.c | 531 ++++++++++++++++++++++++++-------------------------- 1 file changed, 269 insertions(+), 262 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 0ef4bf69..474773b7 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -54,7 +54,7 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) -#define MAP_ACCESS_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) +#define INVALID_MAP_FLAGS ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) @@ -66,9 +66,8 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d buffers", n); - - for(cur = 0;cur < n;cur++) + alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n); + else for(cur = 0;cur < n;cur++) { ALbuffer *buffer = NewBuffer(context); if(!buffer) @@ -80,7 +79,6 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) buffers[cur] = buffer->id; } -done: ALCcontext_DecRef(context); } @@ -97,22 +95,29 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) device = context->Device; LockBuffersWrite(device); - if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d buffers", n); + if(UNLIKELY(n < 0)) + { + alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n); + goto done; + } for(i = 0;i < n;i++) { if(!buffers[i]) continue; - /* Check for valid Buffer ID */ + /* Check for valid Buffer ID, and make sure it's not in use. */ if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffers[i]); + { + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]); + goto done; + } if(ReadRef(&ALBuf->ref) != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Deleting in-use buffer %u", - buffers[i]); + { + alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]); + goto done; + } } - for(i = 0;i < n;i++) { if((ALBuf=LookupBuffer(device, buffers[i])) != NULL) @@ -161,24 +166,26 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(!(size >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Negative storage size %d", size); - if(!(freq > 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid sample rate %d", freq); - if((flags&INVALID_STORAGE_MASK) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid storage flags 0x%x", - flags&INVALID_STORAGE_MASK); - if((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Declaring persistently mapped storage without read or write access"); - if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid format 0x%04x", format); - - align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid unpack alignment"); - - switch(srctype) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(size < 0)) + alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size); + else if(UNLIKELY(freq < 1)) + alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq); + else if(UNLIKELY((flags&INVALID_STORAGE_MASK) != 0)) + alSetError(context, AL_INVALID_VALUE, "Invalid storage flags 0x%x", + flags&INVALID_STORAGE_MASK); + else if(UNLIKELY((flags&AL_MAP_PERSISTENT_BIT_SOFT) && !(flags&MAP_READ_WRITE_FLAGS))) + alSetError(context, AL_INVALID_VALUE, + "Declaring persistently mapped storage without read or write access"); + else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) + alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); + else if(UNLIKELY((align=SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign))) < 1)) + alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment"); + else { + switch(srctype) + { case UserFmtUByte: case UserFmtShort: case UserFmtFloat: @@ -195,15 +202,16 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const case UserFmtMSADPCM: framesize = ((align-2)/2 + 7) * ChannelsFromUserFmt(srcchannels); break; + } + if((size%framesize) != 0) + alSetError(context, AL_INVALID_VALUE, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, framesize, align); + else + LoadData(context, albuf, freq, size/framesize*align, srcchannels, srctype, data, align, + flags); } - if((size%framesize) != 0) - alSetError(context, AL_INVALID_VALUE, "Data size %d is not a multiple of frame size %d", - size, framesize); - else - LoadData(context, albuf, freq, size/framesize*align, srcchannels, srctype, data, align, - flags); -done: UnlockBuffersRead(device); ALCcontext_DecRef(context); } @@ -220,47 +228,49 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if((access&~MAP_ACCESS_FLAGS) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid map flags 0x%x", - access&~MAP_ACCESS_FLAGS); - if(!(access&MAP_READ_WRITE_FLAGS)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Mapping buffer without read or write access"); - - WriteLock(&albuf->lock); - if(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, - "Mapping in-use buffer without persistent mapping"); - if(albuf->MappedAccess != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, "Mapping already-mapped buffer"); - if((access&AL_MAP_READ_BIT_SOFT) && !(albuf->Access&AL_MAP_READ_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, - "Mapping buffer for reading without read access"); - if((access&AL_MAP_WRITE_BIT_SOFT) && !(albuf->Access&AL_MAP_WRITE_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, - "Mapping buffer for writing without write access"); - if((access&AL_MAP_PERSISTENT_BIT_SOFT) && !(albuf->Access&AL_MAP_PERSISTENT_BIT_SOFT)) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, - "Mapping buffer persistently without persistent access"); - if(offset < 0 || offset >= albuf->OriginalSize || - length <= 0 || length > albuf->OriginalSize - offset) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Mapping invalid range %d+%d", - offset, length); - - retval = (ALbyte*)albuf->data + offset; - albuf->MappedAccess = access; - albuf->MappedOffset = offset; - albuf->MappedSize = length; - -unlock_done: - WriteUnlock(&albuf->lock); + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) + alSetError(context, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + else if(UNLIKELY(!(access&MAP_READ_WRITE_FLAGS))) + alSetError(context, AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + buffer); + else + { + ALbitfieldSOFT unavailable; + WriteLock(&albuf->lock); + unavailable = (albuf->Access^access) & access; + if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context, AL_INVALID_OPERATION, + "Mapping in-use buffer %u without persistent mapping", buffer); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context, AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); + else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) + alSetError(context, AL_INVALID_VALUE, + "Mapping buffer %u for reading without read access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context, AL_INVALID_VALUE, + "Mapping buffer %u for writing without write access", buffer); + else if(UNLIKELY((unavailable&AL_MAP_PERSISTENT_BIT_SOFT))) + alSetError(context, AL_INVALID_VALUE, + "Mapping buffer %u persistently without persistent access", buffer); + else if(UNLIKELY(offset < 0 || offset >= albuf->OriginalSize || + length <= 0 || length > albuf->OriginalSize - offset)) + alSetError(context, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + offset, length, buffer); + else + { + retval = (ALbyte*)albuf->data + offset; + albuf->MappedAccess = access; + albuf->MappedOffset = offset; + albuf->MappedSize = length; + } -done: + WriteUnlock(&albuf->lock); + } UnlockBuffersRead(device); - ALCcontext_DecRef(context); + ALCcontext_DecRef(context); return retval; } @@ -276,21 +286,22 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - WriteLock(&albuf->lock); - if(albuf->MappedAccess == 0) - alSetError(context, AL_INVALID_OPERATION, "Unmapping an unmapped buffer %u", buffer); + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else { - albuf->MappedAccess = 0; - albuf->MappedOffset = 0; - albuf->MappedSize = 0; + WriteLock(&albuf->lock); + if(albuf->MappedAccess == 0) + alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + else + { + albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; + } + WriteUnlock(&albuf->lock); } - WriteUnlock(&albuf->lock); - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -305,29 +316,32 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - WriteLock(&albuf->lock); - if(albuf->MappedAccess == 0 || !(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT)) - alSetError(context, AL_INVALID_OPERATION, "Flushing buffer %u not mapped for writing", - buffer); - else if(offset < albuf->MappedOffset || offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset) - alSetError(context, AL_INVALID_VALUE, "Flushing an invalid range %d+%d", offset, length); + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else { - /* FIXME: Need to use some method of double-buffering for the mixer and - * app to hold separate memory, which can be safely transfered - * asynchronously. Currently we just say the app shouldn't write where - * OpenAL's reading, and hope for the best... - */ - ATOMIC_THREAD_FENCE(almemory_order_seq_cst); + WriteLock(&albuf->lock); + if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context, AL_INVALID_OPERATION, + "Flushing buffer %u while not mapped for writing", buffer); + else if(UNLIKELY(offset < albuf->MappedOffset || + offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + offset, length, buffer); + else + { + /* FIXME: Need to use some method of double-buffering for the mixer + * and app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write + * where OpenAL's reading, and hope for the best... + */ + ATOMIC_THREAD_FENCE(almemory_order_seq_cst); + } + WriteUnlock(&albuf->lock); } - WriteUnlock(&albuf->lock); - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -338,71 +352,85 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALCdevice *device; ALCcontext *context; ALbuffer *albuf; - ALsizei byte_align; - ALsizei frame_size; - ALsizei num_chans; - ALsizei align; - void *dst; context = GetContextRef(); if(!context) return; device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE) - SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid format 0x%04x", format); - WriteLock(&albuf->lock); - align = SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign)); - if(align < 1) SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid unpack alignment"); - - if((long)srcchannels != (long)albuf->FmtChannels || srctype != albuf->OriginalType) - SETERR_GOTO(context, AL_INVALID_ENUM, unlock_done, - "Unpacking data with mismatched format"); - if(align != albuf->OriginalAlign) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, - "Unpacking data with mismatched alignment"); - if(albuf->MappedAccess != 0) - SETERR_GOTO(context, AL_INVALID_OPERATION, unlock_done, - "Unpacking data into mapped buffer"); - - num_chans = ChannelsFromFmt(albuf->FmtChannels); - frame_size = num_chans * BytesFromFmt(albuf->FmtType); - if(albuf->OriginalType == UserFmtIMA4) - byte_align = ((align-1)/2 + 4) * num_chans; - else if(albuf->OriginalType == UserFmtMSADPCM) - byte_align = ((align-2)/2 + 7) * num_chans; - else - byte_align = align * frame_size; - - if(offset < 0 || length < 0 || offset > albuf->OriginalSize || - length > albuf->OriginalSize-offset) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid data sub-range %d+%d", - offset, length); - if((offset%byte_align) != 0 || (length%byte_align) != 0) - SETERR_GOTO(context, AL_INVALID_VALUE, unlock_done, "Invalid sub-range alignment"); - - /* offset -> byte offset, length -> sample count */ - offset = offset/byte_align * frame_size; - length = length/byte_align * albuf->OriginalAlign; - - dst = (ALbyte*)albuf->data + offset; - if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) - Convert_ALshort_ALima4(dst, data, num_chans, length, align); - else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) - Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align); + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) + alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); else { - assert((long)srctype == (long)albuf->FmtType); - memcpy(dst, data, length*frame_size); - } + ALsizei unpack_align, align; + ALsizei byte_align; + ALsizei frame_size; + ALsizei num_chans; + void *dst; -unlock_done: - WriteUnlock(&albuf->lock); + WriteLock(&albuf->lock); + unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); + align = SanitizeAlignment(srctype, unpack_align); + if(UNLIKELY(align < 1)) + alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment %d", unpack_align); + else if(UNLIKELY((long)srcchannels != (long)albuf->FmtChannels || + srctype != albuf->OriginalType)) + alSetError(context, AL_INVALID_ENUM, "Unpacking data with mismatched format"); + else if(UNLIKELY(align != albuf->OriginalAlign)) + alSetError(context, AL_INVALID_VALUE, + "Unpacking data with alignment %u does not match original alignment %u", + align, albuf->OriginalAlign); + else if(UNLIKELY(albuf->MappedAccess != 0)) + alSetError(context, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + buffer); + else + { + num_chans = ChannelsFromFmt(albuf->FmtChannels); + frame_size = num_chans * BytesFromFmt(albuf->FmtType); + if(albuf->OriginalType == UserFmtIMA4) + byte_align = ((align-1)/2 + 4) * num_chans; + else if(albuf->OriginalType == UserFmtMSADPCM) + byte_align = ((align-2)/2 + 7) * num_chans; + else + byte_align = align * frame_size; + + if(UNLIKELY(offset < 0 || length < 0 || offset > albuf->OriginalSize || + length > albuf->OriginalSize-offset)) + alSetError(context, AL_INVALID_VALUE, "Invalid data sub-range %d+%d on buffer %u", + offset, length, buffer); + else if(UNLIKELY((offset%byte_align) != 0)) + alSetError(context, AL_INVALID_VALUE, + "Sub-range offset %d is not a multiple of frame size %d (%d unpack alignment)", + offset, byte_align, align); + else if(UNLIKELY((length%byte_align) != 0)) + alSetError(context, AL_INVALID_VALUE, + "Sub-range length %d is not a multiple of frame size %d (%d unpack alignment)", + length, byte_align, align); + else + { + /* offset -> byte offset, length -> sample count */ + offset = offset/byte_align * align * frame_size; + length = length/byte_align * align; + + dst = (ALbyte*)albuf->data + offset; + if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) + Convert_ALshort_ALima4(dst, data, num_chans, length, align); + else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) + Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align); + else + { + assert((long)srctype == (long)albuf->FmtType); + memcpy(dst, data, length*frame_size); + } + } + } -done: + WriteUnlock(&albuf->lock); + } UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -473,17 +501,15 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -498,17 +524,15 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -523,18 +547,17 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -550,31 +573,29 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - switch(param) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) { case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - if(!(value >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Buffer unpack block alignment %d is invalid", value); - ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); + if(UNLIKELY(value < 0)) + alSetError(context, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + else + ATOMIC_STORE_SEQ(&albuf->UnpackAlign, value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - if(!(value >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, - "Buffer pack block alignment %d is invalid", value); - ATOMIC_STORE_SEQ(&albuf->PackAlign, value); + if(UNLIKELY(value < 0)) + alSetError(context, AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + else + ATOMIC_STORE_SEQ(&albuf->PackAlign, value); break; default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -588,16 +609,16 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val if(!context) return; device = context->Device; - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - switch(param) + LockBuffersRead(device); + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } + UnlockBuffersRead(device); -done: ALCcontext_DecRef(context); } @@ -624,30 +645,25 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { case AL_LOOP_POINTS_SOFT: WriteLock(&albuf->lock); - if(ReadRef(&albuf->ref) != 0) + if(UNLIKELY(ReadRef(&albuf->ref) != 0)) + alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", + buffer); + else if(UNLIKELY(values[0] >= values[1] || values[0] < 0 || values[1] > albuf->SampleLen)) + alSetError(context, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", + values[0], values[1], buffer); + else { - WriteUnlock(&albuf->lock); - SETERR_GOTO(context, AL_INVALID_OPERATION, done, - "Modifying in-use buffer loop points"); + albuf->LoopStart = values[0]; + albuf->LoopEnd = values[1]; } - if(values[0] >= values[1] || values[0] < 0 || - values[1] > albuf->SampleLen) - { - WriteUnlock(&albuf->lock); - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid loop point range %d -> %d", - values[0], values[1]); - } - - albuf->LoopStart = values[0]; - albuf->LoopEnd = values[1]; WriteUnlock(&albuf->lock); break; @@ -655,9 +671,8 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -673,18 +688,17 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -699,19 +713,17 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!value1 || !value2 || !value3) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -733,18 +745,17 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -760,11 +771,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!value) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { case AL_FREQUENCY: *value = albuf->Frequency; @@ -796,9 +807,8 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -813,19 +823,17 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 device = context->Device; LockBuffersRead(device); - if(LookupBuffer(device, buffer) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!value1 || !value2 || !value3) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!value1 || !value2 || !value3)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -856,11 +864,11 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values device = context->Device; LockBuffersRead(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid buffer ID %u", buffer); - - if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); - switch(param) + if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) + alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!values)) + alSetError(context, AL_INVALID_VALUE, "NULL pointer"); + else switch(param) { case AL_LOOP_POINTS_SOFT: ReadLock(&albuf->lock); @@ -873,9 +881,8 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } - -done: UnlockBuffersRead(device); + ALCcontext_DecRef(context); } @@ -963,7 +970,7 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei * usage, and reporting the real size could cause problems for apps that * use AL_SIZE to try to get the buffer's play length. */ - if(newsize <= INT_MAX-15) + if(LIKELY(newsize <= INT_MAX-15)) newsize = (newsize+15) & ~0xf; if(newsize != ALBuf->BytesAlloc) { -- cgit v1.2.3 From e1e1c73ae6bf89a7a6b4d27c083b68fd60647e4f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jan 2018 13:34:59 -0800 Subject: Read the buffer unpack alignment under the buffer lock --- OpenAL32/alBuffer.c | 145 +++++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 474773b7..69dc9bc2 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -45,9 +45,10 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); -static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei frames, +static const ALchar *NameFromUserFmtType(enum UserFmtType type); +static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, - const ALvoid *data, ALsizei align, ALbitfieldSOFT access); + const ALvoid *data, ALbitfieldSOFT access); static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); @@ -158,8 +159,6 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALCdevice *device; ALCcontext *context; ALbuffer *albuf; - ALsizei framesize = 1; - ALsizei align; context = GetContextRef(); if(!context) return; @@ -180,36 +179,11 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const "Declaring persistently mapped storage without read or write access"); else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); - else if(UNLIKELY((align=SanitizeAlignment(srctype, ATOMIC_LOAD_SEQ(&albuf->UnpackAlign))) < 1)) - alSetError(context, AL_INVALID_VALUE, "Invalid unpack alignment"); else { - switch(srctype) - { - case UserFmtUByte: - case UserFmtShort: - case UserFmtFloat: - case UserFmtDouble: - case UserFmtMulaw: - case UserFmtAlaw: - framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align; - break; - - case UserFmtIMA4: - framesize = ((align-1)/2 + 4) * ChannelsFromUserFmt(srcchannels); - break; - - case UserFmtMSADPCM: - framesize = ((align-2)/2 + 7) * ChannelsFromUserFmt(srcchannels); - break; - } - if((size%framesize) != 0) - alSetError(context, AL_INVALID_VALUE, - "Data size %d is not a multiple of frame size %d (%d unpack alignment)", - size, framesize, align); - else - LoadData(context, albuf, freq, size/framesize*align, srcchannels, srctype, data, align, - flags); + WriteLock(&albuf->lock); + LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags); + WriteUnlock(&albuf->lock); } UnlockBuffersRead(device); @@ -887,19 +861,43 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values } +static const ALchar *NameFromUserFmtType(enum UserFmtType type) +{ + switch(type) + { + case UserFmtUByte: return "Unsigned Byte"; + case UserFmtShort: return "Signed Short"; + case UserFmtFloat: return "Float32"; + case UserFmtDouble: return "Float64"; + case UserFmtMulaw: return "muLaw"; + case UserFmtAlaw: return "aLaw"; + case UserFmtIMA4: return "IMA4 ADPCM"; + case UserFmtMSADPCM: return "MSADPCM"; + } + return ""; +} + /* * LoadData * * Loads the specified data into the buffer, using the specified format. */ -static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALbitfieldSOFT access) +static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALbitfieldSOFT access) { enum FmtChannels DstChannels = FmtMono; enum FmtType DstType = FmtUByte; ALsizei NumChannels, FrameSize; + ALsizei SrcByteAlign; + ALsizei unpackalign; ALsizei newsize; + ALsizei frames; + ALsizei align; + + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); - /* Currently no channels need to be converted. */ + /* Currently no channel configurations need to be converted. */ switch(SrcChannels) { case UserFmtMono: DstChannels = FmtMono; break; @@ -928,42 +926,60 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei case UserFmtMSADPCM: DstType = FmtShort; break; } + /* TODO: Currently we can only map/preserve samples when they're not + * converted. To allow it would need some kind of double-buffering to hold + * onto a copy of the original data. + */ if(access != 0) { if(UNLIKELY((long)SrcType != (long)DstType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "Format cannot be mapped or preserved"); + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped or preserved", + NameFromUserFmtType(SrcType)); } - NumChannels = ChannelsFromFmt(DstChannels); - FrameSize = NumChannels * BytesFromFmt(DstType); - - if(UNLIKELY(frames > INT_MAX/FrameSize)) - SETERR_RETURN(context, AL_OUT_OF_MEMORY,, - "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); - newsize = frames*FrameSize; - - WriteLock(&ALBuf->lock); - if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) - { - WriteUnlock(&ALBuf->lock); - SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer"); - } + unpackalign = ATOMIC_LOAD_SEQ(&ALBuf->UnpackAlign); + if(UNLIKELY((align=SanitizeAlignment(SrcType, unpackalign)) < 1)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid unpack alignment %d for %s samples", + unpackalign, NameFromUserFmtType(SrcType)); if((access&AL_PRESERVE_DATA_BIT_SOFT)) { /* Can only preserve data with the same format and alignment. */ if(UNLIKELY(ALBuf->FmtChannels != DstChannels || ALBuf->OriginalType != SrcType)) - { - WriteUnlock(&ALBuf->lock); SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched format"); - } if(UNLIKELY(ALBuf->OriginalAlign != align)) - { - WriteUnlock(&ALBuf->lock); SETERR_RETURN(context, AL_INVALID_VALUE,, "Preserving data of mismatched alignment"); - } } + /* Convert the input/source size in bytes to sample frames using the unpack + * block alignment. + */ + if(SrcType == UserFmtIMA4) + SrcByteAlign = ((align-1)/2 + 4) * ChannelsFromUserFmt(SrcChannels); + else if(SrcType == UserFmtMSADPCM) + SrcByteAlign = ((align-2)/2 + 7) * ChannelsFromUserFmt(SrcChannels); + else + SrcByteAlign = align * FrameSizeFromUserFmt(SrcChannels, SrcType); + if(UNLIKELY((size%SrcByteAlign) != 0)) + SETERR_RETURN(context, AL_INVALID_VALUE,, + "Data size %d is not a multiple of frame size %d (%d unpack alignment)", + size, SrcByteAlign, align); + + if(UNLIKELY(size / SrcByteAlign > INT_MAX / align)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d blocks x %d samples per block", size/SrcByteAlign, align); + frames = size / SrcByteAlign * align; + + /* Convert the sample frames to the number of bytes needed for internal + * storage. + */ + NumChannels = ChannelsFromFmt(DstChannels); + FrameSize = NumChannels * BytesFromFmt(DstType); + if(UNLIKELY(frames > INT_MAX/FrameSize)) + SETERR_RETURN(context, AL_OUT_OF_MEMORY,, + "Buffer size overflow, %d frames x %d bytes per frame", frames, FrameSize); + newsize = frames*FrameSize; + /* Round up to the next 16-byte multiple. This could reallocate only when * increasing or the new size is less than half the current, but then the * buffer's AL_SIZE would not be very reliable for accounting buffer memory @@ -976,11 +992,8 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei { void *temp = al_malloc(16, (size_t)newsize); if(UNLIKELY(!temp && newsize)) - { - WriteUnlock(&ALBuf->lock); SETERR_RETURN(context, AL_OUT_OF_MEMORY,, "Failed to allocate %d bytes of storage", newsize); - } if((access&AL_PRESERVE_DATA_BIT_SOFT)) { ALsizei tocopy = mini(newsize, ALBuf->BytesAlloc); @@ -991,33 +1004,29 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei ALBuf->BytesAlloc = newsize; } - ALBuf->OriginalType = SrcType; if(SrcType == UserFmtIMA4) { - ALsizei byte_align = ((align-1)/2 + 4) * NumChannels; - ALBuf->OriginalSize = frames / align * byte_align; - ALBuf->OriginalAlign = align; assert(DstType == FmtShort); if(data != NULL && ALBuf->data != NULL) Convert_ALshort_ALima4(ALBuf->data, data, NumChannels, frames, align); + ALBuf->OriginalAlign = align; } else if(SrcType == UserFmtMSADPCM) { - ALsizei byte_align = ((align-2)/2 + 7) * NumChannels; - ALBuf->OriginalSize = frames / align * byte_align; - ALBuf->OriginalAlign = align; assert(DstType == FmtShort); if(data != NULL && ALBuf->data != NULL) Convert_ALshort_ALmsadpcm(ALBuf->data, data, NumChannels, frames, align); + ALBuf->OriginalAlign = align; } else { - ALBuf->OriginalSize = frames * FrameSize; - ALBuf->OriginalAlign = 1; assert((long)SrcType == (long)DstType); if(data != NULL && ALBuf->data != NULL) memcpy(ALBuf->data, data, frames*FrameSize); + ALBuf->OriginalAlign = 1; } + ALBuf->OriginalSize = size; + ALBuf->OriginalType = SrcType; ALBuf->Frequency = freq; ALBuf->FmtChannels = DstChannels; @@ -1027,8 +1036,6 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei ALBuf->SampleLen = frames; ALBuf->LoopStart = 0; ALBuf->LoopEnd = ALBuf->SampleLen; - - WriteUnlock(&ALBuf->lock); } -- cgit v1.2.3 From 3ba4746ff852c3ac6dcfb047fa51b75c1d58e5c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jan 2018 16:41:14 -0800 Subject: Allow preserving converted samples --- OpenAL32/alBuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 69dc9bc2..f692ca11 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -926,14 +926,14 @@ static void LoadData(ALCcontext *context, ALbuffer *ALBuf, ALuint freq, ALsizei case UserFmtMSADPCM: DstType = FmtShort; break; } - /* TODO: Currently we can only map/preserve samples when they're not - * converted. To allow it would need some kind of double-buffering to hold - * onto a copy of the original data. + /* TODO: Currently we can only map samples when they're not converted. To + * allow it would need some kind of double-buffering to hold onto a copy of + * the original data. */ - if(access != 0) + if((access&MAP_READ_WRITE_FLAGS)) { if(UNLIKELY((long)SrcType != (long)DstType)) - SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped or preserved", + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", NameFromUserFmtType(SrcType)); } -- cgit v1.2.3 From a885fd6d0e28c982e4beb423e31d56be9e6b61dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jan 2018 21:11:12 -0800 Subject: Make some functions static that are only used in one source --- OpenAL32/Include/alBuffer.h | 12 +++--------- OpenAL32/alBuffer.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index b6d77436..50946126 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -109,15 +109,9 @@ inline void LockBuffersRead(ALCdevice *device) { LockUIntMapRead(&device->BufferMap); } inline void UnlockBuffersRead(ALCdevice *device) { UnlockUIntMapRead(&device->BufferMap); } -inline void LockBuffersWrite(ALCdevice *device) -{ LockUIntMapWrite(&device->BufferMap); } -inline void UnlockBuffersWrite(ALCdevice *device) -{ UnlockUIntMapWrite(&device->BufferMap); } - -inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } -inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id) -{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); } + +inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ return (ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } ALvoid ReleaseALBuffers(ALCdevice *device); diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index f692ca11..985fa6eb 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -38,10 +38,7 @@ extern inline void LockBuffersRead(ALCdevice *device); extern inline void UnlockBuffersRead(ALCdevice *device); -extern inline void LockBuffersWrite(ALCdevice *device); -extern inline void UnlockBuffersWrite(ALCdevice *device); -extern inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id); -extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id); +extern inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); @@ -52,6 +49,14 @@ static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); +static inline void LockBuffersWrite(ALCdevice *device) +{ LockUIntMapWrite(&device->BufferMap); } +static inline void UnlockBuffersWrite(ALCdevice *device) +{ UnlockUIntMapWrite(&device->BufferMap); } + +static inline ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id) +{ return (ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); } + #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) #define MAP_READ_WRITE_FLAGS (AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT) -- cgit v1.2.3 From 5d2196c119f376ca6e58e23b43d4ffbaf4c68c12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 26 Jan 2018 21:32:43 -0800 Subject: Don't rely on alMain.h in alBuffer.h --- Alc/inprogext.h | 78 +++++++++++++++++++++++++++++++++++++++++++++ OpenAL32/Include/alBuffer.h | 16 ++++------ OpenAL32/Include/alMain.h | 73 +++++++----------------------------------- 3 files changed, 96 insertions(+), 71 deletions(-) create mode 100644 Alc/inprogext.h diff --git a/Alc/inprogext.h b/Alc/inprogext.h new file mode 100644 index 00000000..721f2370 --- /dev/null +++ b/Alc/inprogext.h @@ -0,0 +1,78 @@ +#ifndef INPROGEXT_H +#define INPROGEXT_H + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ALC_SOFT_loopback2 +#define ALC_SOFT_loopback2 1 +#define ALC_AMBISONIC_LAYOUT_SOFT 0xfff0 +#define ALC_AMBISONIC_SCALING_SOFT 0xfff1 +#define ALC_AMBISONIC_ORDER_SOFT 0xfff2 +#define ALC_MAX_AMBISONIC_ORDER_SOFT 0xfff3 + +#define ALC_BFORMAT3D_SOFT 0x1508 + +/* Ambisonic layouts */ +#define ALC_ACN_SOFT 0xfff4 +#define ALC_FUMA_SOFT 0xfff5 + +/* Ambisonic scalings (normalization) */ +/*#define ALC_FUMA_SOFT*/ +#define ALC_SN3D_SOFT 0xfff6 +#define ALC_N3D_SOFT 0xfff7 +#endif + +#ifndef AL_SOFT_map_buffer +#define AL_SOFT_map_buffer 1 +typedef unsigned int ALbitfieldSOFT; +#define AL_MAP_READ_BIT_SOFT 0x00000001 +#define AL_MAP_WRITE_BIT_SOFT 0x00000002 +#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 +#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 +typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); +typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); +typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); +AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); +AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); +AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_events +#define AL_SOFT_events 1 +#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 +#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 +#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 +#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 +#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 +#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 +#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 +typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, + ALsizei length, const ALchar *message, + void *userParam); +typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); +typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); +typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); +typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); +AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); +AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); +AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); +#endif +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* INPROGEXT_H */ diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 50946126..775bf391 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -1,7 +1,13 @@ #ifndef _AL_BUFFER_H_ #define _AL_BUFFER_H_ -#include "alMain.h" +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" + +#include "inprogext.h" +#include "atomic.h" +#include "rwlock.h" #ifdef __cplusplus extern "C" { @@ -105,14 +111,6 @@ typedef struct ALbuffer { ALbuffer *NewBuffer(ALCcontext *context); void DeleteBuffer(ALCdevice *device, ALbuffer *buffer); -inline void LockBuffersRead(ALCdevice *device) -{ LockUIntMapRead(&device->BufferMap); } -inline void UnlockBuffersRead(ALCdevice *device) -{ UnlockUIntMapRead(&device->BufferMap); } - -inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ return (ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } - ALvoid ReleaseALBuffers(ALCdevice *device); #ifdef __cplusplus diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 18dc32dd..bf7d2559 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -17,6 +17,7 @@ #include "AL/alc.h" #include "AL/alext.h" +#include "inprogext.h" #include "logging.h" #include "polymorphism.h" #include "static_assert.h" @@ -28,68 +29,6 @@ #include "almalloc.h" #include "threads.h" -#ifndef ALC_SOFT_loopback2 -#define ALC_SOFT_loopback2 1 -#define ALC_AMBISONIC_LAYOUT_SOFT 0xfff0 -#define ALC_AMBISONIC_SCALING_SOFT 0xfff1 -#define ALC_AMBISONIC_ORDER_SOFT 0xfff2 -#define ALC_MAX_AMBISONIC_ORDER_SOFT 0xfff3 - -#define ALC_BFORMAT3D_SOFT 0x1508 - -/* Ambisonic layouts */ -#define ALC_ACN_SOFT 0xfff4 -#define ALC_FUMA_SOFT 0xfff5 - -/* Ambisonic scalings (normalization) */ -/*#define ALC_FUMA_SOFT*/ -#define ALC_SN3D_SOFT 0xfff6 -#define ALC_N3D_SOFT 0xfff7 -#endif - -#ifndef AL_SOFT_map_buffer -#define AL_SOFT_map_buffer 1 -typedef unsigned int ALbitfieldSOFT; -#define AL_MAP_READ_BIT_SOFT 0x00000001 -#define AL_MAP_WRITE_BIT_SOFT 0x00000002 -#define AL_MAP_PERSISTENT_BIT_SOFT 0x00000004 -#define AL_PRESERVE_DATA_BIT_SOFT 0x00000008 -typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); -typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer); -typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags); -AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access); -AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer); -AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length); -#endif -#endif - -#ifndef AL_SOFT_events -#define AL_SOFT_events 1 -#define AL_EVENT_CALLBACK_FUNCTION_SOFT 0x1220 -#define AL_EVENT_CALLBACK_USER_PARAM_SOFT 0x1221 -#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT 0x1222 -#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT 0x1223 -#define AL_EVENT_TYPE_ERROR_SOFT 0x1224 -#define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 -#define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 -typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, - ALsizei length, const ALchar *message, - void *userParam); -typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable); -typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam); -typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); -typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable); -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam); -AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname); -AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); -#endif -#endif - #if defined(_WIN64) #define SZFMT "%I64u" @@ -163,6 +102,7 @@ struct DirectHrtfState; struct FrontStablizer; struct Compressor; struct ALCbackend; +struct ALbuffer; struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; @@ -680,6 +620,15 @@ inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) { return GetChannelIndex(real->ChannelName, chan); } +inline void LockBuffersRead(ALCdevice *device) +{ LockUIntMapRead(&device->BufferMap); } +inline void UnlockBuffersRead(ALCdevice *device) +{ UnlockUIntMapRead(&device->BufferMap); } + +inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } + + vector_al_string SearchDataFiles(const char *match, const char *subdir); #ifdef __cplusplus -- cgit v1.2.3 From 9613b4bfe24cbefba0f4c9c738ebd30d4b116970 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 01:51:01 -0800 Subject: Use a different method for storing and looking up buffers Rather than each buffer being individually allocated with a generated 'thunk' ID that's used with a uint:ptr map, buffers are allocated in arrays of 64 within a vector. Each group of 64 has an associated 64-bit mask indicating which are free to use, and the buffer ID is comprised of the two array indices which directly locate the buffer (no searching, binary or otherwise). Currently no buffers are actually deallocated after being allocated, though they are reused. So an app that creates a ton of buffers once, then deletes them all and uses only a couple from then on, will have a bit of waste, while an app that's more consistent with the number of used buffers won't be a problem. This can be improved by removing elements of the containing vector that contain all-free buffers while there are plenty of other free buffers. Also, this method can easily be applied to other resources, like sources. --- Alc/ALc.c | 22 ++--- OpenAL32/Include/alBuffer.h | 3 - OpenAL32/Include/alMain.h | 69 +++++++++++++-- OpenAL32/alBuffer.c | 211 +++++++++++++++++++++++++++----------------- OpenAL32/alSource.c | 31 +++++-- 5 files changed, 226 insertions(+), 110 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 255265b5..aea49070 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2376,13 +2376,12 @@ static ALCvoid FreeDevice(ALCdevice *device) almtx_destroy(&device->BackendLock); - if(device->BufferMap.size > 0) - { - WARN("(%p) Deleting %d Buffer%s\n", device, device->BufferMap.size, - (device->BufferMap.size==1)?"":"s"); - ReleaseALBuffers(device); - } - ResetUIntMap(&device->BufferMap); + ReleaseALBuffers(device); +#define FREE_BUFFERSUBLIST(x) al_free((x)->Buffers) + VECTOR_FOR_EACH(BufferSubList, device->BufferList, FREE_BUFFERSUBLIST); +#undef FREE_BUFFERSUBLIST + VECTOR_DEINIT(device->BufferList); + almtx_destroy(&device->BufferLock); if(device->EffectMap.size > 0) { @@ -3988,7 +3987,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - InitUIntMap(&device->BufferMap, INT_MAX); + VECTOR_INIT(device->BufferList); InitUIntMap(&device->EffectMap, INT_MAX); InitUIntMap(&device->FilterMap, INT_MAX); @@ -4120,6 +4119,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) return NULL; } almtx_init(&device->BackendLock, almtx_plain); + almtx_init(&device->BufferLock, almtx_plain); if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { @@ -4265,7 +4265,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->RealOut.Buffer = NULL; device->RealOut.NumChannels = 0; - InitUIntMap(&device->BufferMap, INT_MAX); + VECTOR_INIT(device->BufferList); InitUIntMap(&device->EffectMap, INT_MAX); InitUIntMap(&device->FilterMap, INT_MAX); @@ -4314,6 +4314,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return NULL; } almtx_init(&device->BackendLock, almtx_plain); + almtx_init(&device->BufferLock, almtx_plain); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); @@ -4488,7 +4489,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - InitUIntMap(&device->BufferMap, INT_MAX); + VECTOR_INIT(device->BufferList); InitUIntMap(&device->EffectMap, INT_MAX); InitUIntMap(&device->FilterMap, INT_MAX); @@ -4508,6 +4509,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN return NULL; } almtx_init(&device->BackendLock, almtx_plain); + almtx_init(&device->BufferLock, almtx_plain); //Set output format device->NumUpdates = 0; diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 775bf391..8eedddbc 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -108,9 +108,6 @@ typedef struct ALbuffer { ALuint id; } ALbuffer; -ALbuffer *NewBuffer(ALCcontext *context); -void DeleteBuffer(ALCdevice *device, ALbuffer *buffer); - ALvoid ReleaseALBuffers(ALCdevice *device); #ifdef __cplusplus diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bf7d2559..f3ffac29 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -12,6 +12,9 @@ #ifdef HAVE_STRINGS_H #include #endif +#ifdef HAVE_INTRIN_H +#include +#endif #include "AL/al.h" #include "AL/alc.h" @@ -83,6 +86,51 @@ typedef ALuint64SOFT ALuint64; #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) +/* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result + * is *UNDEFINED* if the value is 0. + */ +#ifdef __GNUC__ + +#if SIZEOF_LONG == 8 +#define CTZ64(x) __builtin_ctzl(x) +#else +#define CTZ64(x) __builtin_ctzll(x) +#endif + +#elif defined(_MSC_VER) + +static inline int msvc_ctz64(ALuint64 v) +{ + unsigned long idx = 0; + _BitScanForward64(&idx, v); + return idx; +} +#define CTZ64(x) msvc_ctz64(x) + +#else + +/* There be black magics here. The popcnt64 method is derived from + * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + * while the ctz-utilizing-popcnt algorithm is shown here + * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt + * as the ntz2 variant. These likely aren't the most efficient methods, but + * they're good enough if the GCC or MSVC intrinsics aren't available. + */ +static inline int fallback_popcnt64(ALuint64 v) +{ + v = v - ((v >> 1) & U64(0x5555555555555555)); + v = (v & U64(0x3333333333333333)) + ((v >> 2) & U64(0x3333333333333333)); + v = (v + (v >> 4)) & U64(0x0f0f0f0f0f0f0f0f); + return (v * U64(0x0101010101010101)) >> 56; +} + +static inline int fallback_ctz64(ALuint64 value) +{ + return fallback_popcnt64(~value & (value - 1)); +} +#define CTZ64(x) fallback_ctz64(x) +#endif + static const union { ALuint u; ALubyte b[sizeof(ALuint)]; @@ -312,6 +360,13 @@ typedef union AmbiConfig { } AmbiConfig; +typedef struct BufferSubList { + ALuint64 FreeMask; + struct ALbuffer *Buffers; /* 64 */ +} BufferSubList; +TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList) + + typedef struct EnumeratedHrtf { al_string name; @@ -399,7 +454,8 @@ struct ALCdevice_struct ALsizei NumAuxSends; // Map of Buffers for this device - UIntMap BufferMap; + vector_BufferSubList BufferList; + almtx_t BufferLock; // Map of Effects for this device UIntMap EffectMap; @@ -620,13 +676,10 @@ inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) { return GetChannelIndex(real->ChannelName, chan); } -inline void LockBuffersRead(ALCdevice *device) -{ LockUIntMapRead(&device->BufferMap); } -inline void UnlockBuffersRead(ALCdevice *device) -{ UnlockUIntMapRead(&device->BufferMap); } - -inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) -{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); } +inline void LockBufferList(ALCdevice *device) +{ almtx_lock(&device->BufferLock); } +inline void UnlockBufferList(ALCdevice *device) +{ almtx_unlock(&device->BufferLock); } vector_al_string SearchDataFiles(const char *match, const char *subdir); diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 985fa6eb..1464ef74 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -36,12 +36,13 @@ #include "sample_cvt.h" -extern inline void LockBuffersRead(ALCdevice *device); -extern inline void UnlockBuffersRead(ALCdevice *device); -extern inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id); +extern inline void LockBufferList(ALCdevice *device); +extern inline void UnlockBufferList(ALCdevice *device); extern inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type); extern inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type); +static ALbuffer *AllocBuffer(ALCcontext *context); +static void FreeBuffer(ALCdevice *device, ALbuffer *buffer); static const ALchar *NameFromUserFmtType(enum UserFmtType type); static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, @@ -49,13 +50,19 @@ static void LoadData(ALCcontext *context, ALbuffer *buffer, ALuint freq, ALsizei static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align); -static inline void LockBuffersWrite(ALCdevice *device) -{ LockUIntMapWrite(&device->BufferMap); } -static inline void UnlockBuffersWrite(ALCdevice *device) -{ UnlockUIntMapWrite(&device->BufferMap); } - -static inline ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id) -{ return (ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); } +static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + BufferSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) + return NULL; + sublist = &VECTOR_ELEM(device->BufferList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; +} #define INVALID_STORAGE_MASK ~(AL_MAP_READ_BIT_SOFT | AL_MAP_WRITE_BIT_SOFT | AL_PRESERVE_DATA_BIT_SOFT | AL_MAP_PERSISTENT_BIT_SOFT) @@ -75,7 +82,7 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n); else for(cur = 0;cur < n;cur++) { - ALbuffer *buffer = NewBuffer(context); + ALbuffer *buffer = AllocBuffer(context); if(!buffer) { alDeleteBuffers(cur, buffers); @@ -100,7 +107,7 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) device = context->Device; - LockBuffersWrite(device); + LockBufferList(device); if(UNLIKELY(n < 0)) { alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n); @@ -127,11 +134,11 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) for(i = 0;i < n;i++) { if((ALBuf=LookupBuffer(device, buffers[i])) != NULL) - DeleteBuffer(device, ALBuf); + FreeBuffer(device, ALBuf); } done: - UnlockBuffersWrite(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -143,10 +150,10 @@ AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) context = GetContextRef(); if(!context) return AL_FALSE; - LockBuffersRead(context->Device); + LockBufferList(context->Device); ret = ((!buffer || LookupBuffer(context->Device, buffer)) ? AL_TRUE : AL_FALSE); - UnlockBuffersRead(context->Device); + UnlockBufferList(context->Device); ALCcontext_DecRef(context); @@ -169,7 +176,7 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(size < 0)) @@ -191,7 +198,7 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const WriteUnlock(&albuf->lock); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -206,7 +213,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei if(!context) return retval; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY((access&INVALID_MAP_FLAGS) != 0)) @@ -247,7 +254,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei WriteUnlock(&albuf->lock); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); return retval; @@ -263,7 +270,7 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if((albuf=LookupBuffer(device, buffer)) == NULL) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else @@ -279,7 +286,7 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) } WriteUnlock(&albuf->lock); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -294,7 +301,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else @@ -319,7 +326,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A } WriteUnlock(&albuf->lock); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -336,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) @@ -408,7 +415,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons WriteUnlock(&albuf->lock); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -479,7 +486,7 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) @@ -487,7 +494,7 @@ AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat UNUSED(va default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -502,7 +509,7 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) @@ -510,7 +517,7 @@ AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat UNUSED(v default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -525,7 +532,7 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) @@ -535,7 +542,7 @@ AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *v default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -551,7 +558,7 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) @@ -573,7 +580,7 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -588,7 +595,7 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) @@ -596,7 +603,7 @@ AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint UNUSED(val default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -623,7 +630,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) @@ -650,7 +657,7 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -666,7 +673,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) @@ -676,7 +683,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *val default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -691,7 +698,7 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value1 || !value2 || !value3)) @@ -701,7 +708,7 @@ AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *valu default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -723,7 +730,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) @@ -733,7 +740,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -749,7 +756,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value)) @@ -786,7 +793,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -801,7 +808,7 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!value1 || !value2 || !value3)) @@ -811,7 +818,7 @@ AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1 default: alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -842,7 +849,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values if(!context) return; device = context->Device; - LockBuffersRead(device); + LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!values)) @@ -860,7 +867,7 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", param); } - UnlockBuffersRead(device); + UnlockBufferList(device); ALCcontext_DecRef(context); } @@ -1221,43 +1228,76 @@ static ALsizei SanitizeAlignment(enum UserFmtType type, ALsizei align) } -ALbuffer *NewBuffer(ALCcontext *context) +static ALbuffer *AllocBuffer(ALCcontext *context) { ALCdevice *device = context->Device; - ALbuffer *buffer; - ALenum err; + BufferSubList *sublist, *subend; + ALbuffer *buffer = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&device->BufferLock); + sublist = VECTOR_BEGIN(device->BufferList); + subend = VECTOR_END(device->BufferList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + buffer = sublist->Buffers + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!buffer)) + { + const BufferSubList empty_sublist = { 0, NULL }; + lidx = VECTOR_SIZE(device->BufferList); + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(lidx >= 1<<25)) + { + almtx_unlock(&device->BufferLock); + return NULL; + } + VECTOR_PUSH_BACK(device->BufferList, empty_sublist); + sublist = &VECTOR_BACK(device->BufferList); + sublist->FreeMask = ~U64(0); + sublist->Buffers = al_calloc(16, sizeof(ALbuffer)*64); + if(UNLIKELY(!sublist->Buffers)) + { + VECTOR_POP_BACK(device->BufferList); + almtx_unlock(&device->BufferLock); + return NULL; + } + + slidx = 0; + buffer = sublist->Buffers + slidx; + } - buffer = al_calloc(16, sizeof(ALbuffer)); - if(!buffer) - SETERR_RETURN(context, AL_OUT_OF_MEMORY, NULL, "Failed to allocate buffer object"); + memset(buffer, 0, sizeof(*buffer)); RWLockInit(&buffer->lock); - buffer->Access = 0; - buffer->MappedAccess = 0; - 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)); - al_free(buffer); + /* Add 1 to avoid buffer ID 0. */ + buffer->id = ((lidx<<6) | slidx) + 1; - SETERR_RETURN(context, err, NULL, "Failed to set buffer ID"); - } + sublist->FreeMask &= ~(U64(1)<BufferLock); return buffer; } -void DeleteBuffer(ALCdevice *device, ALbuffer *buffer) +static void FreeBuffer(ALCdevice *device, ALbuffer *buffer) { - RemoveBuffer(device, buffer->id); - FreeThunkEntry(buffer->id); + ALuint id = buffer->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; al_free(buffer->data); - memset(buffer, 0, sizeof(*buffer)); - al_free(buffer); + + VECTOR_ELEM(device->BufferList, lidx).FreeMask |= U64(1) << slidx; } @@ -1268,16 +1308,25 @@ void DeleteBuffer(ALCdevice *device, ALbuffer *buffer) */ ALvoid ReleaseALBuffers(ALCdevice *device) { - ALsizei i; - for(i = 0;i < device->BufferMap.size;i++) + BufferSubList *sublist = VECTOR_BEGIN(device->BufferList); + BufferSubList *subend = VECTOR_END(device->BufferList); + size_t leftover = 0; + for(;sublist != subend;++sublist) { - ALbuffer *temp = device->BufferMap.values[i]; - device->BufferMap.values[i] = NULL; + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALbuffer *buffer = sublist->Buffers + idx; - al_free(temp->data); + al_free(buffer->data); + memset(buffer, 0, sizeof(*buffer)); + ++leftover; - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(ALbuffer)); - al_free(temp); + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; } + if(leftover > 0) + WARN("(%p) Deleted "SZFMT" Buffer%s\n", device, leftover, (leftover==1)?"":"s"); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 898e54d6..17d57852 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -56,6 +56,21 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); +static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) +{ + BufferSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->BufferList))) + return NULL; + sublist = &VECTOR_ELEM(device->BufferList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Buffers + slidx; +} + + typedef enum SourceProp { srcPitch = AL_PITCH, srcGain = AL_GAIN, @@ -757,10 +772,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_BUFFER: - LockBuffersRead(device); + LockBufferList(device); if(!(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL)) { - UnlockBuffersRead(device); + UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid buffer ID %u", *values); } @@ -770,7 +785,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { WriteUnlock(&Source->queue_lock); - UnlockBuffersRead(device); + UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting non-persistently mapped buffer %u", buffer->id); } @@ -780,7 +795,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if(state == AL_PLAYING || state == AL_PAUSED) { WriteUnlock(&Source->queue_lock); - UnlockBuffersRead(device); + UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting buffer on playing or paused source %u", Source->id); } @@ -808,7 +823,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->queue = NULL; } WriteUnlock(&Source->queue_lock); - UnlockBuffersRead(device); + UnlockBufferList(device); /* Delete all elements in the previous queue */ while(oldlist != NULL) @@ -2879,7 +2894,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } - LockBuffersRead(device); + LockBufferList(device); BufferListStart = NULL; BufferList = NULL; for(i = 0;i < nb;i++) @@ -2950,7 +2965,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu al_free(BufferListStart); BufferListStart = next; } - UnlockBuffersRead(device); + UnlockBufferList(device); goto done; } } @@ -2965,7 +2980,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu } BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } - UnlockBuffersRead(device); + UnlockBufferList(device); /* Source is now streaming */ source->SourceType = AL_STREAMING; -- cgit v1.2.3 From 9718502e5db46952693d550c54ec35b0a44128d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 11:11:39 -0800 Subject: Check for _BitScanForward64 before using it --- CMakeLists.txt | 7 +++++++ OpenAL32/Include/alMain.h | 8 ++++---- config.h.in | 3 +++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 29c0a3b7..8e3ee808 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,6 +487,13 @@ IF(HAVE_INTRIN_H) __cpuid(regs, 0); return regs[0]; }" HAVE_CPUID_INTRINSIC) + CHECK_C_SOURCE_COMPILES("#include + int main() + { + unsigned long idx = 0; + _BitScanForward64(&idx, 1); + return idx; + }" HAVE_BITSCANFORWARD64_INTRINSIC) ENDIF() CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f3ffac29..afa3eee3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -97,13 +97,13 @@ typedef ALuint64SOFT ALuint64; #define CTZ64(x) __builtin_ctzll(x) #endif -#elif defined(_MSC_VER) +#elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) static inline int msvc_ctz64(ALuint64 v) { - unsigned long idx = 0; + unsigned long idx = 64; _BitScanForward64(&idx, v); - return idx; + return (int)idx; } #define CTZ64(x) msvc_ctz64(x) @@ -121,7 +121,7 @@ static inline int fallback_popcnt64(ALuint64 v) v = v - ((v >> 1) & U64(0x5555555555555555)); v = (v & U64(0x3333333333333333)) + ((v >> 2) & U64(0x3333333333333333)); v = (v + (v >> 4)) & U64(0x0f0f0f0f0f0f0f0f); - return (v * U64(0x0101010101010101)) >> 56; + return (int)((v * U64(0x0101010101010101)) >> 56); } static inline int fallback_ctz64(ALuint64 value) diff --git a/config.h.in b/config.h.in index bc4e6432..99be6a0b 100644 --- a/config.h.in +++ b/config.h.in @@ -179,6 +179,9 @@ /* Define if we have the __cpuid() intrinsic */ #cmakedefine HAVE_CPUID_INTRINSIC +/* Define if we have the _BitScanForward64() intrinsic */ +#cmakedefine HAVE_BITSCANFORWARD64_INTRINSIC + /* Define if we have _controlfp() */ #cmakedefine HAVE__CONTROLFP -- cgit v1.2.3 From c969dad6c25bdce58e70e71eac92c4ba6f9ccf30 Mon Sep 17 00:00:00 2001 From: Arthur Brainville Date: Sat, 27 Jan 2018 23:16:36 +0100 Subject: Reformat README for a nicer display on github --- README | 55 ------------------------------------------------------- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 55 deletions(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index a0178ae5..00000000 --- a/README +++ /dev/null @@ -1,55 +0,0 @@ -Source Install -============== - -To install OpenAL Soft, use your favorite shell to go into the build/ -directory, and run: - -cmake .. - -Assuming configuration went well, you can then build it, typically using GNU -Make (KDevelop, MSVC, and others are possible depending on your system setup -and CMake configuration). - -Please Note: Double check that the appropriate backends were detected. Often, -complaints of no sound, crashing, and missing devices can be solved by making -sure the correct backends are being used. CMake's output will identify which -backends were enabled. - -For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio -were detected (if your target system uses them). For Windows, make sure -DirectSound was detected. - - -Utilities -========= - -The source package comes with an informational utility, openal-info, and is -built by default. It prints out information provided by the ALC and AL sub- -systems, including discovered devices, version information, and extensions. - - -Configuration -============= - -OpenAL Soft can be configured on a per-user and per-system basis. This allows -users and sysadmins to control information provided to applications, as well -as application-agnostic behavior of the library. See alsoftrc.sample for -available settings. - - -Acknowledgements -================ - -Special thanks go to: - -Creative Labs for the original source code this is based off of. - -Christopher Fitzgerald for the current reverb effect implementation, and -helping with the low-pass and HRTF filters. - -Christian Borss for the 3D panning code previous versions used as a base. - -Ben Davis for the idea behind a previous version of the click-removal code. - -Richard Furse for helping with my understanding of Ambisonics that is used by -the various parts of the library. diff --git a/README.md b/README.md new file mode 100644 index 00000000..3071163f --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +Source Install +============== + +To install OpenAL Soft, use your favorite shell to go into the build/ +directory, and run: + +```bash +cmake .. +``` + +Assuming configuration went well, you can then build it, typically using GNU +Make (KDevelop, MSVC, and others are possible depending on your system setup +and CMake configuration). + +Please Note: Double check that the appropriate backends were detected. Often, +complaints of no sound, crashing, and missing devices can be solved by making +sure the correct backends are being used. CMake's output will identify which +backends were enabled. + +For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio +were detected (if your target system uses them). For Windows, make sure +DirectSound was detected. + + +Utilities +========= + +The source package comes with an informational utility, openal-info, and is +built by default. It prints out information provided by the ALC and AL sub- +systems, including discovered devices, version information, and extensions. + + +Configuration +============= + +OpenAL Soft can be configured on a per-user and per-system basis. This allows +users and sysadmins to control information provided to applications, as well +as application-agnostic behavior of the library. See alsoftrc.sample for +available settings. + + +Acknowledgements +================ + +Special thanks go to: + + - Creative Labs for the original source code this is based off of. + - Christopher Fitzgerald for the current reverb effect implementation, and +helping with the low-pass and HRTF filters. + - Christian Borss for the 3D panning code previous versions used as a base. + - Ben Davis for the idea behind a previous version of the click-removal code. + - Richard Furse for helping with my understanding of Ambisonics that is used by +the various parts of the library. -- cgit v1.2.3 From f76ab02bd4fc13d6648d839374da966ef12201fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 11:19:59 -0800 Subject: Add a ctz64 fallback using _BitScanForward when available --- CMakeLists.txt | 7 +++++++ OpenAL32/Include/alMain.h | 16 +++++++++++++++- config.h.in | 3 +++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e3ee808..b5c65c55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,13 @@ IF(HAVE_INTRIN_H) _BitScanForward64(&idx, 1); return idx; }" HAVE_BITSCANFORWARD64_INTRINSIC) + CHECK_C_SOURCE_COMPILES("#include + int main() + { + unsigned long idx = 0; + _BitScanForward(&idx, 1); + return idx; + }" HAVE_BITSCANFORWARD_INTRINSIC) ENDIF() CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index afa3eee3..c4223ac9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -99,12 +99,26 @@ typedef ALuint64SOFT ALuint64; #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) -static inline int msvc_ctz64(ALuint64 v) +static inline int msvc64_ctz64(ALuint64 v) { unsigned long idx = 64; _BitScanForward64(&idx, v); return (int)idx; } +#define CTZ64(x) msvc64_ctz64(x) + +#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) + +static inline int msvc_ctz64(ALuint64 v) +{ + unsigned long idx = 64; + if(!_BitScanForward(&idx, v&0xffffffff)) + { + if(_BitScanForward(&idx, v>>32)) + idx += 32; + } + return (int)idx; +} #define CTZ64(x) msvc_ctz64(x) #else diff --git a/config.h.in b/config.h.in index 99be6a0b..8ef9057a 100644 --- a/config.h.in +++ b/config.h.in @@ -182,6 +182,9 @@ /* Define if we have the _BitScanForward64() intrinsic */ #cmakedefine HAVE_BITSCANFORWARD64_INTRINSIC +/* Define if we have the _BitScanForward() intrinsic */ +#cmakedefine HAVE_BITSCANFORWARD_INTRINSIC + /* Define if we have _controlfp() */ #cmakedefine HAVE__CONTROLFP -- cgit v1.2.3 From c4a76af3978715315603bd967ac688509b074775 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 11:50:06 -0800 Subject: Add some casts to pacify MSVC --- OpenAL32/alBuffer.c | 4 ++-- OpenAL32/alError.c | 4 ++-- OpenAL32/alState.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 1464ef74..a8ad855f 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1252,15 +1252,15 @@ static ALbuffer *AllocBuffer(ALCcontext *context) if(UNLIKELY(!buffer)) { const BufferSubList empty_sublist = { 0, NULL }; - lidx = VECTOR_SIZE(device->BufferList); /* Don't allocate so many list entries that the 32-bit ID could * overflow... */ - if(UNLIKELY(lidx >= 1<<25)) + if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) { almtx_unlock(&device->BufferLock); return NULL; } + lidx = (ALsizei)VECTOR_SIZE(device->BufferList); VECTOR_PUSH_BACK(device->BufferList, empty_sublist); sublist = &VECTOR_BACK(device->BufferList); sublist->FreeMask = ~U64(0); diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index fe0e02be..e3909742 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -48,14 +48,14 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) if(msglen < 0 || (size_t)msglen >= sizeof(message)) { message[sizeof(message)-1] = 0; - msglen = strlen(message); + msglen = (int)strlen(message); } if(msglen > 0) msg = message; else { msg = ""; - msglen = strlen(msg); + msglen = (int)strlen(msg); } WARN("Error generated on context %p, code 0x%04x, \"%s\"\n", diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 2637aacd..d436e7a7 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -720,9 +720,10 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) { static const ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; + const ALsizei msglen = (ALsizei)strlen(msg); almtx_lock(&context->EventLock); if((context->EnabledEvts&EventType_Deprecated) && context->EventCb) - (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, strlen(msg), msg, + (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, context->EventParam); almtx_unlock(&context->EventLock); } -- cgit v1.2.3 From 38261a0f2a5a17683ce90cbe86267669717a6df0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 11:56:31 -0800 Subject: Make some more functions static where they're used --- OpenAL32/Include/alSource.h | 14 -------------- OpenAL32/alSource.c | 21 ++++++++++++++------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 970ea07c..b346e619 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -104,20 +104,6 @@ typedef struct ALsource { ALuint id; } ALsource; -inline void LockSourcesRead(ALCcontext *context) -{ LockUIntMapRead(&context->SourceMap); } -inline void UnlockSourcesRead(ALCcontext *context) -{ UnlockUIntMapRead(&context->SourceMap); } -inline void LockSourcesWrite(ALCcontext *context) -{ LockUIntMapWrite(&context->SourceMap); } -inline void UnlockSourcesWrite(ALCcontext *context) -{ UnlockUIntMapWrite(&context->SourceMap); } - -inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); } -inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } - void UpdateAllSourceProps(ALCcontext *context); ALvoid ReleaseALSources(ALCcontext *Context); diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 17d57852..b5f8a94f 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -40,13 +40,6 @@ #include "almalloc.h" -extern inline void LockSourcesRead(ALCcontext *context); -extern inline void UnlockSourcesRead(ALCcontext *context); -extern inline void LockSourcesWrite(ALCcontext *context); -extern inline void UnlockSourcesWrite(ALCcontext *context); -extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); -extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); - static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context); @@ -56,6 +49,20 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); +static inline void LockSourcesRead(ALCcontext *context) +{ LockUIntMapRead(&context->SourceMap); } +static inline void UnlockSourcesRead(ALCcontext *context) +{ UnlockUIntMapRead(&context->SourceMap); } +static inline void LockSourcesWrite(ALCcontext *context) +{ LockUIntMapWrite(&context->SourceMap); } +static inline void UnlockSourcesWrite(ALCcontext *context) +{ UnlockUIntMapWrite(&context->SourceMap); } + +static inline ALsource *LookupSource(ALCcontext *context, ALuint id) +{ return (ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); } +static inline ALsource *RemoveSource(ALCcontext *context, ALuint id) +{ return (ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } + static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) { BufferSubList *sublist; -- cgit v1.2.3 From 031cf248808df8cc7d0af2a5c5174d189af7a4ac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 13:02:17 -0800 Subject: Use an array lookup for source IDs This is now similar to buffers, being stored in groups of 64 in a vector with the ID providing the array indices. --- Alc/ALc.c | 85 +++++++------ OpenAL32/Include/alMain.h | 12 +- OpenAL32/alSource.c | 317 ++++++++++++++++++++++++++++------------------ 3 files changed, 252 insertions(+), 162 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index aea49070..f59c6e90 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2231,6 +2231,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) context = ATOMIC_LOAD_SEQ(&device->ContextList); while(context) { + SourceSubList *sublist, *subend; struct ALvoiceProps *vprops; ALsizei pos; @@ -2263,40 +2264,48 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } UnlockUIntMapRead(&context->EffectSlotMap); - LockUIntMapRead(&context->SourceMap); - RelimitUIntMapNoLock(&context->SourceMap, device->SourcesMax); - for(pos = 0;pos < context->SourceMap.size;pos++) + almtx_lock(&context->SourceLock); + sublist = VECTOR_BEGIN(context->SourceList); + subend = VECTOR_END(context->SourceList); + for(;sublist != subend;++sublist) { - ALsource *source = context->SourceMap.values[pos]; - - if(old_sends != device->NumAuxSends) + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) { - ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); - ALsizei s; + ALsizei idx = CTZ64(usemask); + ALsource *source = sublist->Sources + idx; - memcpy(sends, source->Send, - mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) - ); - for(s = device->NumAuxSends;s < old_sends;s++) - { - if(source->Send[s].Slot) - DecrementRef(&source->Send[s].Slot->ref); - source->Send[s].Slot = NULL; - } - al_free(source->Send); - source->Send = sends; - for(s = old_sends;s < device->NumAuxSends;s++) + usemask &= ~(U64(1) << idx); + + if(old_sends != device->NumAuxSends) { - source->Send[s].Slot = NULL; - source->Send[s].Gain = 1.0f; - source->Send[s].GainHF = 1.0f; - source->Send[s].HFReference = LOWPASSFREQREF; - source->Send[s].GainLF = 1.0f; - source->Send[s].LFReference = HIGHPASSFREQREF; + ALvoid *sends = al_calloc(16, device->NumAuxSends*sizeof(source->Send[0])); + ALsizei s; + + memcpy(sends, source->Send, + mini(device->NumAuxSends, old_sends)*sizeof(source->Send[0]) + ); + for(s = device->NumAuxSends;s < old_sends;s++) + { + if(source->Send[s].Slot) + DecrementRef(&source->Send[s].Slot->ref); + source->Send[s].Slot = NULL; + } + al_free(source->Send); + source->Send = sends; + for(s = old_sends;s < device->NumAuxSends;s++) + { + source->Send[s].Slot = NULL; + source->Send[s].Gain = 1.0f; + source->Send[s].GainHF = 1.0f; + source->Send[s].HFReference = LOWPASSFREQREF; + source->Send[s].GainLF = 1.0f; + source->Send[s].LFReference = HIGHPASSFREQREF; + } } - } - ATOMIC_FLAG_CLEAR(&source->PropsClean, almemory_order_release); + ATOMIC_FLAG_CLEAR(&source->PropsClean, almemory_order_release); + } } /* Clear any pre-existing voice property structs, in case the number of @@ -2334,7 +2343,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } } } - UnlockUIntMapRead(&context->SourceMap); + almtx_unlock(&context->SourceLock); ATOMIC_FLAG_TEST_AND_SET(&context->PropsClean, almemory_order_release); UpdateContextProps(context); @@ -2522,7 +2531,9 @@ static ALvoid InitContext(ALCcontext *Context) Context->GainBoost = 1.0f; RWLockInit(&Context->PropLock); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); - InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax); + VECTOR_INIT(Context->SourceList); + Context->NumSources = 0; + almtx_init(&Context->SourceLock, almtx_plain); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); if(Context->DefaultSlot) @@ -2618,13 +2629,13 @@ static void FreeContext(ALCcontext *context) auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, NULL, almemory_order_relaxed); al_free(auxslots); - if(context->SourceMap.size > 0) - { - WARN("(%p) Deleting %d Source%s\n", context, context->SourceMap.size, - (context->SourceMap.size==1)?"":"s"); - ReleaseALSources(context); - } - ResetUIntMap(&context->SourceMap); + ReleaseALSources(context); +#define FREE_SOURCESUBLIST(x) al_free((x)->Sources) + VECTOR_FOR_EACH(SourceSubList, context->SourceList, FREE_SOURCESUBLIST); +#undef FREE_SOURCESUBLIST + VECTOR_DEINIT(context->SourceList); + context->NumSources = 0; + almtx_destroy(&context->SourceLock); count = 0; eprops = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c4223ac9..f7ae2ecd 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -165,6 +165,7 @@ struct FrontStablizer; struct Compressor; struct ALCbackend; struct ALbuffer; +struct ALsource; struct ALcontextProps; struct ALlistenerProps; struct ALvoiceProps; @@ -380,6 +381,12 @@ typedef struct BufferSubList { } BufferSubList; TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList) +typedef struct SourceSubList { + ALuint64 FreeMask; + struct ALsource *Sources; /* 64 */ +} SourceSubList; +TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList) + typedef struct EnumeratedHrtf { al_string name; @@ -589,7 +596,10 @@ struct ALCcontext_struct { struct ALlistener *Listener; - UIntMap SourceMap; + vector_SourceSubList SourceList; + ALuint NumSources; + almtx_t SourceLock; + UIntMap EffectSlotMap; ATOMIC(ALenum) LastError; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b5f8a94f..05d9a456 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -40,6 +40,8 @@ #include "almalloc.h" +static ALsource *AllocSource(ALCcontext *context); +static void FreeSource(ALCcontext *context, ALsource *source); static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); static void UpdateSourceProps(ALsource *source, ALvoice *voice, ALsizei num_sends, ALCcontext *context); @@ -49,19 +51,24 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac); static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); -static inline void LockSourcesRead(ALCcontext *context) -{ LockUIntMapRead(&context->SourceMap); } -static inline void UnlockSourcesRead(ALCcontext *context) -{ UnlockUIntMapRead(&context->SourceMap); } -static inline void LockSourcesWrite(ALCcontext *context) -{ LockUIntMapWrite(&context->SourceMap); } -static inline void UnlockSourcesWrite(ALCcontext *context) -{ UnlockUIntMapWrite(&context->SourceMap); } +static inline void LockSourceList(ALCcontext *context) +{ almtx_lock(&context->SourceLock); } +static inline void UnlockSourceList(ALCcontext *context) +{ almtx_unlock(&context->SourceLock); } static inline ALsource *LookupSource(ALCcontext *context, ALuint id) -{ return (ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); } -static inline ALsource *RemoveSource(ALCcontext *context, ALuint id) -{ return (ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); } +{ + SourceSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(context->SourceList))) + return NULL; + sublist = &VECTOR_ELEM(context->SourceList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Sources + slidx; +} static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) { @@ -1771,40 +1778,22 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) { - ALCdevice *device; ALCcontext *context; ALsizei cur = 0; - ALenum err; context = GetContextRef(); if(!context) return; if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d sources", n); - device = context->Device; for(cur = 0;cur < n;cur++) { - ALsource *source = al_calloc(16, sizeof(ALsource)); + ALsource *source = AllocSource(context); if(!source) { alDeleteSources(cur, sources); SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Failed to allocate source object"); } - InitSourceParams(source, device->NumAuxSends); - - 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); - SETERR_GOTO(context, err, done, "Failed to set source ID"); - } - sources[cur] = source->id; } @@ -1815,7 +1804,6 @@ done: AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) { - ALCdevice *device; ALCcontext *context; ALsource *Source; ALsizei i; @@ -1823,7 +1811,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; - LockSourcesWrite(context); + LockSourceList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d sources", n); @@ -1833,31 +1821,14 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) if(LookupSource(context, sources[i]) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", sources[i]); } - device = context->Device; for(i = 0;i < n;i++) { - ALvoice *voice; - - if((Source=RemoveSource(context, sources[i])) == NULL) - continue; - FreeThunkEntry(Source->id); - - ALCdevice_Lock(device); - if((voice=GetSourceVoice(Source, context)) != NULL) - { - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); - ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - } - ALCdevice_Unlock(device); - - DeinitSource(Source, device->NumAuxSends); - - memset(Source, 0, sizeof(*Source)); - al_free(Source); + if((Source=LookupSource(context, sources[i])) != NULL) + FreeSource(context, Source); } done: - UnlockSourcesWrite(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -1870,9 +1841,9 @@ AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) context = GetContextRef(); if(!context) return AL_FALSE; - LockSourcesRead(context); + LockSourceList(context); ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); @@ -1889,14 +1860,14 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(FloatValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM, "Invalid float property 0x%04x", param); else SetSourcefv(Source, Context, param, &value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -1911,7 +1882,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(FloatValsByProp(param) == 3)) @@ -1921,7 +1892,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 ALfloat fvals[3] = { value1, value2, value3 }; SetSourcefv(Source, Context, param, fvals); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -1936,7 +1907,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -1945,7 +1916,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat alSetError(Context, AL_INVALID_ENUM, "Invalid float-vector property 0x%04x", param); else SetSourcefv(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -1961,7 +1932,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(DoubleValsByProp(param) == 1)) @@ -1971,7 +1942,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va ALfloat fval = (ALfloat)value; SetSourcefv(Source, Context, param, &fval); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -1986,7 +1957,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(DoubleValsByProp(param) == 3)) @@ -1996,7 +1967,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; SetSourcefv(Source, Context, param, fvals); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2012,7 +1983,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2028,7 +1999,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo fvals[i] = (ALfloat)values[i]; SetSourcefv(Source, Context, param, fvals); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2044,14 +2015,14 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(IntValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else SetSourceiv(Source, Context, param, &value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2066,7 +2037,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(IntValsByProp(param) == 3)) @@ -2076,7 +2047,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL ALint ivals[3] = { value1, value2, value3 }; SetSourceiv(Source, Context, param, ivals); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2091,7 +2062,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2100,7 +2071,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else SetSourceiv(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2116,14 +2087,14 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(Int64ValsByProp(param) == 1)) alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else SetSourcei64v(Source, Context, param, &value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2138,7 +2109,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(Int64ValsByProp(param) == 3)) @@ -2148,7 +2119,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF ALint64SOFT i64vals[3] = { value1, value2, value3 }; SetSourcei64v(Source, Context, param, i64vals); } - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2163,7 +2134,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin if(!Context) return; WriteLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2172,7 +2143,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else SetSourcei64v(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); WriteUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2188,7 +2159,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) @@ -2201,7 +2172,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val if(GetSourcedv(Source, Context, param, &dval)) *value = (ALfloat)dval; } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2217,7 +2188,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) @@ -2234,7 +2205,7 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va *value3 = (ALfloat)dvals[2]; } } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2251,7 +2222,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2268,7 +2239,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va values[i] = (ALfloat)dvals[i]; } } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2284,7 +2255,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) @@ -2293,7 +2264,7 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * alSetError(Context, AL_INVALID_ENUM, "Invalid double property 0x%04x", param); else GetSourcedv(Source, Context, param, value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2308,7 +2279,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) @@ -2325,7 +2296,7 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value3 = dvals[2]; } } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2340,7 +2311,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2349,7 +2320,7 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble alSetError(Context, AL_INVALID_ENUM, "Invalid double-vector property 0x%04x", param); else GetSourcedv(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2365,7 +2336,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) @@ -2374,7 +2345,7 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value alSetError(Context, AL_INVALID_ENUM, "Invalid integer property 0x%04x", param); else GetSourceiv(Source, Context, param, value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2390,7 +2361,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) @@ -2407,7 +2378,7 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 *value3 = ivals[2]; } } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2423,7 +2394,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2432,7 +2403,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values alSetError(Context, AL_INVALID_ENUM, "Invalid integer-vector property 0x%04x", param); else GetSourceiv(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2448,7 +2419,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!value) @@ -2457,7 +2428,7 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S alSetError(Context, AL_INVALID_ENUM, "Invalid integer64 property 0x%04x", param); else GetSourcei64v(Source, Context, param, value); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2472,7 +2443,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!(value1 && value2 && value3)) @@ -2489,7 +2460,7 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 *value3 = i64vals[2]; } } - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2504,7 +2475,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 if(!Context) return; ReadLock(&Context->PropLock); - LockSourcesRead(Context); + LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); else if(!values) @@ -2513,7 +2484,7 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 alSetError(Context, AL_INVALID_ENUM, "Invalid integer64-vector property 0x%04x", param); else GetSourcei64v(Source, Context, param, values); - UnlockSourcesRead(Context); + UnlockSourceList(Context); ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); @@ -2535,7 +2506,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; - LockSourcesRead(context); + LockSourceList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Playing %d sources", n); for(i = 0;i < n;i++) @@ -2704,7 +2675,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ALCdevice_Unlock(device); done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -2723,7 +2694,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; - LockSourcesRead(context); + LockSourceList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Pausing %d sources", n); for(i = 0;i < n;i++) @@ -2751,7 +2722,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) ALCdevice_Unlock(device); done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -2770,7 +2741,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; - LockSourcesRead(context); + LockSourceList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Stopping %d sources", n); for(i = 0;i < n;i++) @@ -2801,7 +2772,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) ALCdevice_Unlock(device); done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -2820,7 +2791,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) context = GetContextRef(); if(!context) return; - LockSourcesRead(context); + LockSourceList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Rewinding %d sources", n); for(i = 0;i < n;i++) @@ -2851,7 +2822,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) ALCdevice_Unlock(device); done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -2874,7 +2845,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu device = context->Device; - LockSourcesRead(context); + LockSourceList(context); if(!(nb >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffers", nb); if((source=LookupSource(context, src)) == NULL) @@ -3004,7 +2975,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu WriteUnlock(&source->queue_lock); done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -3021,7 +2992,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint context = GetContextRef(); if(!context) return; - LockSourcesRead(context); + LockSourceList(context); if(!(nb >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing %d buffers", nb); if((source=LookupSource(context, src)) == NULL) @@ -3088,7 +3059,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } done: - UnlockSourcesRead(context); + UnlockSourceList(context); ALCcontext_DecRef(context); } @@ -3680,23 +3651,121 @@ static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALsizei *frac } +static ALsource *AllocSource(ALCcontext *context) +{ + ALCdevice *device = context->Device; + SourceSubList *sublist, *subend; + ALsource *source = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&context->SourceLock); + if(context->NumSources >= device->SourcesMax) + { + almtx_unlock(&context->SourceLock); + return NULL; + } + sublist = VECTOR_BEGIN(context->SourceList); + subend = VECTOR_END(context->SourceList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + source = sublist->Sources + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!source)) + { + const SourceSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25)) + { + almtx_unlock(&device->BufferLock); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(context->SourceList); + VECTOR_PUSH_BACK(context->SourceList, empty_sublist); + sublist = &VECTOR_BACK(context->SourceList); + sublist->FreeMask = ~U64(0); + sublist->Sources = al_calloc(16, sizeof(ALsource)*64); + if(UNLIKELY(!sublist->Sources)) + { + VECTOR_POP_BACK(context->SourceList); + almtx_unlock(&context->SourceLock); + return NULL; + } + + slidx = 0; + source = sublist->Sources + slidx; + } + + memset(source, 0, sizeof(*source)); + InitSourceParams(source, device->NumAuxSends); + + /* Add 1 to avoid source ID 0. */ + source->id = ((lidx<<6) | slidx) + 1; + + context->NumSources++; + sublist->FreeMask &= ~(U64(1)<SourceLock); + + return source; +} + +static void FreeSource(ALCcontext *context, ALsource *source) +{ + ALCdevice *device = context->Device; + ALuint id = source->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + ALvoice *voice; + + ALCdevice_Lock(device); + if((voice=GetSourceVoice(source, context)) != NULL) + { + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + } + ALCdevice_Unlock(device); + + DeinitSource(source, device->NumAuxSends); + memset(source, 0, sizeof(*source)); + + VECTOR_ELEM(context->SourceList, lidx).FreeMask |= U64(1) << slidx; + context->NumSources--; +} + /* ReleaseALSources * * Destroys all sources in the source map. */ -ALvoid ReleaseALSources(ALCcontext *Context) +ALvoid ReleaseALSources(ALCcontext *context) { - ALCdevice *device = Context->Device; - ALsizei pos; - for(pos = 0;pos < Context->SourceMap.size;pos++) + ALCdevice *device = context->Device; + SourceSubList *sublist = VECTOR_BEGIN(context->SourceList); + SourceSubList *subend = VECTOR_END(context->SourceList); + size_t leftover = 0; + for(;sublist != subend;++sublist) { - ALsource *temp = Context->SourceMap.values[pos]; - Context->SourceMap.values[pos] = NULL; + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALsource *source = sublist->Sources + idx; - DeinitSource(temp, device->NumAuxSends); + DeinitSource(source, device->NumAuxSends); + memset(source, 0, sizeof(*source)); + ++leftover; - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(*temp)); - al_free(temp); + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; } + if(leftover > 0) + WARN("(%p) Deleted "SZFMT" Source%s\n", device, leftover, (leftover==1)?"":"s"); } -- cgit v1.2.3 From 6562a939ea5a5b582d6aa182f3f6fa7411a5e222 Mon Sep 17 00:00:00 2001 From: Arthur Brainville Date: Sun, 28 Jan 2018 01:37:00 +0100 Subject: Add project overview and travis build badge Signed-off-by: Arthur Brainville (Ybalrid) --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3071163f..42d12fda 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ -Source Install -============== +OpenAL-soft +=========== + +CI status : [![Build Status](https://travis-ci.org/kcat/openal-soft.svg?branch=master)](https://travis-ci.org/kcat/openal-soft) + +OpenAL Soft is an LGPL-licensed, cross-platform, software implementation of the OpenAL 3D audio API. It's forked from the open-sourced Windows version available originally from openal.org's SVN repository (now defunct). +OpenAL provides capabilities for playing audio in a virtual 3D environment. Distance attenuation, doppler shift, and directional sound emitters are among the features handled by the API. More advanced effects, including air absorption, occlusion, and environmental reverb, are available through the EFX extension. It also facilitates streaming audio, multi-channel buffers, and audio capture. +More information available on the [official website](http://openal-soft.org/) + +Source Install +------------- To install OpenAL Soft, use your favorite shell to go into the build/ directory, and run: @@ -23,15 +32,14 @@ DirectSound was detected. Utilities -========= - +--------- The source package comes with an informational utility, openal-info, and is built by default. It prints out information provided by the ALC and AL sub- systems, including discovered devices, version information, and extensions. Configuration -============= +------------- OpenAL Soft can be configured on a per-user and per-system basis. This allows users and sysadmins to control information provided to applications, as well @@ -40,7 +48,7 @@ available settings. Acknowledgements -================ +---------------- Special thanks go to: -- cgit v1.2.3 From d2cf61c99aa46561f6a32d4194c149c5c5bca4e0 Mon Sep 17 00:00:00 2001 From: Arthur Brainville Date: Sun, 28 Jan 2018 02:29:54 +0100 Subject: Added AppVeyor badge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42d12fda..ecfd855b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ OpenAL-soft =========== -CI status : [![Build Status](https://travis-ci.org/kcat/openal-soft.svg?branch=master)](https://travis-ci.org/kcat/openal-soft) +`master` branch CI status : [![Build Status](https://travis-ci.org/kcat/openal-soft.svg?branch=master)](https://travis-ci.org/kcat/openal-soft) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/kcat/openal-soft?branch=master&svg=true)](https://ci.appveyor.com/api/projects/status/github/kcat/openal-soft?branch=master&svg=true) OpenAL Soft is an LGPL-licensed, cross-platform, software implementation of the OpenAL 3D audio API. It's forked from the open-sourced Windows version available originally from openal.org's SVN repository (now defunct). OpenAL provides capabilities for playing audio in a virtual 3D environment. Distance attenuation, doppler shift, and directional sound emitters are among the features handled by the API. More advanced effects, including air absorption, occlusion, and environmental reverb, are available through the EFX extension. It also facilitates streaming audio, multi-channel buffers, and audio capture. -More information available on the [official website](http://openal-soft.org/) +More information are available on the [official website](http://openal-soft.org/) Source Install ------------- -- cgit v1.2.3 From 58fd9d70d250047c2edd8a35b69d0e2f10948dad Mon Sep 17 00:00:00 2001 From: Arthur Brainville Date: Sun, 28 Jan 2018 03:26:02 +0100 Subject: Additional corrections as mentionned in the PR --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecfd855b..0c9d3027 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -OpenAL-soft +OpenAL soft =========== `master` branch CI status : [![Build Status](https://travis-ci.org/kcat/openal-soft.svg?branch=master)](https://travis-ci.org/kcat/openal-soft) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/kcat/openal-soft?branch=master&svg=true)](https://ci.appveyor.com/api/projects/status/github/kcat/openal-soft?branch=master&svg=true) @@ -6,7 +6,7 @@ OpenAL-soft OpenAL Soft is an LGPL-licensed, cross-platform, software implementation of the OpenAL 3D audio API. It's forked from the open-sourced Windows version available originally from openal.org's SVN repository (now defunct). OpenAL provides capabilities for playing audio in a virtual 3D environment. Distance attenuation, doppler shift, and directional sound emitters are among the features handled by the API. More advanced effects, including air absorption, occlusion, and environmental reverb, are available through the EFX extension. It also facilitates streaming audio, multi-channel buffers, and audio capture. -More information are available on the [official website](http://openal-soft.org/) +More information is available on the [official website](http://openal-soft.org/) Source Install ------------- -- cgit v1.2.3 From 4d1795e90b83f040aa59cf69616a4ff2b32bf71a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 15:06:20 -0800 Subject: Remove an unused function --- common/uintmap.c | 5 ----- common/uintmap.h | 1 - 2 files changed, 6 deletions(-) diff --git a/common/uintmap.c b/common/uintmap.c index 98ed3191..be628a5f 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -36,11 +36,6 @@ void ResetUIntMap(UIntMap *map) WriteUnlock(&map->lock); } -void RelimitUIntMapNoLock(UIntMap *map, ALsizei limit) -{ - map->limit = limit; -} - ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) { ALsizei pos = 0; diff --git a/common/uintmap.h b/common/uintmap.h index 3adc66c4..32cd1eaa 100644 --- a/common/uintmap.h +++ b/common/uintmap.h @@ -25,7 +25,6 @@ typedef struct UIntMap { void InitUIntMap(UIntMap *map, ALsizei limit); void ResetUIntMap(UIntMap *map); -void RelimitUIntMapNoLock(UIntMap *map, ALsizei limit); ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); -- cgit v1.2.3 From 6a839600b96b73104f8b93a4fa4a1a8da67cae5c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 17:24:18 -0800 Subject: Use a vector to store the effect slot pointers And make the ID a simple index into it (1-base, to avoid ID 0). --- Alc/ALc.c | 25 +++---- OpenAL32/Include/alAuxEffectSlot.h | 14 ---- OpenAL32/Include/alMain.h | 9 ++- OpenAL32/alAuxEffectSlot.c | 143 +++++++++++++++++++++---------------- OpenAL32/alSource.c | 18 +++-- 5 files changed, 116 insertions(+), 93 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f59c6e90..0dc93b56 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2249,10 +2249,10 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } WriteLock(&context->PropLock); - LockUIntMapRead(&context->EffectSlotMap); - for(pos = 0;pos < context->EffectSlotMap.size;pos++) + almtx_lock(&context->EffectSlotLock); + for(pos = 0;pos < (ALsizei)VECTOR_SIZE(context->EffectSlotList);pos++) { - ALeffectslot *slot = context->EffectSlotMap.values[pos]; + ALeffectslot *slot = VECTOR_ELEM(context->EffectSlotList, pos); ALeffectState *state = slot->Effect.State; state->OutBuffer = device->Dry.Buffer; @@ -2262,7 +2262,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) else UpdateEffectSlotProps(slot, context); } - UnlockUIntMapRead(&context->EffectSlotMap); + almtx_unlock(&context->EffectSlotLock); almtx_lock(&context->SourceLock); sublist = VECTOR_BEGIN(context->SourceList); @@ -2534,7 +2534,8 @@ static ALvoid InitContext(ALCcontext *Context) VECTOR_INIT(Context->SourceList); Context->NumSources = 0; almtx_init(&Context->SourceLock, almtx_plain); - InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); + VECTOR_INIT(Context->EffectSlotList); + almtx_init(&Context->EffectSlotLock, almtx_plain); if(Context->DefaultSlot) { @@ -2648,13 +2649,13 @@ static void FreeContext(ALCcontext *context) ++count; } TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s"); - if(context->EffectSlotMap.size > 0) - { - WARN("(%p) Deleting %d AuxiliaryEffectSlot%s\n", context, context->EffectSlotMap.size, - (context->EffectSlotMap.size==1)?"":"s"); - ReleaseALAuxiliaryEffectSlots(context); - } - ResetUIntMap(&context->EffectSlotMap); + + ReleaseALAuxiliaryEffectSlots(context); +#define FREE_EFFECTSLOTPTR(x) al_free(*(x)) + VECTOR_FOR_EACH(ALeffectslotPtr, context->EffectSlotList, FREE_EFFECTSLOTPTR); +#undef FREE_EFFECTSLOTPTR + VECTOR_DEINIT(context->EffectSlotList); + almtx_destroy(&context->EffectSlotLock); count = 0; vprops = ATOMIC_LOAD(&context->FreeVoiceProps, almemory_order_relaxed); diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 74bb841c..e4e954a0 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -149,20 +149,6 @@ typedef struct ALeffectslot { alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALeffectslot; -inline void LockEffectSlotsRead(ALCcontext *context) -{ LockUIntMapRead(&context->EffectSlotMap); } -inline void UnlockEffectSlotsRead(ALCcontext *context) -{ UnlockUIntMapRead(&context->EffectSlotMap); } -inline void LockEffectSlotsWrite(ALCcontext *context) -{ LockUIntMapWrite(&context->EffectSlotMap); } -inline void UnlockEffectSlotsWrite(ALCcontext *context) -{ UnlockUIntMapWrite(&context->EffectSlotMap); } - -inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) -{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); } -inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id) -{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); } - ALenum InitEffectSlot(ALeffectslot *slot); void DeinitEffectSlot(ALeffectslot *slot); void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f7ae2ecd..d1ae0a94 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -387,6 +387,12 @@ typedef struct SourceSubList { } SourceSubList; TYPEDEF_VECTOR(SourceSubList, vector_SourceSubList) +/* Effect slots are rather large, and apps aren't likely to have more than one + * or two (let alone 64), so hold them individually. + */ +typedef struct ALeffectslot *ALeffectslotPtr; +TYPEDEF_VECTOR(ALeffectslotPtr, vector_ALeffectslotPtr) + typedef struct EnumeratedHrtf { al_string name; @@ -600,7 +606,8 @@ struct ALCcontext_struct { ALuint NumSources; almtx_t SourceLock; - UIntMap EffectSlotMap; + vector_ALeffectslotPtr EffectSlotList; + almtx_t EffectSlotLock; ATOMIC(ALenum) LastError; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index d2039097..3fbf4b6e 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -36,13 +36,6 @@ #include "almalloc.h" -extern inline void LockEffectSlotsRead(ALCcontext *context); -extern inline void UnlockEffectSlotsRead(ALCcontext *context); -extern inline void LockEffectSlotsWrite(ALCcontext *context); -extern inline void UnlockEffectSlotsWrite(ALCcontext *context); -extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id); -extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id); - static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) { @@ -54,6 +47,21 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) static void ALeffectState_IncRef(ALeffectState *state); + +static inline void LockEffectSlotList(ALCcontext *context) +{ almtx_lock(&context->EffectSlotLock); } +static inline void UnlockEffectSlotList(ALCcontext *context) +{ almtx_unlock(&context->EffectSlotLock); } + +static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) +{ + id--; + if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) + return NULL; + return VECTOR_ELEM(context->EffectSlotList, id); +} + + #define DO_UPDATEPROPS() do { \ if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ UpdateEffectSlotProps(slot, context); \ @@ -76,38 +84,45 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); - LockEffectSlotsWrite(context); + LockEffectSlotList(context); 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) - { - al_free(slot); - UnlockEffectSlotsWrite(context); + ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); + ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); + ALeffectslot *slot = NULL; - alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); + for(;iter != end;iter++) + { + if(!*iter) + break; } + if(iter == end) + { + if(VECTOR_SIZE(context->EffectSlotList) >= INT_MAX) + { + UnlockEffectSlotList(context); - err = NewThunkEntry(&slot->id); - if(err == AL_NO_ERROR) - err = InsertUIntMapEntryNoLock(&context->EffectSlotMap, slot->id, slot); - if(err != AL_NO_ERROR) + alDeleteAuxiliaryEffectSlots(cur, effectslots); + SETERR_GOTO(context, err, done, "Too many effect slot objects"); + } + VECTOR_PUSH_BACK(context->EffectSlotList, NULL); + iter = &VECTOR_BACK(context->EffectSlotList); + } + slot = al_calloc(16, sizeof(ALeffectslot)); + err = AL_OUT_OF_MEMORY; + if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) { - FreeThunkEntry(slot->id); - ALeffectState_DecRef(slot->Effect.State); - if(slot->Params.EffectState) - ALeffectState_DecRef(slot->Params.EffectState); al_free(slot); - UnlockEffectSlotsWrite(context); + UnlockEffectSlotList(context); alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, done, "Failed to set effect slot ID"); + SETERR_GOTO(context, err, done, "Effect slot object allocation failed"); } - aluInitEffectPanning(slot); + slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; + *iter = slot; + tmpslots[cur] = slot; effectslots[cur] = slot->id; } @@ -131,7 +146,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo althrd_yield(); al_free(newarray); } - UnlockEffectSlotsWrite(context); + UnlockEffectSlotList(context); done: al_free(tmpslots); @@ -147,7 +162,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * context = GetContextRef(); if(!context) return; - LockEffectSlotsWrite(context); + LockEffectSlotList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); for(i = 0;i < n;i++) @@ -194,9 +209,9 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * for(i = 0;i < n;i++) { - if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL) + if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) continue; - FreeThunkEntry(slot->id); + VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL; DeinitEffectSlot(slot); @@ -205,7 +220,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * } done: - UnlockEffectSlotsWrite(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -217,9 +232,9 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) context = GetContextRef(); if(!context) return AL_FALSE; - LockEffectSlotsRead(context); + LockEffectSlotList(context); ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE); - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); @@ -238,7 +253,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param if(!context) return; WriteLock(&context->PropLock); - LockEffectSlotsRead(context); + LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -274,7 +289,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param DO_UPDATEPROPS(); done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -294,7 +309,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if(LookupEffectSlot(context, effectslot) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -305,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -318,7 +333,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param if(!context) return; WriteLock(&context->PropLock); - LockEffectSlotsRead(context); + LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -336,7 +351,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param DO_UPDATEPROPS(); done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); WriteUnlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -355,7 +370,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if(LookupEffectSlot(context, effectslot) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -366,7 +381,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -378,7 +393,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -392,7 +407,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -411,7 +426,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if(LookupEffectSlot(context, effectslot) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -422,7 +437,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -434,7 +449,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -448,7 +463,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -466,7 +481,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p context = GetContextRef(); if(!context) return; - LockEffectSlotsRead(context); + LockEffectSlotList(context); if(LookupEffectSlot(context, effectslot) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); switch(param) @@ -477,7 +492,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p } done: - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); ALCcontext_DecRef(context); } @@ -697,7 +712,7 @@ void UpdateAllEffectSlotProps(ALCcontext *context) struct ALeffectslotArray *auxslots; ALsizei i; - LockEffectSlotsRead(context); + LockEffectSlotList(context); auxslots = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); for(i = 0;i < auxslots->count;i++) { @@ -705,21 +720,27 @@ void UpdateAllEffectSlotProps(ALCcontext *context) if(!ATOMIC_FLAG_TEST_AND_SET(&slot->PropsClean, almemory_order_acq_rel)) UpdateEffectSlotProps(slot, context); } - UnlockEffectSlotsRead(context); + UnlockEffectSlotList(context); } -ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context) +ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context) { - ALsizei pos; - for(pos = 0;pos < Context->EffectSlotMap.size;pos++) + ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); + ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); + size_t leftover = 0; + + for(;iter != end;iter++) { - ALeffectslot *temp = Context->EffectSlotMap.values[pos]; - Context->EffectSlotMap.values[pos] = NULL; + ALeffectslot *slot = *iter; + if(!slot) continue; + *iter = NULL; - DeinitEffectSlot(temp); + DeinitEffectSlot(slot); - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(ALeffectslot)); - al_free(temp); + memset(slot, 0, sizeof(*slot)); + al_free(slot); + ++leftover; } + if(leftover > 0) + WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s"); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 05d9a456..58026aeb 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -84,6 +84,14 @@ static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) return sublist->Buffers + slidx; } +static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) +{ + id--; + if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) + return NULL; + return VECTOR_ELEM(context->EffectSlotList, id); +} + typedef enum SourceProp { srcPitch = AL_PITCH, @@ -972,23 +980,23 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: - LockEffectSlotsRead(Context); + almtx_lock(&Context->EffectSlotLock); if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) { - UnlockEffectSlotsRead(Context); + almtx_unlock(&Context->EffectSlotLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); } if(!((ALuint)values[1] < (ALuint)device->NumAuxSends)) { - UnlockEffectSlotsRead(Context); + almtx_unlock(&Context->EffectSlotLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); } LockFiltersRead(device); if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) { UnlockFiltersRead(device); - UnlockEffectSlotsRead(Context); + almtx_unlock(&Context->EffectSlotLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); } @@ -1037,7 +1045,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].Slot = slot; DO_UPDATEPROPS(); } - UnlockEffectSlotsRead(Context); + almtx_unlock(&Context->EffectSlotLock); return AL_TRUE; -- cgit v1.2.3 From e8c268ef09d53461386fa7e81bd853cd1007d6c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 19:01:25 -0800 Subject: Store effects in an array of lists --- Alc/ALc.c | 22 ++--- OpenAL32/Include/alEffect.h | 14 ---- OpenAL32/Include/alMain.h | 10 ++- OpenAL32/alAuxEffectSlot.c | 20 ++++- OpenAL32/alEffect.c | 195 ++++++++++++++++++++++++++++++-------------- 5 files changed, 172 insertions(+), 89 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 0dc93b56..9a0fa63b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2392,13 +2392,12 @@ static ALCvoid FreeDevice(ALCdevice *device) VECTOR_DEINIT(device->BufferList); almtx_destroy(&device->BufferLock); - if(device->EffectMap.size > 0) - { - WARN("(%p) Deleting %d Effect%s\n", device, device->EffectMap.size, - (device->EffectMap.size==1)?"":"s"); - ReleaseALEffects(device); - } - ResetUIntMap(&device->EffectMap); + ReleaseALEffects(device); +#define FREE_EFFECTSUBLIST(x) al_free((x)->Effects) + VECTOR_FOR_EACH(EffectSubList, device->EffectList, FREE_EFFECTSUBLIST); +#undef FREE_EFFECTSUBLIST + VECTOR_DEINIT(device->EffectList); + almtx_destroy(&device->EffectLock); if(device->FilterMap.size > 0) { @@ -4000,7 +3999,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumAuxSends = DEFAULT_SENDS; VECTOR_INIT(device->BufferList); - InitUIntMap(&device->EffectMap, INT_MAX); + VECTOR_INIT(device->EffectList); InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -4132,6 +4131,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); + almtx_init(&device->EffectLock, almtx_plain); if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { @@ -4278,7 +4278,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->RealOut.NumChannels = 0; VECTOR_INIT(device->BufferList); - InitUIntMap(&device->EffectMap, INT_MAX); + VECTOR_INIT(device->EffectList); InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -4327,6 +4327,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); + almtx_init(&device->EffectLock, almtx_plain); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); @@ -4502,7 +4503,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumAuxSends = DEFAULT_SENDS; VECTOR_INIT(device->BufferList); - InitUIntMap(&device->EffectMap, INT_MAX); + VECTOR_INIT(device->EffectList); InitUIntMap(&device->FilterMap, INT_MAX); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -4522,6 +4523,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN } almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); + almtx_init(&device->EffectLock, almtx_plain); //Set output format device->NumUpdates = 0; diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index dbbd8966..30055f1f 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -166,20 +166,6 @@ typedef struct ALeffect { ALuint id; } ALeffect; -inline void LockEffectsRead(ALCdevice *device) -{ LockUIntMapRead(&device->EffectMap); } -inline void UnlockEffectsRead(ALCdevice *device) -{ UnlockUIntMapRead(&device->EffectMap); } -inline void LockEffectsWrite(ALCdevice *device) -{ LockUIntMapWrite(&device->EffectMap); } -inline void UnlockEffectsWrite(ALCdevice *device) -{ UnlockUIntMapWrite(&device->EffectMap); } - -inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id) -{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); } -inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id) -{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); } - inline ALboolean IsReverbEffect(ALenum type) { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d1ae0a94..8908d93f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -165,6 +165,7 @@ struct FrontStablizer; struct Compressor; struct ALCbackend; struct ALbuffer; +struct ALeffect; struct ALsource; struct ALcontextProps; struct ALlistenerProps; @@ -381,6 +382,12 @@ typedef struct BufferSubList { } BufferSubList; TYPEDEF_VECTOR(BufferSubList, vector_BufferSubList) +typedef struct EffectSubList { + ALuint64 FreeMask; + struct ALeffect *Effects; /* 64 */ +} EffectSubList; +TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList) + typedef struct SourceSubList { ALuint64 FreeMask; struct ALsource *Sources; /* 64 */ @@ -485,7 +492,8 @@ struct ALCdevice_struct almtx_t BufferLock; // Map of Effects for this device - UIntMap EffectMap; + vector_EffectSubList EffectList; + almtx_t EffectLock; // Map of Filters for this device UIntMap FilterMap; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 3fbf4b6e..30ca097f 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -61,6 +61,20 @@ static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) return VECTOR_ELEM(context->EffectSlotList, id); } +static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + EffectSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) + return NULL; + sublist = &VECTOR_ELEM(device->EffectList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; +} + #define DO_UPDATEPROPS() do { \ if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \ @@ -261,15 +275,15 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param case AL_EFFECTSLOT_EFFECT: device = context->Device; - LockEffectsRead(device); + almtx_lock(&device->EffectLock); effect = (value ? LookupEffect(device, value) : NULL); if(!(value == 0 || effect != NULL)) { - UnlockEffectsRead(device); + almtx_unlock(&device->EffectLock); SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); } err = InitializeEffect(context, slot, effect); - UnlockEffectsRead(device); + almtx_unlock(&device->EffectLock); if(err != AL_NO_ERROR) SETERR_GOTO(context, err, done, "Effect initialization failed"); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index ab42112c..797687fa 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -48,20 +48,34 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { ALboolean DisabledEffects[MAX_EFFECTS]; -extern inline void LockEffectsRead(ALCdevice *device); -extern inline void UnlockEffectsRead(ALCdevice *device); -extern inline void LockEffectsWrite(ALCdevice *device); -extern inline void UnlockEffectsWrite(ALCdevice *device); -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 ALeffect *AllocEffect(ALCcontext *context); +static void FreeEffect(ALCdevice *device, ALeffect *effect); static void InitEffectParams(ALeffect *effect, ALenum type); +static inline void LockEffectList(ALCdevice *device) +{ almtx_lock(&device->EffectLock); } +static inline void UnlockEffectList(ALCdevice *device) +{ almtx_unlock(&device->EffectLock); } + +static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) +{ + EffectSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) + return NULL; + sublist = &VECTOR_ELEM(device->EffectList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Effects + slidx; +} + AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) { - ALCdevice *device; ALCcontext *context; ALsizei cur; @@ -71,31 +85,14 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effects", n); - device = context->Device; for(cur = 0;cur < n;cur++) { - ALeffect *effect = al_calloc(16, sizeof(ALeffect)); - ALenum err = AL_OUT_OF_MEMORY; - if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR) + ALeffect *effect = AllocEffect(context); + if(!effect) { - al_free(effect); - alDeleteEffects(cur, effects); - SETERR_GOTO(context, err, done, "Failed to allocate effect object"); - } - - 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)); - al_free(effect); - alDeleteEffects(cur, effects); - SETERR_GOTO(context, err, done, "Failed to set effect ID"); + break; } - effects[cur] = effect->id; } @@ -114,7 +111,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) if(!context) return; device = context->Device; - LockEffectsWrite(device); + LockEffectList(device); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n); for(i = 0;i < n;i++) @@ -124,16 +121,12 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) } for(i = 0;i < n;i++) { - if((effect=RemoveEffect(device, effects[i])) == NULL) - continue; - FreeThunkEntry(effect->id); - - memset(effect, 0, sizeof(*effect)); - al_free(effect); + if((effect=LookupEffect(device, effects[i])) != NULL) + FreeEffect(device, effect); } done: - UnlockEffectsWrite(device); + UnlockEffectList(device); ALCcontext_DecRef(context); } @@ -145,10 +138,10 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) Context = GetContextRef(); if(!Context) return AL_FALSE; - LockEffectsRead(Context->Device); + LockEffectList(Context->Device); result = ((!effect || LookupEffect(Context->Device, effect)) ? AL_TRUE : AL_FALSE); - UnlockEffectsRead(Context->Device); + UnlockEffectList(Context->Device); ALCcontext_DecRef(Context); @@ -165,7 +158,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) if(!Context) return; Device = Context->Device; - LockEffectsWrite(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -192,7 +185,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) V(ALEffect,setParami)(Context, param, value); } } - UnlockEffectsWrite(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -214,7 +207,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v if(!Context) return; Device = Context->Device; - LockEffectsWrite(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -222,7 +215,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v /* Call the appropriate handler */ V(ALEffect,setParamiv)(Context, param, values); } - UnlockEffectsWrite(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -237,7 +230,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) if(!Context) return; Device = Context->Device; - LockEffectsWrite(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -245,7 +238,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) /* Call the appropriate handler */ V(ALEffect,setParamf)(Context, param, value); } - UnlockEffectsWrite(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -260,7 +253,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat if(!Context) return; Device = Context->Device; - LockEffectsWrite(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -268,7 +261,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat /* Call the appropriate handler */ V(ALEffect,setParamfv)(Context, param, values); } - UnlockEffectsWrite(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -283,7 +276,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value if(!Context) return; Device = Context->Device; - LockEffectsRead(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -296,7 +289,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value V(ALEffect,getParami)(Context, param, value); } } - UnlockEffectsRead(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -318,7 +311,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu if(!Context) return; Device = Context->Device; - LockEffectsRead(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -326,7 +319,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu /* Call the appropriate handler */ V(ALEffect,getParamiv)(Context, param, values); } - UnlockEffectsRead(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -341,7 +334,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val if(!Context) return; Device = Context->Device; - LockEffectsRead(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -349,7 +342,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val /* Call the appropriate handler */ V(ALEffect,getParamf)(Context, param, value); } - UnlockEffectsRead(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -364,7 +357,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va if(!Context) return; Device = Context->Device; - LockEffectsRead(Device); + LockEffectList(Device); if((ALEffect=LookupEffect(Device, effect)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect); else @@ -372,7 +365,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va /* Call the appropriate handler */ V(ALEffect,getParamfv)(Context, param, values); } - UnlockEffectsRead(Device); + UnlockEffectList(Device); ALCcontext_DecRef(Context); } @@ -384,19 +377,99 @@ ALenum InitEffect(ALeffect *effect) return AL_NO_ERROR; } +static ALeffect *AllocEffect(ALCcontext *context) +{ + ALCdevice *device = context->Device; + EffectSubList *sublist, *subend; + ALeffect *effect = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&device->EffectLock); + sublist = VECTOR_BEGIN(device->EffectList); + subend = VECTOR_END(device->EffectList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + effect = sublist->Effects + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!effect)) + { + const EffectSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) + { + almtx_unlock(&device->EffectLock); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(device->EffectList); + VECTOR_PUSH_BACK(device->EffectList, empty_sublist); + sublist = &VECTOR_BACK(device->EffectList); + sublist->FreeMask = ~U64(0); + sublist->Effects = al_calloc(16, sizeof(ALeffect)*64); + if(UNLIKELY(!sublist->Effects)) + { + VECTOR_POP_BACK(device->EffectList); + almtx_unlock(&device->EffectLock); + return NULL; + } + + slidx = 0; + effect = sublist->Effects + slidx; + } + + memset(effect, 0, sizeof(*effect)); + InitEffectParams(effect, AL_EFFECT_NULL); + + /* Add 1 to avoid effect ID 0. */ + effect->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<EffectLock); + + return effect; +} + +static void FreeEffect(ALCdevice *device, ALeffect *effect) +{ + ALuint id = effect->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + memset(effect, 0, sizeof(*effect)); + + VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; +} + ALvoid ReleaseALEffects(ALCdevice *device) { - ALsizei i; - for(i = 0;i < device->EffectMap.size;i++) + EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); + EffectSubList *subend = VECTOR_END(device->EffectList); + size_t leftover = 0; + for(;sublist != subend;++sublist) { - ALeffect *temp = device->EffectMap.values[i]; - device->EffectMap.values[i] = NULL; + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALeffect *effect = sublist->Effects + idx; - // Release effect structure - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(ALeffect)); - al_free(temp); + memset(effect, 0, sizeof(*effect)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; } + if(leftover > 0) + WARN("(%p) Deleted "SZFMT" Effect%s\n", device, leftover, (leftover==1)?"":"s"); } -- cgit v1.2.3 From cb9fb3121499b02efd7ce513ea95173a3ce64f4c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 19:40:47 -0800 Subject: Store filters in an array of lists --- Alc/ALc.c | 22 ++--- OpenAL32/Include/alFilter.h | 16 +--- OpenAL32/Include/alMain.h | 10 ++- OpenAL32/alFilter.c | 194 ++++++++++++++++++++++++++++++-------------- OpenAL32/alSource.c | 26 ++++-- 5 files changed, 176 insertions(+), 92 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 9a0fa63b..7ec5ec8d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2399,13 +2399,12 @@ static ALCvoid FreeDevice(ALCdevice *device) VECTOR_DEINIT(device->EffectList); almtx_destroy(&device->EffectLock); - if(device->FilterMap.size > 0) - { - WARN("(%p) Deleting %d Filter%s\n", device, device->FilterMap.size, - (device->FilterMap.size==1)?"":"s"); - ReleaseALFilters(device); - } - ResetUIntMap(&device->FilterMap); + ReleaseALFilters(device); +#define FREE_FILTERSUBLIST(x) al_free((x)->Filters) + VECTOR_FOR_EACH(FilterSubList, device->FilterList, FREE_FILTERSUBLIST); +#undef FREE_FILTERSUBLIST + VECTOR_DEINIT(device->FilterList); + almtx_destroy(&device->FilterLock); AL_STRING_DEINIT(device->HrtfName); FreeHrtfList(&device->HrtfList); @@ -4000,7 +3999,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) VECTOR_INIT(device->BufferList); VECTOR_INIT(device->EffectList); - InitUIntMap(&device->FilterMap, INT_MAX); + VECTOR_INIT(device->FilterList); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -4132,6 +4131,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); almtx_init(&device->EffectLock, almtx_plain); + almtx_init(&device->FilterLock, almtx_plain); if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { @@ -4279,7 +4279,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, VECTOR_INIT(device->BufferList); VECTOR_INIT(device->EffectList); - InitUIntMap(&device->FilterMap, INT_MAX); + VECTOR_INIT(device->FilterList); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -4328,6 +4328,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); almtx_init(&device->EffectLock, almtx_plain); + almtx_init(&device->FilterLock, almtx_plain); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); @@ -4504,7 +4505,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN VECTOR_INIT(device->BufferList); VECTOR_INIT(device->EffectList); - InitUIntMap(&device->FilterMap, INT_MAX); + VECTOR_INIT(device->FilterList); for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) { @@ -4524,6 +4525,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN almtx_init(&device->BackendLock, almtx_plain); almtx_init(&device->BufferLock, almtx_plain); almtx_init(&device->EffectLock, almtx_plain); + almtx_init(&device->FilterLock, almtx_plain); //Set output format device->NumUpdates = 0; diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index c1932e2e..e28b7b2b 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -163,21 +163,7 @@ typedef struct ALfilter { ALuint id; } ALfilter; -inline void LockFiltersRead(ALCdevice *device) -{ LockUIntMapRead(&device->FilterMap); } -inline void UnlockFiltersRead(ALCdevice *device) -{ UnlockUIntMapRead(&device->FilterMap); } -inline void LockFiltersWrite(ALCdevice *device) -{ LockUIntMapWrite(&device->FilterMap); } -inline void UnlockFiltersWrite(ALCdevice *device) -{ UnlockUIntMapWrite(&device->FilterMap); } - -inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); } -inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); } - -ALvoid ReleaseALFilters(ALCdevice *device); +void ReleaseALFilters(ALCdevice *device); #ifdef __cplusplus } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8908d93f..d21ec3b0 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -166,6 +166,7 @@ struct Compressor; struct ALCbackend; struct ALbuffer; struct ALeffect; +struct ALfilter; struct ALsource; struct ALcontextProps; struct ALlistenerProps; @@ -388,6 +389,12 @@ typedef struct EffectSubList { } EffectSubList; TYPEDEF_VECTOR(EffectSubList, vector_EffectSubList) +typedef struct FilterSubList { + ALuint64 FreeMask; + struct ALfilter *Filters; /* 64 */ +} FilterSubList; +TYPEDEF_VECTOR(FilterSubList, vector_FilterSubList) + typedef struct SourceSubList { ALuint64 FreeMask; struct ALsource *Sources; /* 64 */ @@ -496,7 +503,8 @@ struct ALCdevice_struct almtx_t EffectLock; // Map of Filters for this device - UIntMap FilterMap; + vector_FilterSubList FilterList; + almtx_t FilterLock; /* HRTF state and info */ struct DirectHrtfState *Hrtf; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 34f2f271..de8e3a8c 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -29,27 +29,40 @@ #include "alError.h" -extern inline void LockFiltersRead(ALCdevice *device); -extern inline void UnlockFiltersRead(ALCdevice *device); -extern inline void LockFiltersWrite(ALCdevice *device); -extern inline void UnlockFiltersWrite(ALCdevice *device); -extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); -extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline void ALfilterState_clear(ALfilterState *filter); extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); +static ALfilter *AllocFilter(ALCcontext *context); +static void FreeFilter(ALCdevice *device, ALfilter *filter); static void InitFilterParams(ALfilter *filter, ALenum type); +static inline void LockFilterList(ALCdevice *device) +{ almtx_lock(&device->FilterLock); } +static inline void UnlockFilterList(ALCdevice *device) +{ almtx_unlock(&device->FilterLock); } + +static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + FilterSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) + return NULL; + sublist = &VECTOR_ELEM(device->FilterList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; +} + AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) { - ALCdevice *device; ALCcontext *context; ALsizei cur = 0; - ALenum err; context = GetContextRef(); if(!context) return; @@ -57,28 +70,13 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d filters", n); - device = context->Device; for(cur = 0;cur < n;cur++) { - ALfilter *filter = al_calloc(16, sizeof(ALfilter)); + ALfilter *filter = AllocFilter(context); if(!filter) { alDeleteFilters(cur, filters); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Failed to allocate filter object"); - } - 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)); - al_free(filter); - - alDeleteFilters(cur, filters); - SETERR_GOTO(context, err, done, "Failed ot set filter ID"); + break; } filters[cur] = filter->id; @@ -99,7 +97,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) if(!context) return; device = context->Device; - LockFiltersWrite(device); + LockFilterList(device); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n); for(i = 0;i < n;i++) @@ -109,16 +107,12 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) } for(i = 0;i < n;i++) { - if((filter=RemoveFilter(device, filters[i])) == NULL) - continue; - FreeThunkEntry(filter->id); - - memset(filter, 0, sizeof(*filter)); - al_free(filter); + if((filter=LookupFilter(device, filters[i])) != NULL) + FreeFilter(device, filter); } done: - UnlockFiltersWrite(device); + UnlockFilterList(device); ALCcontext_DecRef(context); } @@ -130,10 +124,10 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) Context = GetContextRef(); if(!Context) return AL_FALSE; - LockFiltersRead(Context->Device); + LockFilterList(Context->Device); result = ((!filter || LookupFilter(Context->Device, filter)) ? AL_TRUE : AL_FALSE); - UnlockFiltersRead(Context->Device); + UnlockFilterList(Context->Device); ALCcontext_DecRef(Context); @@ -150,7 +144,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) if(!Context) return; Device = Context->Device; - LockFiltersWrite(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -169,7 +163,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) V(ALFilter,setParami)(Context, param, value); } } - UnlockFiltersWrite(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -191,7 +185,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v if(!Context) return; Device = Context->Device; - LockFiltersWrite(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -199,7 +193,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v /* Call the appropriate handler */ V(ALFilter,setParamiv)(Context, param, values); } - UnlockFiltersWrite(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -214,7 +208,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) if(!Context) return; Device = Context->Device; - LockFiltersWrite(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -222,7 +216,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) /* Call the appropriate handler */ V(ALFilter,setParamf)(Context, param, value); } - UnlockFiltersWrite(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -237,7 +231,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat if(!Context) return; Device = Context->Device; - LockFiltersWrite(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -245,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat /* Call the appropriate handler */ V(ALFilter,setParamfv)(Context, param, values); } - UnlockFiltersWrite(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -260,7 +254,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value if(!Context) return; Device = Context->Device; - LockFiltersRead(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -273,7 +267,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value V(ALFilter,getParami)(Context, param, value); } } - UnlockFiltersRead(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -295,7 +289,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu if(!Context) return; Device = Context->Device; - LockFiltersRead(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -303,7 +297,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu /* Call the appropriate handler */ V(ALFilter,getParamiv)(Context, param, values); } - UnlockFiltersRead(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -318,7 +312,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val if(!Context) return; Device = Context->Device; - LockFiltersRead(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -326,7 +320,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val /* Call the appropriate handler */ V(ALFilter,getParamf)(Context, param, value); } - UnlockFiltersRead(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -341,7 +335,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va if(!Context) return; Device = Context->Device; - LockFiltersRead(Device); + LockFilterList(Device); if((ALFilter=LookupFilter(Device, filter)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter); else @@ -349,7 +343,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va /* Call the appropriate handler */ V(ALFilter,getParamfv)(Context, param, values); } - UnlockFiltersRead(Device); + UnlockFilterList(Device); ALCcontext_DecRef(Context); } @@ -625,19 +619,99 @@ static void ALnullfilter_getParamfv(ALfilter *UNUSED(filter), ALCcontext *contex DEFINE_ALFILTER_VTABLE(ALnullfilter); -ALvoid ReleaseALFilters(ALCdevice *device) +static ALfilter *AllocFilter(ALCcontext *context) { - ALsizei i; - for(i = 0;i < device->FilterMap.size;i++) + ALCdevice *device = context->Device; + FilterSubList *sublist, *subend; + ALfilter *filter = NULL; + ALsizei lidx = 0; + ALsizei slidx; + + almtx_lock(&device->FilterLock); + sublist = VECTOR_BEGIN(device->FilterList); + subend = VECTOR_END(device->FilterList); + for(;sublist != subend;++sublist) + { + if(sublist->FreeMask) + { + slidx = CTZ64(sublist->FreeMask); + filter = sublist->Filters + slidx; + break; + } + ++lidx; + } + if(UNLIKELY(!filter)) { - ALfilter *temp = device->FilterMap.values[i]; - device->FilterMap.values[i] = NULL; + const FilterSubList empty_sublist = { 0, NULL }; + /* Don't allocate so many list entries that the 32-bit ID could + * overflow... + */ + if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) + { + almtx_unlock(&device->FilterLock); + return NULL; + } + lidx = (ALsizei)VECTOR_SIZE(device->FilterList); + VECTOR_PUSH_BACK(device->FilterList, empty_sublist); + sublist = &VECTOR_BACK(device->FilterList); + sublist->FreeMask = ~U64(0); + sublist->Filters = al_calloc(16, sizeof(ALfilter)*64); + if(UNLIKELY(!sublist->Filters)) + { + VECTOR_POP_BACK(device->FilterList); + almtx_unlock(&device->FilterLock); + return NULL; + } + + slidx = 0; + filter = sublist->Filters + slidx; + } + + memset(filter, 0, sizeof(*filter)); + InitFilterParams(filter, AL_FILTER_NULL); + + /* Add 1 to avoid filter ID 0. */ + filter->id = ((lidx<<6) | slidx) + 1; + + sublist->FreeMask &= ~(U64(1)<FilterLock); + + return filter; +} + +static void FreeFilter(ALCdevice *device, ALfilter *filter) +{ + ALuint id = filter->id - 1; + ALsizei lidx = id >> 6; + ALsizei slidx = id & 0x3f; + + memset(filter, 0, sizeof(*filter)); + + VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx; +} + +void ReleaseALFilters(ALCdevice *device) +{ + FilterSubList *sublist = VECTOR_BEGIN(device->FilterList); + FilterSubList *subend = VECTOR_END(device->FilterList); + size_t leftover = 0; + for(;sublist != subend;++sublist) + { + ALuint64 usemask = ~sublist->FreeMask; + while(usemask) + { + ALsizei idx = CTZ64(usemask); + ALfilter *filter = sublist->Filters + idx; - // Release filter structure - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(ALfilter)); - al_free(temp); + memset(filter, 0, sizeof(*filter)); + ++leftover; + + usemask &= ~(U64(1) << idx); + } + sublist->FreeMask = ~usemask; } + if(leftover > 0) + WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s"); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 58026aeb..01555b69 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -84,6 +84,20 @@ static inline ALbuffer *LookupBuffer(ALCdevice *device, ALuint id) return sublist->Buffers + slidx; } +static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) +{ + FilterSubList *sublist; + ALuint lidx = (id-1) >> 6; + ALsizei slidx = (id-1) & 0x3f; + + if(UNLIKELY(lidx >= VECTOR_SIZE(device->FilterList))) + return NULL; + sublist = &VECTOR_ELEM(device->FilterList, lidx); + if(UNLIKELY(sublist->FreeMask & (U64(1)<Filters + slidx; +} + static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { id--; @@ -894,10 +908,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DIRECT_FILTER: - LockFiltersRead(device); + almtx_lock(&device->FilterLock); if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) { - UnlockFiltersRead(device); + almtx_unlock(&device->FilterLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", *values); } @@ -918,7 +932,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Direct.GainLF = filter->GainLF; Source->Direct.LFReference = filter->LFReference; } - UnlockFiltersRead(device); + almtx_unlock(&device->FilterLock); DO_UPDATEPROPS(); return AL_TRUE; @@ -992,10 +1006,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p almtx_unlock(&Context->EffectSlotLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); } - LockFiltersRead(device); + almtx_lock(&device->FilterLock); if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) { - UnlockFiltersRead(device); + almtx_unlock(&device->FilterLock); almtx_unlock(&Context->EffectSlotLock); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); @@ -1018,7 +1032,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].GainLF = filter->GainLF; Source->Send[values[1]].LFReference = filter->LFReference; } - UnlockFiltersRead(device); + almtx_unlock(&device->FilterLock); if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { -- cgit v1.2.3 From e12059a31186605ce2ed534ba42004edf3df5a6b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 20:04:21 -0800 Subject: Fix error reporting for resource generation --- OpenAL32/alBuffer.c | 2 ++ OpenAL32/alEffect.c | 8 ++++---- OpenAL32/alFilter.c | 8 ++++---- OpenAL32/alSource.c | 10 ++++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index a8ad855f..10f661f6 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -1258,6 +1258,7 @@ static ALbuffer *AllocBuffer(ALCcontext *context) if(UNLIKELY(VECTOR_SIZE(device->BufferList) >= 1<<25)) { almtx_unlock(&device->BufferLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many buffers allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(device->BufferList); @@ -1269,6 +1270,7 @@ static ALbuffer *AllocBuffer(ALCcontext *context) { VECTOR_POP_BACK(device->BufferList); almtx_unlock(&device->BufferLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate buffer batch"); return NULL; } diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 797687fa..0fa2ee08 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -83,9 +83,8 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effects", n); - - for(cur = 0;cur < n;cur++) + alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n); + else for(cur = 0;cur < n;cur++) { ALeffect *effect = AllocEffect(context); if(!effect) @@ -96,7 +95,6 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) effects[cur] = effect->id; } -done: ALCcontext_DecRef(context); } @@ -407,6 +405,7 @@ static ALeffect *AllocEffect(ALCcontext *context) if(UNLIKELY(VECTOR_SIZE(device->EffectList) >= 1<<25)) { almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(device->EffectList); @@ -418,6 +417,7 @@ static ALeffect *AllocEffect(ALCcontext *context) { VECTOR_POP_BACK(device->EffectList); almtx_unlock(&device->EffectLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch"); return NULL; } diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index de8e3a8c..7a3513c3 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -68,9 +68,8 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d filters", n); - - for(cur = 0;cur < n;cur++) + alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n); + else for(cur = 0;cur < n;cur++) { ALfilter *filter = AllocFilter(context); if(!filter) @@ -82,7 +81,6 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) filters[cur] = filter->id; } -done: ALCcontext_DecRef(context); } @@ -649,6 +647,7 @@ static ALfilter *AllocFilter(ALCcontext *context) if(UNLIKELY(VECTOR_SIZE(device->FilterList) >= 1<<25)) { almtx_unlock(&device->FilterLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(device->FilterList); @@ -660,6 +659,7 @@ static ALfilter *AllocFilter(ALCcontext *context) { VECTOR_POP_BACK(device->FilterList); almtx_unlock(&device->FilterLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch"); return NULL; } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 01555b69..19017e51 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1807,19 +1807,18 @@ AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) if(!context) return; if(!(n >= 0)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d sources", n); - for(cur = 0;cur < n;cur++) + alSetError(context, AL_INVALID_VALUE, "Generating %d sources", n); + else for(cur = 0;cur < n;cur++) { ALsource *source = AllocSource(context); if(!source) { alDeleteSources(cur, sources); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Failed to allocate source object"); + break; } sources[cur] = source->id; } -done: ALCcontext_DecRef(context); } @@ -3685,6 +3684,7 @@ static ALsource *AllocSource(ALCcontext *context) if(context->NumSources >= device->SourcesMax) { almtx_unlock(&context->SourceLock); + alSetError(context, AL_OUT_OF_MEMORY, "Exceeding %u source limit", device->SourcesMax); return NULL; } sublist = VECTOR_BEGIN(context->SourceList); @@ -3708,6 +3708,7 @@ static ALsource *AllocSource(ALCcontext *context) if(UNLIKELY(VECTOR_SIZE(context->SourceList) >= 1<<25)) { almtx_unlock(&device->BufferLock); + alSetError(context, AL_OUT_OF_MEMORY, "Too many sources allocated"); return NULL; } lidx = (ALsizei)VECTOR_SIZE(context->SourceList); @@ -3719,6 +3720,7 @@ static ALsource *AllocSource(ALCcontext *context) { VECTOR_POP_BACK(context->SourceList); almtx_unlock(&context->SourceLock); + alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate source batch"); return NULL; } -- cgit v1.2.3 From f16ece6048ebe3e81b892476fa0dc66f4091a4a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 21:16:24 -0800 Subject: Move some inline functions into a header instead of copying them Unfortunately does not include the Lookup* functions, which need the full type declaration to offset the pointer. --- OpenAL32/Include/alMain.h | 17 +++++++++++++---- OpenAL32/alAuxEffectSlot.c | 14 ++++++-------- OpenAL32/alEffect.c | 11 ++++------- OpenAL32/alFilter.c | 7 ++----- OpenAL32/alSource.c | 22 +++++++++++----------- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d21ec3b0..5b31696e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -723,10 +723,19 @@ inline ALint GetChannelIdxByName(const RealMixParams *real, enum Channel chan) { return GetChannelIndex(real->ChannelName, chan); } -inline void LockBufferList(ALCdevice *device) -{ almtx_lock(&device->BufferLock); } -inline void UnlockBufferList(ALCdevice *device) -{ almtx_unlock(&device->BufferLock); } +inline void LockBufferList(ALCdevice *device) { almtx_lock(&device->BufferLock); } +inline void UnlockBufferList(ALCdevice *device) { almtx_unlock(&device->BufferLock); } + +inline void LockEffectList(ALCdevice *device) { almtx_lock(&device->EffectLock); } +inline void UnlockEffectList(ALCdevice *device) { almtx_unlock(&device->EffectLock); } + +inline void LockFilterList(ALCdevice *device) { almtx_lock(&device->FilterLock); } +inline void UnlockFilterList(ALCdevice *device) { almtx_unlock(&device->FilterLock); } + +inline void LockEffectSlotList(ALCcontext *context) +{ almtx_lock(&context->EffectSlotLock); } +inline void UnlockEffectSlotList(ALCcontext *context) +{ almtx_unlock(&context->EffectSlotLock); } vector_al_string SearchDataFiles(const char *match, const char *subdir); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 30ca097f..70025409 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -36,6 +36,9 @@ #include "almalloc.h" +extern inline void LockEffectSlotList(ALCcontext *context); +extern inline void UnlockEffectSlotList(ALCcontext *context); + static UIntMap EffectStateFactoryMap; static inline ALeffectStateFactory *getFactoryByType(ALenum type) { @@ -48,11 +51,6 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type) static void ALeffectState_IncRef(ALeffectState *state); -static inline void LockEffectSlotList(ALCcontext *context) -{ almtx_lock(&context->EffectSlotLock); } -static inline void UnlockEffectSlotList(ALCcontext *context) -{ almtx_unlock(&context->EffectSlotLock); } - static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { id--; @@ -275,15 +273,15 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param case AL_EFFECTSLOT_EFFECT: device = context->Device; - almtx_lock(&device->EffectLock); + LockEffectList(device); effect = (value ? LookupEffect(device, value) : NULL); if(!(value == 0 || effect != NULL)) { - almtx_unlock(&device->EffectLock); + UnlockEffectList(device); SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value); } err = InitializeEffect(context, slot, effect); - almtx_unlock(&device->EffectLock); + UnlockEffectList(device); if(err != AL_NO_ERROR) SETERR_GOTO(context, err, done, "Effect initialization failed"); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 0fa2ee08..e538433f 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -32,6 +32,10 @@ #include "alError.h" +extern inline void LockEffectList(ALCdevice *device); +extern inline void UnlockEffectList(ALCdevice *device); +extern inline ALboolean IsReverbEffect(ALenum type); + const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, @@ -48,17 +52,10 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { ALboolean DisabledEffects[MAX_EFFECTS]; -extern inline ALboolean IsReverbEffect(ALenum type); - static ALeffect *AllocEffect(ALCcontext *context); static void FreeEffect(ALCdevice *device, ALeffect *effect); static void InitEffectParams(ALeffect *effect, ALenum type); -static inline void LockEffectList(ALCdevice *device) -{ almtx_lock(&device->EffectLock); } -static inline void UnlockEffectList(ALCdevice *device) -{ almtx_unlock(&device->EffectLock); } - static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { EffectSubList *sublist; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 7a3513c3..de527fea 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -29,6 +29,8 @@ #include "alError.h" +extern inline void LockFilterList(ALCdevice *device); +extern inline void UnlockFilterList(ALCdevice *device); extern inline void ALfilterState_clear(ALfilterState *filter); extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); @@ -39,11 +41,6 @@ static ALfilter *AllocFilter(ALCcontext *context); static void FreeFilter(ALCdevice *device, ALfilter *filter); static void InitFilterParams(ALfilter *filter, ALenum type); -static inline void LockFilterList(ALCdevice *device) -{ almtx_lock(&device->FilterLock); } -static inline void UnlockFilterList(ALCdevice *device) -{ almtx_unlock(&device->FilterLock); } - static inline ALfilter *LookupFilter(ALCdevice *device, ALuint id) { FilterSubList *sublist; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 19017e51..b3e98bc9 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -908,10 +908,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_DIRECT_FILTER: - almtx_lock(&device->FilterLock); + LockFilterList(device); if(!(*values == 0 || (filter=LookupFilter(device, *values)) != NULL)) { - almtx_unlock(&device->FilterLock); + UnlockFilterList(device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", *values); } @@ -932,7 +932,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Direct.GainLF = filter->GainLF; Source->Direct.LFReference = filter->LFReference; } - almtx_unlock(&device->FilterLock); + UnlockFilterList(device); DO_UPDATEPROPS(); return AL_TRUE; @@ -994,23 +994,23 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER: - almtx_lock(&Context->EffectSlotLock); + LockEffectSlotList(Context); if(!(values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL)) { - almtx_unlock(&Context->EffectSlotLock); + UnlockEffectSlotList(Context); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid effect ID %u", values[0]); } if(!((ALuint)values[1] < (ALuint)device->NumAuxSends)) { - almtx_unlock(&Context->EffectSlotLock); + UnlockEffectSlotList(Context); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid send %u", values[1]); } - almtx_lock(&device->FilterLock); + LockFilterList(device); if(!(values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL)) { - almtx_unlock(&device->FilterLock); - almtx_unlock(&Context->EffectSlotLock); + UnlockFilterList(device); + UnlockEffectSlotList(Context); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid filter ID %u", values[2]); } @@ -1032,7 +1032,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].GainLF = filter->GainLF; Source->Send[values[1]].LFReference = filter->LFReference; } - almtx_unlock(&device->FilterLock); + UnlockFilterList(device); if(slot != Source->Send[values[1]].Slot && IsPlayingOrPaused(Source)) { @@ -1059,7 +1059,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->Send[values[1]].Slot = slot; DO_UPDATEPROPS(); } - almtx_unlock(&Context->EffectSlotLock); + UnlockEffectSlotList(Context); return AL_TRUE; -- cgit v1.2.3 From 0cd61fd197394bbbc867f1df87ea2f951f49822d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 23:07:29 -0800 Subject: Don't allocate more effect slots than allowed --- OpenAL32/alAuxEffectSlot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 70025409..f5362e94 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -84,6 +84,7 @@ static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) { + ALCdevice *device; ALCcontext *context; ALeffectslot **tmpslots = NULL; ALsizei cur; @@ -96,7 +97,14 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); + device = context->Device; LockEffectSlotList(context); + if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) > (ALuint)n) + { + UnlockEffectSlotList(context); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit", + device->AuxiliaryEffectSlotMax); + } for(cur = 0;cur < n;cur++) { ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); -- cgit v1.2.3 From 0051ebace0c419d873c1ebbe615c483c0124e70e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jan 2018 23:50:04 -0800 Subject: Don't bother with a return value that's never used --- OpenAL32/Include/alEffect.h | 6 +++--- OpenAL32/alEffect.c | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 30055f1f..4469349c 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -169,10 +169,10 @@ typedef struct ALeffect { inline ALboolean IsReverbEffect(ALenum type) { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } -ALenum InitEffect(ALeffect *effect); -ALvoid ReleaseALEffects(ALCdevice *device); +void InitEffect(ALeffect *effect); +void ReleaseALEffects(ALCdevice *device); -ALvoid LoadReverbPreset(const char *name, ALeffect *effect); +void LoadReverbPreset(const char *name, ALeffect *effect); #ifdef __cplusplus } diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index e538433f..39f6f330 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -366,10 +366,9 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va } -ALenum InitEffect(ALeffect *effect) +void InitEffect(ALeffect *effect) { InitEffectParams(effect, AL_EFFECT_NULL); - return AL_NO_ERROR; } static ALeffect *AllocEffect(ALCcontext *context) @@ -445,7 +444,7 @@ static void FreeEffect(ALCdevice *device, ALeffect *effect) VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; } -ALvoid ReleaseALEffects(ALCdevice *device) +void ReleaseALEffects(ALCdevice *device) { EffectSubList *sublist = VECTOR_BEGIN(device->EffectList); EffectSubList *subend = VECTOR_END(device->EffectList); @@ -740,7 +739,7 @@ static const struct { }; #undef DECL -ALvoid LoadReverbPreset(const char *name, ALeffect *effect) +void LoadReverbPreset(const char *name, ALeffect *effect) { size_t i; -- cgit v1.2.3 From dcc5a10c7b8bbe6be82c992b6540fd1ad745b7a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 00:10:12 -0800 Subject: Use a fixed array for the effect state factory list --- Alc/ALc.c | 4 --- OpenAL32/Include/alAuxEffectSlot.h | 3 --- OpenAL32/alAuxEffectSlot.c | 52 ++++++++++++++++++-------------------- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7ec5ec8d..ea387c6d 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1127,8 +1127,6 @@ static void alc_initconfig(void) } while(next++); } - InitEffectFactoryMap(); - InitEffect(&DefaultEffect); str = getenv("ALSOFT_DEFAULT_REVERB"); if((str && str[0]) || ConfigValueStr(NULL, NULL, "default-reverb", &str)) @@ -1229,8 +1227,6 @@ 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) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index e4e954a0..aa3a0118 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -171,9 +171,6 @@ ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void); ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); -void InitEffectFactoryMap(void); -void DeinitEffectFactoryMap(void); - void ALeffectState_DecRef(ALeffectState *state); #ifdef __cplusplus diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index f5362e94..cd028bb0 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -39,12 +39,32 @@ extern inline void LockEffectSlotList(ALCcontext *context); extern inline void UnlockEffectSlotList(ALCcontext *context); -static UIntMap EffectStateFactoryMap; +static const struct { + ALenum Type; + ALeffectStateFactory* (*GetFactory)(void); +} FactoryList[] = { + { AL_EFFECT_NULL, ALnullStateFactory_getFactory }, + { AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory }, + { AL_EFFECT_REVERB, ALreverbStateFactory_getFactory }, + { AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory }, + { AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory }, + { AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory }, + { AL_EFFECT_ECHO, ALechoStateFactory_getFactory }, + { AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory }, + { AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory }, + { AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory } +}; + static inline ALeffectStateFactory *getFactoryByType(ALenum type) { - ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type); - if(getFactory != NULL) - return getFactory(); + size_t i; + for(i = 0;i < COUNTOF(FactoryList);i++) + { + if(FactoryList[i].Type == type) + return FactoryList[i].GetFactory(); + } return NULL; } @@ -517,30 +537,6 @@ done: } -void InitEffectFactoryMap(void) -{ - InitUIntMap(&EffectStateFactoryMap, INT_MAX); - - 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_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(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect) { ALCdevice *Device = Context->Device; -- cgit v1.2.3 From d1da9f1f679e94b3aa05c9d9d981c63e145399a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 00:53:21 -0800 Subject: Remove some now-unused NoLock function variants --- common/uintmap.c | 132 ------------------------------------------------------- common/uintmap.h | 17 +++---- 2 files changed, 5 insertions(+), 144 deletions(-) diff --git a/common/uintmap.c b/common/uintmap.c index be628a5f..18d52d64 100644 --- a/common/uintmap.c +++ b/common/uintmap.c @@ -119,81 +119,6 @@ ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) return AL_NO_ERROR; } -ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value) -{ - ALsizei pos = 0; - - if(map->size > 0) - { - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(!(map->keys[i] < key)) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - } - - if(pos == map->size || map->keys[pos] != key) - { - if(map->size >= map->limit) - return AL_OUT_OF_MEMORY; - - if(map->size == map->capacity) - { - ALuint *keys = NULL; - ALvoid **values; - ALsizei newcap, keylen; - - newcap = (map->capacity ? (map->capacity<<1) : 4); - if(map->limit > 0 && newcap > map->limit) - newcap = map->limit; - if(newcap > map->capacity) - { - /* Round the memory size for keys up to a multiple of the - * pointer size. - */ - keylen = newcap * sizeof(map->keys[0]); - keylen += sizeof(map->values[0]) - 1; - keylen -= keylen%sizeof(map->values[0]); - - keys = al_malloc(16, keylen + newcap*sizeof(map->values[0])); - } - if(!keys) - return AL_OUT_OF_MEMORY; - values = (ALvoid**)((ALbyte*)keys + keylen); - - if(map->keys) - { - memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); - memcpy(values, map->values, map->size*sizeof(map->values[0])); - } - al_free(map->keys); - map->keys = keys; - map->values = values; - map->capacity = newcap; - } - - if(pos < map->size) - { - memmove(&map->keys[pos+1], &map->keys[pos], - (map->size-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos+1], &map->values[pos], - (map->size-pos)*sizeof(map->values[0])); - } - map->size++; - } - map->keys[pos] = key; - map->values[pos] = value; - - return AL_NO_ERROR; -} - ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) { ALvoid *ptr = NULL; @@ -230,40 +155,6 @@ ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) return ptr; } -ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key) -{ - ALvoid *ptr = NULL; - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(!(map->keys[i] < key)) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - { - ptr = map->values[pos]; - if(pos < map->size-1) - { - memmove(&map->keys[pos], &map->keys[pos+1], - (map->size-1-pos)*sizeof(map->keys[0])); - memmove(&map->values[pos], &map->values[pos+1], - (map->size-1-pos)*sizeof(map->values[0])); - } - map->size--; - } - } - return ptr; -} - ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) { ALvoid *ptr = NULL; @@ -289,26 +180,3 @@ ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) ReadUnlock(&map->lock); return ptr; } - -ALvoid *LookupUIntMapKeyNoLock(UIntMap *map, ALuint key) -{ - if(map->size > 0) - { - ALsizei pos = 0; - ALsizei count = map->size; - do { - ALsizei step = count>>1; - ALsizei i = pos+step; - if(!(map->keys[i] < key)) - count = step; - else - { - pos = i+1; - count -= step+1; - } - } while(count > 0); - if(pos < map->size && map->keys[pos] == key) - return map->values[pos]; - } - return NULL; -} diff --git a/common/uintmap.h b/common/uintmap.h index 32cd1eaa..32868653 100644 --- a/common/uintmap.h +++ b/common/uintmap.h @@ -26,20 +26,13 @@ typedef struct UIntMap { void InitUIntMap(UIntMap *map, ALsizei limit); void ResetUIntMap(UIntMap *map); ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); -ALenum InsertUIntMapEntryNoLock(UIntMap *map, ALuint key, ALvoid *value); ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); -ALvoid *RemoveUIntMapKeyNoLock(UIntMap *map, ALuint key); ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); -ALvoid *LookupUIntMapKeyNoLock(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); } + +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); } #ifdef __cplusplus } -- cgit v1.2.3 From 38a3ba74d4e078866678619588c7535d90ad52a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 13:13:40 -0800 Subject: Report the problem value for global state errors --- OpenAL32/alState.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index d436e7a7..d4f3c6cf 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -88,7 +88,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid enable property"); + alSetError(context, AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); } WriteUnlock(&context->PropLock); @@ -111,7 +111,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid disable property"); + alSetError(context, AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); } WriteUnlock(&context->PropLock); @@ -133,7 +133,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property"); + alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); } ALCcontext_DecRef(context); @@ -190,7 +190,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid boolean property"); + alSetError(context, AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -241,7 +241,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid double property"); + alSetError(context, AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -292,7 +292,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid float property"); + alSetError(context, AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -343,7 +343,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -394,7 +394,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -420,7 +420,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid pointer property"); + alSetError(context, AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -456,7 +456,7 @@ AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid boolean-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -491,7 +491,7 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid double-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -526,7 +526,7 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid float-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -561,7 +561,7 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -596,7 +596,7 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid integer64-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -625,7 +625,7 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values) switch(pname) { default: - alSetError(context, AL_INVALID_VALUE, "Invalid pointer-vector property"); + alSetError(context, AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -682,7 +682,7 @@ AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) break; default: - alSetError(context, AL_INVALID_VALUE, "Invalid string property"); + alSetError(context, AL_INVALID_VALUE, "Invalid string property 0x%04x", pname); } ALCcontext_DecRef(context); @@ -697,7 +697,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) if(!context) return; if(!(value >= 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Doppler factor out of range"); + alSetError(context, AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { WriteLock(&context->PropLock); @@ -729,7 +729,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) } if(!(value >= 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Doppler velocity out of range"); + alSetError(context, AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { WriteLock(&context->PropLock); @@ -749,7 +749,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) if(!context) return; if(!(value > 0.0f && isfinite(value))) - alSetError(context, AL_INVALID_VALUE, "Speed of sound out of range"); + alSetError(context, AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { WriteLock(&context->PropLock); @@ -772,7 +772,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) value == AL_LINEAR_DISTANCE || value == AL_LINEAR_DISTANCE_CLAMPED || value == AL_EXPONENT_DISTANCE || value == AL_EXPONENT_DISTANCE_CLAMPED || value == AL_NONE)) - alSetError(context, AL_INVALID_VALUE, "Distance model out of range"); + alSetError(context, AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { WriteLock(&context->PropLock); @@ -830,7 +830,8 @@ AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index) { case AL_RESAMPLER_NAME_SOFT: if(index < 0 || (size_t)index >= COUNTOF(ResamplerNames)) - SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index out of range"); + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Resampler name index %d out of range", + index); value = ResamplerNames[index]; break; -- cgit v1.2.3 From 782eb650c73fe01d1008a2a1bb9da56b65211eff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 13:18:33 -0800 Subject: Use std::array instead of a plain array in alffplay --- examples/alffplay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 6eedcd76..039f5d68 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -704,16 +704,16 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui int AudioState::handler() { - const ALenum types[5] = { + const std::array types{{ AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT - }; + }}; std::unique_lock lock(mSrcMutex); ALenum fmt; if(alEventControlSOFT) { - alEventControlSOFT(5, types, AL_TRUE); + alEventControlSOFT(types.size(), types.data(), AL_TRUE); alEventCallbackSOFT(EventCallback, this); } @@ -948,7 +948,7 @@ finish: if(alEventControlSOFT) { - alEventControlSOFT(5, types, AL_FALSE); + alEventControlSOFT(types.size(), types.data(), AL_FALSE); alEventCallbackSOFT(nullptr, nullptr); } -- cgit v1.2.3 From c2710ffe87dae7d292e77ed9663783e9d5c227dc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 16:58:41 -0800 Subject: Make EnabledEvts atomic --- Alc/ALc.c | 2 +- OpenAL32/Include/alMain.h | 2 +- OpenAL32/alError.c | 6 ++++-- OpenAL32/alState.c | 6 ++++-- OpenAL32/event.c | 19 +++++++++++++++++-- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ea387c6d..21cabf5f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2554,7 +2554,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); almtx_init(&Context->EventLock, almtx_plain); - Context->EnabledEvts = 0; + ATOMIC_INIT(&Context->EnabledEvts, 0); Context->EventCb = NULL; Context->EventParam = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5b31696e..ef5ad0e9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -665,7 +665,7 @@ struct ALCcontext_struct { ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; almtx_t EventLock; - ALbitfieldSOFT EnabledEvts; + ATOMIC(ALbitfieldSOFT) EnabledEvts; ALEVENTPROCSOFT EventCb; void *EventParam; diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index e3909742..22aed458 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -72,10 +72,12 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) } ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode); - if((context->EnabledEvts&EventType_Error)) + if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error)) { + ALbitfieldSOFT enabledevts; almtx_lock(&context->EventLock); - if((context->EnabledEvts&EventType_Error) && context->EventCb) + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + if((enabledevts&EventType_Error) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, context->EventParam); almtx_unlock(&context->EventLock); diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index d4f3c6cf..10fce3b5 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -716,13 +716,15 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) context = GetContextRef(); if(!context) return; - if((context->EnabledEvts&EventType_Deprecated)) + if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Deprecated)) { static const ALCchar msg[] = "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen = (ALsizei)strlen(msg); + ALbitfieldSOFT enabledevts; almtx_lock(&context->EventLock); - if((context->EnabledEvts&EventType_Deprecated) && context->EventCb) + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + if((enabledevts&EventType_Deprecated) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, context->EventParam); almtx_unlock(&context->EventLock); diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 3b70c9f3..93d68d7a 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -39,9 +39,24 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A almtx_lock(&context->EventLock); if(enable) - context->EnabledEvts |= flags; + { + ALbitfieldSOFT enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, + almemory_order_acq_rel, almemory_order_acquire) == 0) + { + /* enabledevts is (re-)filled with the current value on failure, so + * just try again. + */ + } + } else - context->EnabledEvts &= ~flags; + { + ALbitfieldSOFT enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, + almemory_order_acq_rel, almemory_order_acquire) == 0) + { + } + } almtx_unlock(&context->EventLock); done: -- cgit v1.2.3 From a24a22c39aa3ee474197f4f9b12e4351fc836b39 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 17:56:47 -0800 Subject: Fix the effect slot limit check --- OpenAL32/alAuxEffectSlot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index cd028bb0..5400a914 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -119,7 +119,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo device = context->Device; LockEffectSlotList(context); - if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) > (ALuint)n) + if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n) { UnlockEffectSlotList(context); SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit", -- cgit v1.2.3 From 328fd7329d1ae1554452d2d4b0384173c0f47079 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 18:03:54 -0800 Subject: Combine common initialization code into a function --- Alc/ALc.c | 248 ++++++++++++++++++++++++++------------------------------------ 1 file changed, 105 insertions(+), 143 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 21cabf5f..f9f4b29c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2364,6 +2364,64 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_NO_ERROR; } + +static void InitDevice(ALCdevice *device) +{ + ALsizei i; + + device->Flags = 0; + device->Render_Mode = NormalRender; + device->AvgSpeakerDist = 0.0f; + + ATOMIC_INIT(&device->ContextList, NULL); + + device->ClockBase = 0; + device->SamplesDone = 0; + + device->SourcesMax = 0; + device->AuxiliaryEffectSlotMax = 0; + device->NumAuxSends = 0; + + device->Dry.Buffer = NULL; + device->Dry.NumChannels = 0; + device->FOAOut.Buffer = NULL; + device->FOAOut.NumChannels = 0; + device->RealOut.Buffer = NULL; + device->RealOut.NumChannels = 0; + + AL_STRING_INIT(device->DeviceName); + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + device->ChannelDelay[i].Gain = 1.0f; + device->ChannelDelay[i].Length = 0; + device->ChannelDelay[i].Buffer = NULL; + } + + AL_STRING_INIT(device->HrtfName); + VECTOR_INIT(device->HrtfList); + device->HrtfHandle = NULL; + device->Hrtf = NULL; + device->Bs2b = NULL; + device->Uhj_Encoder = NULL; + device->AmbiDecoder = NULL; + device->AmbiUp = NULL; + device->Stablizer = NULL; + device->Limiter = NULL; + + VECTOR_INIT(device->BufferList); + almtx_init(&device->BufferLock, almtx_plain); + + VECTOR_INIT(device->EffectList); + almtx_init(&device->EffectLock, almtx_plain); + + VECTOR_INIT(device->FilterList); + almtx_init(&device->FilterLock, almtx_plain); + + almtx_init(&device->BackendLock, almtx_plain); + device->Backend = NULL; +} + /* FreeDevice * * Frees the device structure, and destroys any objects the app failed to @@ -2375,9 +2433,12 @@ static ALCvoid FreeDevice(ALCdevice *device) TRACE("%p\n", device); - V0(device->Backend,close)(); - DELETE_OBJ(device->Backend); - device->Backend = NULL; + if(device->Backend) + { + V0(device->Backend,close)(); + DELETE_OBJ(device->Backend); + device->Backend = NULL; + } almtx_destroy(&device->BackendLock); @@ -3931,7 +3992,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) const ALCchar *fmt; ALCdevice *device; ALCenum err; - ALCsizei i; DO_INITCONFIG(); @@ -3966,43 +4026,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Type = Playback; ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - device->Flags = 0; - device->Bs2b = NULL; - device->Uhj_Encoder = NULL; - device->Hrtf = NULL; - device->HrtfHandle = NULL; - VECTOR_INIT(device->HrtfList); - AL_STRING_INIT(device->HrtfName); - device->Render_Mode = NormalRender; - AL_STRING_INIT(device->DeviceName); - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - device->Limiter = NULL; - device->AvgSpeakerDist = 0.0f; - - ATOMIC_INIT(&device->ContextList, NULL); - - device->ClockBase = 0; - device->SamplesDone = 0; - - device->SourcesMax = 256; - device->AuxiliaryEffectSlotMax = 64; - device->NumAuxSends = DEFAULT_SENDS; - - VECTOR_INIT(device->BufferList); - VECTOR_INIT(device->EffectList); - VECTOR_INIT(device->FilterList); - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } + InitDevice(device); //Set output format device->FmtChans = DevFmtChannelsDefault; @@ -4014,15 +4038,9 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumUpdates = 3; device->UpdateSize = 1024; - 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; - } - + device->SourcesMax = 256; + device->AuxiliaryEffectSlotMax = 64; + device->NumAuxSends = DEFAULT_SENDS; if(ConfigValueStr(deviceName, NULL, "channels", &fmt)) { @@ -4116,18 +4134,24 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + factory = PlaybackBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Playback); + if(!device->Backend) + { + FreeDevice(device); + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + // Find a playback device to open if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { DELETE_OBJ(device->Backend); - al_free(device); + device->Backend = NULL; + FreeDevice(device); alcSetError(NULL, err); return NULL; } - almtx_init(&device->BackendLock, almtx_plain); - almtx_init(&device->BufferLock, almtx_plain); - almtx_init(&device->EffectLock, almtx_plain); - almtx_init(&device->FilterLock, almtx_plain); if(ConfigValueStr(alstr_get_cstr(device->DeviceName), NULL, "ambi-format", &fmt)) { @@ -4229,7 +4253,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCbackendFactory *factory; ALCdevice *device = NULL; ALCenum err; - ALCsizei i; DO_INITCONFIG(); @@ -4260,49 +4283,18 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Connected = ALC_TRUE; device->Type = Capture; - device->Hrtf = NULL; - device->HrtfHandle = NULL; - VECTOR_INIT(device->HrtfList); - AL_STRING_INIT(device->HrtfName); + InitDevice(device); - AL_STRING_INIT(device->DeviceName); - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - - VECTOR_INIT(device->BufferList); - VECTOR_INIT(device->EffectList); - VECTOR_INIT(device->FilterList); - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } - - 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_FREQUENCY_REQUEST; - device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) { - al_free(device); + FreeDevice(device); alcSetError(NULL, ALC_INVALID_ENUM); return NULL; } + device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; device->IsHeadphones = AL_FALSE; device->AmbiOrder = 0; device->AmbiLayout = AmbiLayout_Default; @@ -4311,20 +4303,27 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->UpdateSize = samples; device->NumUpdates = 1; + factory = CaptureBackend.getFactory(); + device->Backend = V(factory,createBackend)(device, ALCbackend_Capture); + if(!device->Backend) + { + FreeDevice(device); + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + TRACE("Capture format: %s, %s, %uhz, %u update size x%d\n", DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->NumUpdates ); if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { - al_free(device); + DELETE_OBJ(device->Backend); + device->Backend = NULL; + FreeDevice(device); alcSetError(NULL, err); return NULL; } - almtx_init(&device->BackendLock, almtx_plain); - almtx_init(&device->BufferLock, almtx_plain); - almtx_init(&device->EffectLock, almtx_plain); - almtx_init(&device->FilterLock, almtx_plain); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); @@ -4448,7 +4447,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN { ALCbackendFactory *factory; ALCdevice *device; - ALCsizei i; DO_INITCONFIG(); @@ -4472,57 +4470,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Type = Loopback; ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - device->Flags = 0; - device->Hrtf = NULL; - device->HrtfHandle = NULL; - VECTOR_INIT(device->HrtfList); - AL_STRING_INIT(device->HrtfName); - device->Bs2b = NULL; - device->Uhj_Encoder = NULL; - device->Render_Mode = NormalRender; - AL_STRING_INIT(device->DeviceName); - device->Dry.Buffer = NULL; - device->Dry.NumChannels = 0; - device->FOAOut.Buffer = NULL; - device->FOAOut.NumChannels = 0; - device->RealOut.Buffer = NULL; - device->RealOut.NumChannels = 0; - device->Limiter = NULL; - device->AvgSpeakerDist = 0.0f; - - ATOMIC_INIT(&device->ContextList, NULL); - - device->ClockBase = 0; - device->SamplesDone = 0; + InitDevice(device); device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; device->NumAuxSends = DEFAULT_SENDS; - VECTOR_INIT(device->BufferList); - VECTOR_INIT(device->EffectList); - VECTOR_INIT(device->FilterList); - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - device->ChannelDelay[i].Gain = 1.0f; - device->ChannelDelay[i].Length = 0; - device->ChannelDelay[i].Buffer = NULL; - } - - 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; - } - almtx_init(&device->BackendLock, almtx_plain); - almtx_init(&device->BufferLock, almtx_plain); - almtx_init(&device->EffectLock, almtx_plain); - almtx_init(&device->FilterLock, almtx_plain); - //Set output format device->NumUpdates = 0; device->UpdateSize = 0; @@ -4548,6 +4501,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->NumStereoSources = 1; device->NumMonoSources = device->SourcesMax - device->NumStereoSources; + 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; + } + // Open the "backend" V(device->Backend,open)("Loopback"); -- cgit v1.2.3 From a042dbf30524429b49adb63efda35f53054ae924 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 28 Jan 2018 23:32:28 -0800 Subject: Call the backend close method in the destructor --- Alc/backends/alsa.c | 20 ++++++++++++++++++-- Alc/backends/coreaudio.c | 1 + Alc/backends/dsound.c | 25 ++++++++++++++++++++----- Alc/backends/mmdevapi.c | 10 ++++++++++ Alc/backends/opensl.c | 35 ++++++----------------------------- Alc/backends/oss.c | 22 ++++++++++++++++++---- Alc/backends/portaudio.c | 18 ++++-------------- Alc/backends/pulseaudio.c | 28 ++++++++++++++++------------ Alc/backends/qsa.c | 22 ++++++++++++++++++---- Alc/backends/sndio.c | 7 +++---- Alc/backends/solaris.c | 7 +++---- Alc/backends/wave.c | 7 ++++++- Alc/backends/winmm.c | 2 ++ 13 files changed, 125 insertions(+), 79 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index fb5a4446..27d36560 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -446,7 +446,7 @@ static int ALCplaybackAlsa_mixerProc(void *ptr); static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr); static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); -static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct) +static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name); static void ALCplaybackAlsa_close(ALCplaybackAlsa *self); static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self); @@ -468,6 +468,12 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); } +void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) +{ + ALCplaybackAlsa_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static int ALCplaybackAlsa_mixerProc(void *ptr) { @@ -705,6 +711,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) static void ALCplaybackAlsa_close(ALCplaybackAlsa *self) { snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; } static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) @@ -973,7 +980,7 @@ typedef struct ALCcaptureAlsa { } ALCcaptureAlsa; static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); -static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct) +static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name); static void ALCcaptureAlsa_close(ALCcaptureAlsa *self); static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset) @@ -995,6 +1002,12 @@ static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); } +void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) +{ + ALCcaptureAlsa_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { @@ -1129,7 +1142,10 @@ error2: static void ALCcaptureAlsa_close(ALCcaptureAlsa *self) { snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; + ll_ringbuffer_free(self->ring); + self->ring = NULL; al_free(self->buffer); self->buffer = NULL; diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 2ee3fa54..bdd9b678 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -123,6 +123,7 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { + ALCcoreAudioPlayback_close(self); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 8a0a30cb..7760e39d 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -192,7 +192,7 @@ typedef struct ALCdsoundPlayback { static int ALCdsoundPlayback_mixerProc(void *ptr); static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); -static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, Destruct) +static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); static void ALCdsoundPlayback_close(ALCdsoundPlayback *self); static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self); @@ -214,6 +214,12 @@ static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *devi SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); } +static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) +{ + ALCdsoundPlayback_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) { @@ -399,9 +405,11 @@ static void ALCdsoundPlayback_close(ALCdsoundPlayback *self) IDirectSoundBuffer_Release(self->PrimaryBuffer); self->PrimaryBuffer = NULL; - IDirectSound_Release(self->DS); + if(self->DS) + IDirectSound_Release(self->DS); self->DS = NULL; - CloseHandle(self->NotifyEvent); + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); self->NotifyEvent = NULL; } @@ -661,7 +669,7 @@ typedef struct ALCdsoundCapture { } ALCdsoundCapture; static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); -static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, Destruct) +static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); static void ALCdsoundCapture_close(ALCdsoundCapture *self); static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset) @@ -682,6 +690,12 @@ static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); } +static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) +{ + ALCdsoundCapture_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName) { @@ -867,7 +881,8 @@ static void ALCdsoundCapture_close(ALCdsoundCapture *self) self->DSCbuffer = NULL; } - IDirectSoundCapture_Release(self->DSC); + if(self->DSC) + IDirectSoundCapture_Release(self->DSC); self->DSC = NULL; } diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 55d8ec54..899f73d4 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -587,6 +587,8 @@ static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self) { + ALCmmdevPlayback_close(self); + if(self->NotifyEvent != NULL) CloseHandle(self->NotifyEvent); self->NotifyEvent = NULL; @@ -840,6 +842,9 @@ static void ALCmmdevPlayback_close(ALCmmdevPlayback *self) { ThreadRequest req = { self->MsgEvent, 0 }; + if(!req.FinishedEvt) + return; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) (void)WaitForResponse(&req); @@ -1287,6 +1292,8 @@ static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) { + ALCmmdevCapture_close(self); + ll_ringbuffer_free(self->Ring); self->Ring = NULL; @@ -1573,6 +1580,9 @@ static void ALCmmdevCapture_close(ALCmmdevCapture *self) { ThreadRequest req = { self->MsgEvent, 0 }; + if(!req.FinishedEvt) + return; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) (void)WaitForResponse(&req); diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 4ec003d8..c1283111 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -194,21 +194,7 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) { - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - if(self->mOutputMix != NULL) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; + ALCopenslPlayback_close(self); alcnd_destroy(&self->mCond); @@ -409,10 +395,12 @@ static void ALCopenslPlayback_close(ALCopenslPlayback *self) VCALL0(self->mBufferQueueObj,Destroy)(); self->mBufferQueueObj = NULL; - VCALL0(self->mOutputMix,Destroy)(); + if(self->mOutputMix) + VCALL0(self->mOutputMix,Destroy)(); self->mOutputMix = NULL; - VCALL0(self->mEngineObj,Destroy)(); + if(self->mEngineObj) + VCALL0(self->mEngineObj,Destroy)(); self->mEngineObj = NULL; self->mEngine = NULL; } @@ -761,18 +749,7 @@ static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device static void ALCopenslCapture_Destruct(ALCopenslCapture *self) { - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; - + ALCopenslCapture_close(self); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 2ff7c72b..e88e5ff3 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -252,7 +252,7 @@ typedef struct ALCplaybackOSS { static int ALCplaybackOSS_mixerProc(void *ptr); static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); -static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct) +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name); static void ALCplaybackOSS_close(ALCplaybackOSS *self); static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self); @@ -342,6 +342,12 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) ATOMIC_INIT(&self->killNow, AL_FALSE); } +static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) +{ + ALCplaybackOSS_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) { struct oss_device *dev = &oss_playback; @@ -383,7 +389,8 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) static void ALCplaybackOSS_close(ALCplaybackOSS *self) { - close(self->fd); + if(self->fd != -1) + close(self->fd); self->fd = -1; } @@ -519,7 +526,7 @@ typedef struct ALCcaptureOSS { static int ALCcaptureOSS_recordProc(void *ptr); static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); -static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct) +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name); static void ALCcaptureOSS_close(ALCcaptureOSS *self); static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset) @@ -601,6 +608,12 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) ATOMIC_INIT(&self->killNow, AL_FALSE); } +static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) +{ + ALCcaptureOSS_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -728,7 +741,8 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) static void ALCcaptureOSS_close(ALCcaptureOSS *self) { - close(self->fd); + if(self->fd != -1) + close(self->fd); self->fd = -1; ll_ringbuffer_free(self->ring); diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index b793486f..58cf9762 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -165,10 +165,7 @@ static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) static void ALCportPlayback_Destruct(ALCportPlayback *self) { - if(self->stream) - Pa_CloseStream(self->stream); - self->stream = NULL; - + ALCportPlayback_close(self); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -255,7 +252,7 @@ retry_open: static void ALCportPlayback_close(ALCportPlayback *self) { - PaError err = Pa_CloseStream(self->stream); + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); self->stream = NULL; @@ -362,14 +359,7 @@ static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) static void ALCportCapture_Destruct(ALCportCapture *self) { - if(self->stream) - Pa_CloseStream(self->stream); - self->stream = NULL; - - if(self->ring) - ll_ringbuffer_free(self->ring); - self->ring = NULL; - + ALCportCapture_close(self); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -454,7 +444,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) static void ALCportCapture_close(ALCportCapture *self) { - PaError err = Pa_CloseStream(self->stream); + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); self->stream = NULL; diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 3208bf26..581f4c38 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -519,6 +519,7 @@ static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self) { + ALCpulsePlayback_close(self); AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -958,12 +959,13 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name static void ALCpulsePlayback_close(ALCpulsePlayback *self) { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - - alstr_clear(&self->device_name); + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = NULL; + self->context = NULL; + self->stream = NULL; + } } static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) @@ -1273,6 +1275,7 @@ static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device) static void ALCpulseCapture_Destruct(ALCpulseCapture *self) { + ALCpulseCapture_close(self); AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -1621,12 +1624,13 @@ fail: static void ALCpulseCapture_close(ALCpulseCapture *self) { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - - alstr_clear(&self->device_name); + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = NULL; + self->context = NULL; + self->stream = NULL; + } } static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self) diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 58193c96..e1bbf2c2 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -166,7 +166,7 @@ typedef struct PlaybackWrapper { } PlaybackWrapper; static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct) +static void PlaybackWrapper_Destruct(PlaybackWrapper *self); static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); static void PlaybackWrapper_close(PlaybackWrapper *self); static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); @@ -624,6 +624,12 @@ static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) self->ExtraData = NULL; } +static void PlaybackWrapper_Destruct(PlaybackWrapper *self) +{ + PlaybackWrapper_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) { return qsa_open_playback(self, name); @@ -631,7 +637,8 @@ static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) static void PlaybackWrapper_close(PlaybackWrapper *self) { - qsa_close_playback(self); + if(self->ExtraData) + qsa_close_playback(self); } static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) @@ -661,7 +668,7 @@ typedef struct CaptureWrapper { } CaptureWrapper; static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct) +static void CaptureWrapper_Destruct(CaptureWrapper *self); static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); static void CaptureWrapper_close(CaptureWrapper *self); static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) @@ -945,6 +952,12 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) self->ExtraData = NULL; } +static void CaptureWrapper_Destruct(CaptureWrapper *self) +{ + CaptureWrapper_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) { return qsa_open_capture(self, name); @@ -952,7 +965,8 @@ static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) static void CaptureWrapper_close(CaptureWrapper *self) { - qsa_close_capture(self); + if(self->ExtraData) + qsa_close_capture(self); } static ALCboolean CaptureWrapper_start(CaptureWrapper *self) diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 47e05353..436baf26 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -77,9 +77,7 @@ static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device) static void ALCsndioBackend_Destruct(ALCsndioBackend *self) { - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = NULL; + ALCsndioBackend_close(self); al_free(self->mix_data); self->mix_data = NULL; @@ -152,7 +150,8 @@ static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) static void ALCsndioBackend_close(ALCsndioBackend *self) { - sio_close(self->sndHandle); + if(self->sndHandle) + sio_close(self->sndHandle); self->sndHandle = NULL; } diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 59cc5ddc..3230b401 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -90,9 +90,7 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) { - if(self->fd != -1) - close(self->fd); - self->fd = -1; + ALCsolarisBackend_close(self); free(self->mix_data); self->mix_data = NULL; @@ -193,7 +191,8 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na static void ALCsolarisBackend_close(ALCsolarisBackend *self) { - close(self->fd); + if(self->fd != -1) + close(self->fd); self->fd = -1; } diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 1c502fd9..538ab5e6 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -84,7 +84,7 @@ typedef struct ALCwaveBackend { static int ALCwaveBackend_mixerProc(void *ptr); static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); -static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct) +static void ALCwaveBackend_Destruct(ALCwaveBackend *self); static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); static void ALCwaveBackend_close(ALCwaveBackend *self); static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); @@ -114,6 +114,11 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) self->killNow = 1; } +static void ALCwaveBackend_Destruct(ALCwaveBackend *self) +{ + ALCwaveBackend_close(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} static int ALCwaveBackend_mixerProc(void *ptr) { diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 0fcab458..885b624c 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -475,6 +475,7 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { + ALCwinmmCapture_close(self); if(self->InHdl) waveInClose(self->InHdl); self->InHdl = 0; @@ -664,6 +665,7 @@ static void ALCwinmmCapture_close(ALCwinmmCapture *self) int i; /* Tell the processing thread to quit and wait for it to do so. */ + if(self->killNow) return; self->killNow = AL_TRUE; PostThreadMessage(self->thread, WM_QUIT, 0, 0); -- cgit v1.2.3 From e7217760f39071c7aec542c8f3fbaad21c71924a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 29 Jan 2018 01:00:53 -0800 Subject: Don't bother with an explicit stop backend method --- Alc/ALc.c | 9 +---- Alc/backends/alsa.c | 42 +++++++++++------------- Alc/backends/base.h | 3 -- Alc/backends/coreaudio.c | 11 ++----- Alc/backends/dsound.c | 82 ++++++++++++++++++++++----------------------- Alc/backends/jack.c | 15 --------- Alc/backends/loopback.c | 5 --- Alc/backends/mmdevapi.c | 84 ++++++++++++++++------------------------------- Alc/backends/null.c | 5 --- Alc/backends/opensl.c | 59 ++++++++++++++------------------- Alc/backends/oss.c | 34 ++++++++----------- Alc/backends/portaudio.c | 37 ++++++++------------- Alc/backends/pulseaudio.c | 42 +++++++++--------------- Alc/backends/qsa.c | 22 ++++--------- Alc/backends/sndio.c | 15 ++++----- Alc/backends/solaris.c | 13 +++----- Alc/backends/wave.c | 13 +++----- Alc/backends/winmm.c | 66 ++++++++++++++++--------------------- 18 files changed, 209 insertions(+), 348 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index f9f4b29c..53979704 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2434,11 +2434,8 @@ static ALCvoid FreeDevice(ALCdevice *device) TRACE("%p\n", device); if(device->Backend) - { - V0(device->Backend,close)(); DELETE_OBJ(device->Backend); - device->Backend = NULL; - } + device->Backend = NULL; almtx_destroy(&device->BackendLock); @@ -4146,8 +4143,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) // Find a playback device to open if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { - DELETE_OBJ(device->Backend); - device->Backend = NULL; FreeDevice(device); alcSetError(NULL, err); return NULL; @@ -4318,8 +4313,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ); if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { - DELETE_OBJ(device->Backend); - device->Backend = NULL; FreeDevice(device); alcSetError(NULL, err); return NULL; diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 27d36560..915d31d3 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -448,7 +448,6 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr); static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device); static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self); 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); @@ -466,11 +465,16 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self); + + self->pcmHandle = NULL; + self->buffer = NULL; } void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) { - ALCplaybackAlsa_close(self); + if(self->pcmHandle) + snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -708,12 +712,6 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCplaybackAlsa_close(ALCplaybackAlsa *self) -{ - snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; -} - static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -982,7 +980,6 @@ typedef struct ALCcaptureAlsa { static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device); static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self); 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); @@ -1000,11 +997,24 @@ static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self); + + self->pcmHandle = NULL; + self->buffer = NULL; + self->ring = NULL; } void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self) { - ALCcaptureAlsa_close(self); + if(self->pcmHandle) + snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; + + al_free(self->buffer); + self->buffer = NULL; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -1139,18 +1149,6 @@ error2: return ALC_INVALID_VALUE; } -static void ALCcaptureAlsa_close(ALCcaptureAlsa *self) -{ - snd_pcm_close(self->pcmHandle); - self->pcmHandle = NULL; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - al_free(self->buffer); - self->buffer = NULL; -} - static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { int err = snd_pcm_start(self->pcmHandle); diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 318e86fc..177f6869 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -43,7 +43,6 @@ struct ALCbackendVtable { void (*const Destruct)(ALCbackend*); ALCenum (*const open)(ALCbackend*, const ALCchar*); - void (*const close)(ALCbackend*); ALCboolean (*const reset)(ALCbackend*); ALCboolean (*const start)(ALCbackend*); @@ -63,7 +62,6 @@ struct ALCbackendVtable { #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) \ @@ -79,7 +77,6 @@ static const struct ALCbackendVtable T##_ALCbackend_vtable = { \ T##_ALCbackend_Destruct, \ \ T##_ALCbackend_open, \ - T##_ALCbackend_close, \ T##_ALCbackend_reset, \ T##_ALCbackend_start, \ T##_ALCbackend_stop, \ diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index bdd9b678..3db0d702 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -98,7 +98,6 @@ typedef struct ALCcoreAudioPlayback { static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device); static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self); static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name); -static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self); static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self); static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self); static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self); @@ -123,7 +122,9 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self) { - ALCcoreAudioPlayback_close(self); + AudioUnitUninitialize(self->audioUnit); + AudioComponentInstanceDispose(self->audioUnit); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -190,12 +191,6 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch return ALC_NO_ERROR; } -static void ALCcoreAudioPlayback_close(ALCcoreAudioPlayback *self) -{ - AudioUnitUninitialize(self->audioUnit); - AudioComponentInstanceDispose(self->audioUnit); -} - static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 7760e39d..3d130615 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -194,7 +194,6 @@ static int ALCdsoundPlayback_mixerProc(void *ptr); static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name); -static void ALCdsoundPlayback_close(ALCdsoundPlayback *self); static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self); static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self); static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self); @@ -212,11 +211,33 @@ static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *devi { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self); + + self->DS = NULL; + self->PrimaryBuffer = NULL; + self->Buffer = NULL; + self->Notifies = NULL; + self->NotifyEvent = NULL; } static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) { - ALCdsoundPlayback_close(self); + if(self->Notifies) + IDirectSoundNotify_Release(self->Notifies); + self->Notifies = NULL; + if(self->Buffer) + IDirectSoundBuffer_Release(self->Buffer); + self->Buffer = NULL; + if(self->PrimaryBuffer != NULL) + IDirectSoundBuffer_Release(self->PrimaryBuffer); + self->PrimaryBuffer = NULL; + + if(self->DS) + IDirectSound_Release(self->DS); + self->DS = NULL; + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -393,26 +414,6 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de return ALC_NO_ERROR; } -static void ALCdsoundPlayback_close(ALCdsoundPlayback *self) -{ - if(self->Notifies) - IDirectSoundNotify_Release(self->Notifies); - self->Notifies = NULL; - if(self->Buffer) - IDirectSoundBuffer_Release(self->Buffer); - self->Buffer = NULL; - if(self->PrimaryBuffer != NULL) - IDirectSoundBuffer_Release(self->PrimaryBuffer); - self->PrimaryBuffer = NULL; - - if(self->DS) - IDirectSound_Release(self->DS); - self->DS = NULL; - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; -} - static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -671,7 +672,6 @@ typedef struct ALCdsoundCapture { static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name); -static void ALCdsoundCapture_close(ALCdsoundCapture *self); static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self); static void ALCdsoundCapture_stop(ALCdsoundCapture *self); @@ -688,11 +688,28 @@ static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCdsoundCapture, ALCbackend, self); + + self->DSC = NULL; + self->DSCbuffer = NULL; + self->Ring = NULL; } static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) { - ALCdsoundCapture_close(self); + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + if(self->DSCbuffer != NULL) + { + IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); + IDirectSoundCaptureBuffer_Release(self->DSCbuffer); + self->DSCbuffer = NULL; + } + + if(self->DSC) + IDirectSoundCapture_Release(self->DSC); + self->DSC = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -869,23 +886,6 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi return ALC_NO_ERROR; } -static void ALCdsoundCapture_close(ALCdsoundCapture *self) -{ - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - if(self->DSCbuffer != NULL) - { - IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); - IDirectSoundCaptureBuffer_Release(self->DSCbuffer); - self->DSCbuffer = NULL; - } - - if(self->DSC) - IDirectSoundCapture_Release(self->DSC); - self->DSC = NULL; -} - static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) { HRESULT hr; diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 0dc01ae7..f1141ce9 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -164,7 +164,6 @@ static int ALCjackPlayback_mixerProc(void *arg); static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device); static void ALCjackPlayback_Destruct(ALCjackPlayback *self); static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name); -static void ALCjackPlayback_close(ALCjackPlayback *self); static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self); static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self); static void ALCjackPlayback_stop(ALCjackPlayback *self); @@ -388,20 +387,6 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCjackPlayback_close(ALCjackPlayback *self) -{ - ALuint i; - - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - { - if(self->Port[i]) - jack_port_unregister(self->Client, self->Port[i]); - self->Port[i] = NULL; - } - jack_client_close(self->Client); - self->Client = NULL; -} - static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c index 8f23aad9..9186a92f 100644 --- a/Alc/backends/loopback.c +++ b/Alc/backends/loopback.c @@ -35,7 +35,6 @@ typedef struct 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); @@ -63,10 +62,6 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCloopback_close(ALCloopback* UNUSED(self)) -{ -} - static ALCboolean ALCloopback_reset(ALCloopback *self) { SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 899f73d4..d63d22df 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -545,7 +545,6 @@ static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self); static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *name); static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self); -static void ALCmmdevPlayback_close(ALCmmdevPlayback *self); static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self); static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self); static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self); @@ -587,7 +586,22 @@ static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self) { - ALCmmdevPlayback_close(self); + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + } + + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + + free(self->devid); + self->devid = NULL; if(self->NotifyEvent != NULL) CloseHandle(self->NotifyEvent); @@ -838,26 +852,6 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) } -static void ALCmmdevPlayback_close(ALCmmdevPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - - if(!req.FinishedEvt) - return; - - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - free(self->devid); - self->devid = NULL; -} - static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self) { if(self->client) @@ -1248,7 +1242,6 @@ static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device); static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self); static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name); static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self); -static void ALCmmdevCapture_close(ALCmmdevCapture *self); static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self); static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALCboolean, reset) static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self); @@ -1292,7 +1285,19 @@ static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) { - ALCmmdevCapture_close(self); + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + } + + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; ll_ringbuffer_free(self->Ring); self->Ring = NULL; @@ -1300,13 +1305,6 @@ static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) DestroySampleConverter(&self->SampleConv); DestroyChannelConverter(&self->ChannelConv); - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - free(self->devid); self->devid = NULL; @@ -1529,7 +1527,6 @@ static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *device if(FAILED(hr)) { - ALCmmdevCapture_close(self); if(hr == E_OUTOFMEMORY) return ALC_OUT_OF_MEMORY; return ALC_INVALID_VALUE; @@ -1576,29 +1573,6 @@ static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) } -static void ALCmmdevCapture_close(ALCmmdevCapture *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - - if(!req.FinishedEvt) - return; - - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - free(self->devid); - self->devid = NULL; -} - static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self) { if(self->client) diff --git a/Alc/backends/null.c b/Alc/backends/null.c index e8c43782..d17c8bda 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -45,7 +45,6 @@ static int ALCnullBackend_mixerProc(void *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); @@ -135,10 +134,6 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCnullBackend_close(ALCnullBackend* UNUSED(self)) -{ -} - static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) { SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index c1283111..7edc9ff8 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -160,7 +160,6 @@ static int ALCopenslPlayback_mixerProc(void *arg); static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device); static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self); static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name); -static void ALCopenslPlayback_close(ALCopenslPlayback *self); static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self); static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self); static void ALCopenslPlayback_stop(ALCopenslPlayback *self); @@ -194,7 +193,18 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) { - ALCopenslPlayback_close(self); + if(self->mBufferQueueObj != NULL) + VCALL0(self->mBufferQueueObj,Destroy)(); + self->mBufferQueueObj = NULL; + + if(self->mOutputMix) + VCALL0(self->mOutputMix,Destroy)(); + self->mOutputMix = NULL; + + if(self->mEngineObj) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; alcnd_destroy(&self->mCond); @@ -389,22 +399,6 @@ static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *na return ALC_NO_ERROR; } -static void ALCopenslPlayback_close(ALCopenslPlayback *self) -{ - if(self->mBufferQueueObj != NULL) - VCALL0(self->mBufferQueueObj,Destroy)(); - self->mBufferQueueObj = NULL; - - if(self->mOutputMix) - VCALL0(self->mOutputMix,Destroy)(); - self->mOutputMix = NULL; - - if(self->mEngineObj) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; -} - static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; @@ -710,7 +704,6 @@ static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *con static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device); static void ALCopenslCapture_Destruct(ALCopenslCapture *self); static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name); -static void ALCopenslCapture_close(ALCopenslCapture *self); static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self); static void ALCopenslCapture_stop(ALCopenslCapture *self); @@ -749,7 +742,18 @@ static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device static void ALCopenslCapture_Destruct(ALCopenslCapture *self) { - ALCopenslCapture_close(self); + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + + if(self->mRecordObj != NULL) + VCALL0(self->mRecordObj,Destroy)(); + self->mRecordObj = NULL; + + if(self->mEngineObj != NULL) + VCALL0(self->mEngineObj,Destroy)(); + self->mEngineObj = NULL; + self->mEngine = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -918,21 +922,6 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name return ALC_NO_ERROR; } -static void ALCopenslCapture_close(ALCopenslCapture *self) -{ - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - - if(self->mRecordObj != NULL) - VCALL0(self->mRecordObj,Destroy)(); - self->mRecordObj = NULL; - - if(self->mEngineObj != NULL) - VCALL0(self->mEngineObj,Destroy)(); - self->mEngineObj = NULL; - self->mEngine = NULL; -} - static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) { SLRecordItf record; diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index e88e5ff3..b2d9c555 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -254,7 +254,6 @@ static int ALCplaybackOSS_mixerProc(void *ptr); static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device); static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self); 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); @@ -339,12 +338,16 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCplaybackOSS, ALCbackend, self); + self->fd = -1; ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self) { - ALCplaybackOSS_close(self); + if(self->fd != -1) + close(self->fd); + self->fd = -1; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -387,13 +390,6 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCplaybackOSS_close(ALCplaybackOSS *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; -} - static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -528,7 +524,6 @@ static int ALCcaptureOSS_recordProc(void *ptr); static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device); static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self); 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); @@ -605,12 +600,19 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcaptureOSS, ALCbackend, self); + self->fd = -1; + self->ring = NULL; ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self) { - ALCcaptureOSS_close(self); + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -739,16 +741,6 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCcaptureOSS_close(ALCcaptureOSS *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; -} - static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self) { ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE); diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 58cf9762..fdc8a2a5 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -141,7 +141,6 @@ static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBu static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); static void ALCportPlayback_Destruct(ALCportPlayback *self); static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); -static void ALCportPlayback_close(ALCportPlayback *self); static ALCboolean ALCportPlayback_reset(ALCportPlayback *self); static ALCboolean ALCportPlayback_start(ALCportPlayback *self); static void ALCportPlayback_stop(ALCportPlayback *self); @@ -165,7 +164,11 @@ static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) static void ALCportPlayback_Destruct(ALCportPlayback *self) { - ALCportPlayback_close(self); + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + self->stream = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -250,14 +253,6 @@ retry_open: } -static void ALCportPlayback_close(ALCportPlayback *self) -{ - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = NULL; -} - static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -335,7 +330,6 @@ static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuff static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); static void ALCportCapture_Destruct(ALCportCapture *self); static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); -static void ALCportCapture_close(ALCportCapture *self); static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCportCapture_start(ALCportCapture *self); static void ALCportCapture_stop(ALCportCapture *self); @@ -355,11 +349,19 @@ static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) SET_VTABLE2(ALCportCapture, ALCbackend, self); self->stream = NULL; + self->ring = NULL; } static void ALCportCapture_Destruct(ALCportCapture *self) { - ALCportCapture_close(self); + PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + self->stream = NULL; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -442,17 +444,6 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCportCapture_close(ALCportCapture *self) -{ - PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError; - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - self->stream = NULL; - - ll_ringbuffer_free(self->ring); - self->ring = NULL; -} - static ALCboolean ALCportCapture_start(ALCportCapture *self) { diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 581f4c38..bcfbb6c2 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -495,7 +495,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr); static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device); static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self); 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); @@ -514,12 +513,19 @@ static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCpulsePlayback, ALCbackend, self); + self->loop = NULL; AL_STRING_INIT(self->device_name); } static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self) { - ALCpulsePlayback_close(self); + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = NULL; + self->context = NULL; + self->stream = NULL; + } AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -957,17 +963,6 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name return ALC_NO_ERROR; } -static void ALCpulsePlayback_close(ALCpulsePlayback *self) -{ - if(self->loop) - { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - } -} - static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; @@ -1251,7 +1246,6 @@ static pa_stream *ALCpulseCapture_connectStream(const char *device_name, static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device); static void ALCpulseCapture_Destruct(ALCpulseCapture *self); 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); @@ -1270,12 +1264,19 @@ static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCpulseCapture, ALCbackend, self); + self->loop = NULL; AL_STRING_INIT(self->device_name); } static void ALCpulseCapture_Destruct(ALCpulseCapture *self) { - ALCpulseCapture_close(self); + if(self->loop) + { + pulse_close(self->loop, self->context, self->stream); + self->loop = NULL; + self->context = NULL; + self->stream = NULL; + } AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -1622,17 +1623,6 @@ fail: return ALC_INVALID_VALUE; } -static void ALCpulseCapture_close(ALCpulseCapture *self) -{ - if(self->loop) - { - pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; - } -} - static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self) { pa_operation *o; diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index e1bbf2c2..614d738c 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -168,7 +168,6 @@ typedef struct PlaybackWrapper { static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device); static void PlaybackWrapper_Destruct(PlaybackWrapper *self); 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); @@ -626,7 +625,9 @@ static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device) static void PlaybackWrapper_Destruct(PlaybackWrapper *self) { - PlaybackWrapper_close(self); + if(self->ExtraData) + qsa_close_playback(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -635,12 +636,6 @@ static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) return qsa_open_playback(self, name); } -static void PlaybackWrapper_close(PlaybackWrapper *self) -{ - if(self->ExtraData) - qsa_close_playback(self); -} - static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) { return qsa_reset_playback(self); @@ -670,7 +665,6 @@ typedef struct CaptureWrapper { static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device); static void CaptureWrapper_Destruct(CaptureWrapper *self); 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); @@ -954,7 +948,9 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device) static void CaptureWrapper_Destruct(CaptureWrapper *self) { - CaptureWrapper_close(self); + if(self->ExtraData) + qsa_close_capture(self); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -963,12 +959,6 @@ static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) return qsa_open_capture(self, name); } -static void CaptureWrapper_close(CaptureWrapper *self) -{ - if(self->ExtraData) - qsa_close_capture(self); -} - static ALCboolean CaptureWrapper_start(CaptureWrapper *self) { qsa_start_capture(self); diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 436baf26..f7b9af69 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -52,7 +52,6 @@ static int ALCsndioBackend_mixerProc(void *ptr); static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device); static void ALCsndioBackend_Destruct(ALCsndioBackend *self); static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name); -static void ALCsndioBackend_close(ALCsndioBackend *self); static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self); static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self); static void ALCsndioBackend_stop(ALCsndioBackend *self); @@ -73,11 +72,16 @@ static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCsndioBackend, ALCbackend, self); + + self->sndHandle = NULL; + self->mix_data = NULL; } static void ALCsndioBackend_Destruct(ALCsndioBackend *self) { - ALCsndioBackend_close(self); + if(self->sndHandle) + sio_close(self->sndHandle); + self->sndHandle = NULL; al_free(self->mix_data); self->mix_data = NULL; @@ -148,13 +152,6 @@ static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCsndioBackend_close(ALCsndioBackend *self) -{ - if(self->sndHandle) - sio_close(self->sndHandle); - self->sndHandle = NULL; -} - static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 3230b401..49bfad3c 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -60,7 +60,6 @@ static int ALCsolarisBackend_mixerProc(void *ptr); static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name); -static void ALCsolarisBackend_close(ALCsolarisBackend *self); static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self); static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); static void ALCsolarisBackend_stop(ALCsolarisBackend *self); @@ -85,12 +84,15 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); self->fd = -1; + self->mix_data = NULL; ATOMIC_INIT(&self->killNow, AL_FALSE); } static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) { - ALCsolarisBackend_close(self); + if(self->fd != -1) + close(self->fd); + self->fd = -1; free(self->mix_data); self->mix_data = NULL; @@ -189,13 +191,6 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na return ALC_NO_ERROR; } -static void ALCsolarisBackend_close(ALCsolarisBackend *self) -{ - if(self->fd != -1) - close(self->fd); - self->fd = -1; -} - static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 538ab5e6..ecb066f8 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -86,7 +86,6 @@ static int ALCwaveBackend_mixerProc(void *ptr); static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); static void ALCwaveBackend_Destruct(ALCwaveBackend *self); static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); -static void ALCwaveBackend_close(ALCwaveBackend *self); static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); static void ALCwaveBackend_stop(ALCwaveBackend *self); @@ -116,7 +115,10 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) static void ALCwaveBackend_Destruct(ALCwaveBackend *self) { - ALCwaveBackend_close(self); + if(self->mFile) + fclose(self->mFile); + self->mFile = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -239,13 +241,6 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static void ALCwaveBackend_close(ALCwaveBackend *self) -{ - if(self->mFile) - fclose(self->mFile); - self->mFile = NULL; -} - static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 885b624c..59164441 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -159,7 +159,6 @@ static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWO static int ALCwinmmPlayback_mixerProc(void *arg); static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); -static void ALCwinmmPlayback_close(ALCwinmmPlayback *self); static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); @@ -312,9 +311,6 @@ failure: return ALC_INVALID_VALUE; } -static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self)) -{ } - static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; @@ -448,7 +444,6 @@ static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_ static int ALCwinmmCapture_captureProc(void *arg); static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); -static void ALCwinmmCapture_close(ALCwinmmCapture *self); static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); static void ALCwinmmCapture_stop(ALCwinmmCapture *self); @@ -475,7 +470,34 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) { - ALCwinmmCapture_close(self); + void *buffer = NULL; + int i; + + /* Tell the processing thread to quit and wait for it to do so. */ + if(!self->killNow) + { + self->killNow = AL_TRUE; + PostThreadMessage(self->thread, WM_QUIT, 0, 0); + + althrd_join(self->thread, &i); + + /* Make sure capture is stopped and all pending buffers are flushed. */ + waveInReset(self->InHdl); + + // Release the wave buffers + for(i = 0;i < 4;i++) + { + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; + } + free(buffer); + } + + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + // Close the Wave device if(self->InHdl) waveInClose(self->InHdl); self->InHdl = 0; @@ -659,38 +681,6 @@ failure: return ALC_INVALID_VALUE; } -static void ALCwinmmCapture_close(ALCwinmmCapture *self) -{ - void *buffer = NULL; - int i; - - /* Tell the processing thread to quit and wait for it to do so. */ - if(self->killNow) return; - self->killNow = AL_TRUE; - PostThreadMessage(self->thread, WM_QUIT, 0, 0); - - althrd_join(self->thread, &i); - - /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(self->InHdl); - - // Release the wave buffers - for(i = 0;i < 4;i++) - { - waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = self->WaveBuffer[i].lpData; - self->WaveBuffer[i].lpData = NULL; - } - free(buffer); - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - // Close the Wave device - waveInClose(self->InHdl); - self->InHdl = NULL; -} - static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { waveInStart(self->InHdl); -- cgit v1.2.3 From 0394d5a44fd5b1c90c7e4ae9d660bec8a19175f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 30 Jan 2018 12:34:25 -0800 Subject: Rename EventLock to make it more clear it's protecting the callback --- Alc/ALc.c | 4 ++-- OpenAL32/Include/alMain.h | 2 +- OpenAL32/alError.c | 4 ++-- OpenAL32/alState.c | 4 ++-- OpenAL32/event.c | 6 ++---- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 53979704..04b8f9bd 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2611,7 +2611,7 @@ static ALvoid InitContext(ALCcontext *Context) Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); - almtx_init(&Context->EventLock, almtx_plain); + almtx_init(&Context->EventCbLock, almtx_plain); ATOMIC_INIT(&Context->EnabledEvts, 0); Context->EventCb = NULL; Context->EventParam = NULL; @@ -2743,7 +2743,7 @@ static void FreeContext(ALCcontext *context) } TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); - almtx_destroy(&context->EventLock); + almtx_destroy(&context->EventCbLock); ALCdevice_DecRef(context->Device); context->Device = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index ef5ad0e9..6ad67b7b 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -664,7 +664,7 @@ struct ALCcontext_struct { ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; - almtx_t EventLock; + almtx_t EventCbLock; ATOMIC(ALbitfieldSOFT) EnabledEvts; ALEVENTPROCSOFT EventCb; void *EventParam; diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c index 22aed458..b6208f77 100644 --- a/OpenAL32/alError.c +++ b/OpenAL32/alError.c @@ -75,12 +75,12 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error)) { ALbitfieldSOFT enabledevts; - almtx_lock(&context->EventLock); + almtx_lock(&context->EventCbLock); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); if((enabledevts&EventType_Error) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_ERROR_SOFT, 0, errorCode, msglen, msg, context->EventParam); - almtx_unlock(&context->EventLock); + almtx_unlock(&context->EventCbLock); } } diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 10fce3b5..8448e548 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -722,12 +722,12 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound"; const ALsizei msglen = (ALsizei)strlen(msg); ALbitfieldSOFT enabledevts; - almtx_lock(&context->EventLock); + almtx_lock(&context->EventCbLock); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); if((enabledevts&EventType_Deprecated) && context->EventCb) (*context->EventCb)(AL_EVENT_TYPE_DEPRECATED_SOFT, 0, 0, msglen, msg, context->EventParam); - almtx_unlock(&context->EventLock); + almtx_unlock(&context->EventCbLock); } if(!(value >= 0.0f && isfinite(value))) diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 93d68d7a..9a3a92b4 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -37,7 +37,6 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); } - almtx_lock(&context->EventLock); if(enable) { ALbitfieldSOFT enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); @@ -57,7 +56,6 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A { } } - almtx_unlock(&context->EventLock); done: ALCcontext_DecRef(context); @@ -70,10 +68,10 @@ AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *user context = GetContextRef(); if(!context) return; - almtx_lock(&context->EventLock); + almtx_lock(&context->EventCbLock); context->EventCb = callback; context->EventParam = userParam; - almtx_unlock(&context->EventLock); + almtx_unlock(&context->EventCbLock); ALCcontext_DecRef(context); } -- cgit v1.2.3 From 7256bc92fa954b6ff313f30694a27b7f47c1589d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jan 2018 20:21:54 -0800 Subject: Add a thread to marshal events from the mixer To avoid having unknown user code running in the mixer thread that could significantly delay the mixed output, a lockless ringbuffer is used for the mixer to provide events that a secondary thread will pop off and process. --- Alc/ALc.c | 20 ++++++++++++- OpenAL32/Include/alMain.h | 15 +++++++++- OpenAL32/event.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 04b8f9bd..632e1f18 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -41,6 +41,7 @@ #include "bformatdec.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "fpu_modes.h" #include "cpu_caps.h" @@ -2611,8 +2612,11 @@ static ALvoid InitContext(ALCcontext *Context) Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); - almtx_init(&Context->EventCbLock, almtx_plain); + almtx_init(&Context->EventThrdLock, almtx_plain); + alcnd_init(&Context->EventCnd); + Context->AsyncEvents = NULL; ATOMIC_INIT(&Context->EnabledEvts, 0); + almtx_init(&Context->EventCbLock, almtx_plain); Context->EventCb = NULL; Context->EventParam = NULL; @@ -2743,7 +2747,21 @@ static void FreeContext(ALCcontext *context) } TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); + if(ATOMIC_EXCHANGE(&context->EnabledEvts, 0, almemory_order_acq_rel)) + { + static const AsyncEvent kill_evt = { 0 }; + while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) + althrd_yield(); + ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); + althrd_join(context->EventThread, NULL); + } + almtx_destroy(&context->EventCbLock); + almtx_destroy(&context->EventThrdLock); + alcnd_destroy(&context->EventCnd); + + ll_ringbuffer_free(context->AsyncEvents); + context->AsyncEvents = NULL; ALCdevice_DecRef(context->Device); context->Device = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6ad67b7b..e7a95eef 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -158,6 +158,7 @@ static const union { extern "C" { #endif +struct ll_ringbuffer; struct Hrtf; struct HrtfEntry; struct DirectHrtfState; @@ -613,6 +614,14 @@ enum { EventType_Deprecated = 1<<4, }; +typedef struct AsyncEvent { + unsigned int EnumType; + ALenum Type; + ALuint ObjectId; + ALuint Param; + ALchar Message[1008]; +} AsyncEvent; + struct ALCcontext_struct { RefCount ref; @@ -664,8 +673,12 @@ struct ALCcontext_struct { ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; - almtx_t EventCbLock; + almtx_t EventThrdLock; + althrd_t EventThread; + alcnd_t EventCnd; + struct ll_ringbuffer *AsyncEvents; ATOMIC(ALbitfieldSOFT) EnabledEvts; + almtx_t EventCbLock; ALEVENTPROCSOFT EventCb; void *EventParam; diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 9a3a92b4..82a6efb1 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -6,8 +6,48 @@ #include "AL/alext.h" #include "alMain.h" #include "alError.h" +#include "ringbuffer.h" +static int EventThread(void *arg) +{ + ALCcontext *context = arg; + + almtx_lock(&context->EventCbLock); + while(1) + { + AsyncEvent evt; + ALbitfieldSOFT enabledevts; + + if(ll_ringbuffer_read_space(context->AsyncEvents) == 0) + { + /* Wait 50ms before checking again. Because events are delivered + * asynchronously by the mixer, it's possible for one to be written + * in between checking for a readable element and sleeping. So to + * ensure events don't get left to go stale in the ringbuffer, we + * need to keep checking regardless of being signaled. + */ + struct timespec ts; + altimespec_get(&ts, AL_TIME_UTC); + ts.tv_nsec += 50000000; + ts.tv_sec += ts.tv_nsec/1000000000; + ts.tv_nsec %= 1000000000; + alcnd_timedwait(&context->EventCnd, &context->EventCbLock, &ts); + continue; + } + ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1); + if(!evt.EnumType) break; + + /* Should check the actual type is enabled here too. */ + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(context->EventCb && (enabledevts&evt.EnumType) != evt.EnumType) + context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), + evt.Message, context->EventParam); + } + almtx_unlock(&context->EventCbLock); + return 0; +} + AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) { ALCcontext *context; @@ -39,7 +79,13 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A if(enable) { - ALbitfieldSOFT enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + ALbitfieldSOFT enabledevts; + bool isrunning; + almtx_lock(&context->EventThrdLock); + if(!context->AsyncEvents) + context->AsyncEvents = ll_ringbuffer_create(64, sizeof(AsyncEvent)); + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, almemory_order_acq_rel, almemory_order_acquire) == 0) { @@ -47,14 +93,38 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A * just try again. */ } + if(!isrunning && flags) + althrd_create(&context->EventThread, EventThread, context); + almtx_unlock(&context->EventThrdLock); } else { - ALbitfieldSOFT enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + ALbitfieldSOFT enabledevts; + bool isrunning; + almtx_lock(&context->EventThrdLock); + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); + isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, almemory_order_acq_rel, almemory_order_acquire) == 0) { } + if(isrunning && !(enabledevts&~flags)) + { + static const AsyncEvent kill_evt = { 0 }; + while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) + althrd_yield(); + ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); + althrd_join(context->EventThread, NULL); + } + else + { + /* Wait to ensure the event handler sees the changed flags before + * returning. + */ + almtx_lock(&context->EventCbLock); + almtx_unlock(&context->EventCbLock); + } + almtx_unlock(&context->EventThrdLock); } done: -- cgit v1.2.3 From 833eface3875d64274c9b56dd6059535cf510f28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 31 Jan 2018 20:27:14 -0800 Subject: Don't print buffer completed events in alffplay --- examples/alffplay.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 039f5d68..73c3e028 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -684,6 +684,12 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui { AudioState *self = reinterpret_cast(userParam); + if(eventType == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) + { + /* TODO: Signal the audio handler to wake up and decode another buffer. */ + return; + } + std::cout<< "---- AL Event on AudioState "< Date: Thu, 1 Feb 2018 00:50:06 -0800 Subject: Fix check for matching event type --- OpenAL32/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 82a6efb1..ff53d7d8 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -40,7 +40,7 @@ static int EventThread(void *arg) /* Should check the actual type is enabled here too. */ enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(context->EventCb && (enabledevts&evt.EnumType) != evt.EnumType) + if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), evt.Message, context->EventParam); } -- cgit v1.2.3 From bcdc399029ee2dad87ec3dc608eaa44c9dd9614b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 01:36:03 -0800 Subject: Send buffer completed events when enabled --- Alc/ALu.c | 2 +- Alc/mixer.c | 47 +++++++++++++++++++++++++++++++++++++---------- OpenAL32/Include/alu.h | 2 +- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d190a1be..8d2e5727 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1693,7 +1693,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) && voice->Step > 0) { - if(!MixSource(voice, device, SamplesToDo)) + if(!MixSource(voice, source->id, ctx, SamplesToDo)) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); diff --git a/Alc/mixer.c b/Alc/mixer.c index b54e840e..31e94974 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -36,6 +36,7 @@ #include "sample_cvt.h" #include "alu.h" #include "alconfig.h" +#include "ringbuffer.h" #include "cpu_caps.h" #include "mixer_defs.h" @@ -193,6 +194,20 @@ void aluInitMixer(void) } +static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, + ALuint objid, ALuint param, const char *msg) +{ + AsyncEvent evt; + evt.EnumType = enumtype; + evt.Type = type; + evt.ObjectId = objid; + evt.Param = param; + strcpy(evt.Message, msg); + if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) + ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); +} + + static inline ALfloat Sample_ALubyte(ALubyte val) { return (val-128) * (1.0f/128.0f); } @@ -290,11 +305,14 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter #define RESAMPLED_BUF 1 #define FILTERED_BUF 2 #define NFC_DATA_BUF 3 -ALboolean MixSource(ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo) +ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) { + ALCdevice *Device = Context->Device; ALbufferlistitem *BufferListItem; ALbufferlistitem *BufferLoopItem; ALsizei NumChannels, SampleSize; + ALbitfieldSOFT enabledevt; + ALsizei buffers_done = 0; ResamplerFunc Resample; ALsizei DataPosInt; ALsizei DataPosFrac; @@ -707,17 +725,14 @@ ALboolean MixSource(ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo) if(CompLen > DataPosInt) break; + buffers_done++; BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); - if(!BufferListItem) + if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { - BufferListItem = BufferLoopItem; - if(!BufferListItem) - { - isplaying = false; - DataPosInt = 0; - DataPosFrac = 0; - break; - } + isplaying = false; + DataPosInt = 0; + DataPosFrac = 0; + break; } DataPosInt -= CompLen; @@ -730,5 +745,17 @@ ALboolean MixSource(ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo) ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); + + enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); + if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) + { + do { + SendAsyncEvent(Context, EventType_BufferCompleted, + AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, 0, "Buffer completed" + ); + } while(--buffers_done > 0); + alcnd_signal(&Context->EventCnd); + } + return isplaying; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 21390806..2e2e1f5a 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -516,7 +516,7 @@ inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], } -ALboolean MixSource(struct ALvoice *voice, ALCdevice *Device, ALsizei SamplesToDo); +ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device. */ -- cgit v1.2.3 From 7a538141c913d4cd0ebc292c651d399a40d5062d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 02:21:14 -0800 Subject: Signal a condition variable when a buffer completes in alffplay --- examples/alffplay.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 73c3e028..1c8d5697 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -237,6 +237,7 @@ struct AudioState { ALsizei mFrameSize{0}; std::mutex mSrcMutex; + std::condition_variable mSrcCond; ALuint mSource{0}; std::vector mBuffers; ALsizei mBufferIdx{0}; @@ -686,7 +687,11 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui if(eventType == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) { - /* TODO: Signal the audio handler to wake up and decode another buffer. */ + /* Temporarily lock the source mutex to ensure it's not between + * checking the processed count and going to sleep. + */ + std::unique_lock(self->mSrcMutex).unlock(); + self->mSrcCond.notify_one(); return; } @@ -715,12 +720,14 @@ int AudioState::handler() AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT }}; std::unique_lock lock(mSrcMutex); + milliseconds sleep_time = AudioBufferTime / 3; ALenum fmt; if(alEventControlSOFT) { alEventControlSOFT(types.size(), types.data(), AL_TRUE); alEventCallbackSOFT(EventCallback, this); + sleep_time = AudioBufferTotalTime; } /* Find a suitable format for OpenAL. */ @@ -941,9 +948,7 @@ int AudioState::handler() mMovie.mPlaying.load(std::memory_order_relaxed)) startPlayback(); - lock.unlock(); - SDL_Delay((AudioBufferTime/3).count()); - lock.lock(); + mSrcCond.wait_for(lock, sleep_time); } alSourceRewind(mSource); -- cgit v1.2.3 From 4ec31291c0de9334f6715edc13bf2d28ea884eb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 17:37:31 -0800 Subject: Add semaphore functions to the thread API wrapper --- common/threads.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ common/threads.h | 9 ++++++ 2 files changed, 96 insertions(+) diff --git a/common/threads.c b/common/threads.c index dbd196e8..c1b062cd 100644 --- a/common/threads.c +++ b/common/threads.c @@ -389,6 +389,56 @@ void alcnd_destroy(alcnd_t *cond) #endif /* defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 */ +int alsem_init(alsem_t *sem, unsigned int initial) +{ + *sem = CreateSemaphore(NULL, initial, INT_MAX, NULL); + if(*sem != NULL) return althrd_success; + return althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + CloseHandle(*sem); +} + +int alsem_post(alsem_t *sem) +{ + DWORD ret = ReleaseSemaphore(*sem, 1, NULL); + if(ret) return althrd_success; + return althrd_error; +} + +int alsem_wait(alsem_t *sem) +{ + DWORD ret = WaitForSingleObject(*sem, INFINITE); + if(ret == WAIT_OBJECT_0) return althrd_success; + return althrd_error; +} + +int alsem_timedwait(alsem_t *sem, const struct timespec *time_point) +{ + struct timespec curtime; + DWORD sleeptime, ret; + + if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) + return althrd_error; + + if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && + curtime.tv_nsec >= time_point->tv_nsec)) + sleeptime = 0; + else + { + sleeptime = (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000; + sleeptime += (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; + } + + ret = WaitForSingleObject(*sem, sleeptime); + if(ret == WAIT_OBJECT_0) return althrd_success; + if(ret == WAIT_TIMEOUT) return althrd_timedout; + return althrd_error; +} + + /* An associative map of uint:void* pairs. The key is the TLS index (given by * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, * we iterate over the TLS indices for their thread-local value and call the @@ -699,6 +749,43 @@ void alcnd_destroy(alcnd_t *cond) } +int alsem_init(alsem_t *sem, unsigned int initial) +{ + int ret = sem_init(sem, 0, initial); + if(ret == 0) return althrd_success; + return althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + sem_destroy(sem); +} + +int alsem_post(alsem_t *sem) +{ + int ret = sem_post(sem); + if(ret == 0) return althrd_success; + return althrd_error; +} + +int alsem_wait(alsem_t *sem) +{ + int ret = sem_wait(sem); + if(ret == 0) return althrd_success; + if(errno == EINTR) return -2; + return althrd_error; +} + +int alsem_timedwait(alsem_t *sem, const struct timespec *time_point) +{ + int ret = sem_timedwait(sem, time_point); + if(ret == 0) return althrd_success; + if(errno == ETIMEDOUT) return althrd_timedout; + if(errno == EINTR) return -2; + return althrd_error; +} + + int altss_create(altss_t *tss_id, altss_dtor_t callback) { if(pthread_key_create(tss_id, callback) != 0) diff --git a/common/threads.h b/common/threads.h index 87b8a6f5..a8096546 100644 --- a/common/threads.h +++ b/common/threads.h @@ -57,6 +57,7 @@ typedef CONDITION_VARIABLE alcnd_t; #else typedef struct { void *Ptr; } alcnd_t; #endif +typedef HANDLE alsem_t; typedef DWORD altss_t; typedef LONG alonce_flag; @@ -127,11 +128,13 @@ inline int altss_set(altss_t tss_id, void *val) #include #include #include +#include typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; typedef pthread_cond_t alcnd_t; +typedef sem_t alsem_t; typedef pthread_key_t altss_t; typedef pthread_once_t alonce_flag; @@ -233,6 +236,12 @@ int alcnd_wait(alcnd_t *cond, almtx_t *mtx); int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point); void alcnd_destroy(alcnd_t *cond); +int alsem_init(alsem_t *sem, unsigned int initial); +void alsem_destroy(alsem_t *sem); +int alsem_post(alsem_t *sem); +int alsem_wait(alsem_t *sem); +int alsem_timedwait(alsem_t *sem, const struct timespec *time_point); + int altss_create(altss_t *tss_id, altss_dtor_t callback); void altss_delete(altss_t tss_id); -- cgit v1.2.3 From e240351d81105e233f02d006f6bf42d03c0dd09b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 18:09:16 -0800 Subject: Use a semaphore to signal the event handler Semaphores allow for semi-persistent signals, compared to a condition variable which requires a mutex for proper detection. A semaphore can be 'post'ed after writing some data on one thread, and another thread will be able to recognize it quickly even if the post occured in between checking for data and waiting. This more correctly fixes a race condition with events since the mixer shouldn't be using mutexes, and arbitrary wake-ups just to make sure an event wasn't missed was quite inefficient. --- Alc/ALc.c | 5 +++-- Alc/mixer.c | 2 +- OpenAL32/Include/alMain.h | 2 +- OpenAL32/event.c | 19 ++++--------------- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 632e1f18..8ed10ac6 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2613,7 +2613,7 @@ static ALvoid InitContext(ALCcontext *Context) ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); almtx_init(&Context->EventThrdLock, almtx_plain); - alcnd_init(&Context->EventCnd); + alsem_init(&Context->EventSem, 0); Context->AsyncEvents = NULL; ATOMIC_INIT(&Context->EnabledEvts, 0); almtx_init(&Context->EventCbLock, almtx_plain); @@ -2753,12 +2753,13 @@ static void FreeContext(ALCcontext *context) while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) althrd_yield(); ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); + alsem_post(&context->EventSem); althrd_join(context->EventThread, NULL); } almtx_destroy(&context->EventCbLock); almtx_destroy(&context->EventThrdLock); - alcnd_destroy(&context->EventCnd); + alsem_destroy(&context->EventSem); ll_ringbuffer_free(context->AsyncEvents); context->AsyncEvents = NULL; diff --git a/Alc/mixer.c b/Alc/mixer.c index 31e94974..c34284d5 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -754,7 +754,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, 0, "Buffer completed" ); } while(--buffers_done > 0); - alcnd_signal(&Context->EventCnd); + alsem_post(&Context->EventSem); } return isplaying; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e7a95eef..bc5a27c8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -675,7 +675,7 @@ struct ALCcontext_struct { almtx_t EventThrdLock; althrd_t EventThread; - alcnd_t EventCnd; + alsem_t EventSem; struct ll_ringbuffer *AsyncEvents; ATOMIC(ALbitfieldSOFT) EnabledEvts; almtx_t EventCbLock; diff --git a/OpenAL32/event.c b/OpenAL32/event.c index ff53d7d8..38c12d98 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -13,7 +13,6 @@ static int EventThread(void *arg) { ALCcontext *context = arg; - almtx_lock(&context->EventCbLock); while(1) { AsyncEvent evt; @@ -21,30 +20,19 @@ static int EventThread(void *arg) if(ll_ringbuffer_read_space(context->AsyncEvents) == 0) { - /* Wait 50ms before checking again. Because events are delivered - * asynchronously by the mixer, it's possible for one to be written - * in between checking for a readable element and sleeping. So to - * ensure events don't get left to go stale in the ringbuffer, we - * need to keep checking regardless of being signaled. - */ - struct timespec ts; - altimespec_get(&ts, AL_TIME_UTC); - ts.tv_nsec += 50000000; - ts.tv_sec += ts.tv_nsec/1000000000; - ts.tv_nsec %= 1000000000; - alcnd_timedwait(&context->EventCnd, &context->EventCbLock, &ts); + alsem_wait(&context->EventSem); continue; } ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1); if(!evt.EnumType) break; - /* Should check the actual type is enabled here too. */ + almtx_lock(&context->EventCbLock); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), evt.Message, context->EventParam); + almtx_unlock(&context->EventCbLock); } - almtx_unlock(&context->EventCbLock); return 0; } @@ -114,6 +102,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) althrd_yield(); ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); + alsem_post(&context->EventSem); althrd_join(context->EventThread, NULL); } else -- cgit v1.2.3 From 975c682ec367f61e6e700b21da38e2c59cf69c3b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 18:54:13 -0800 Subject: Use semaphores to signal for more samples with JACK and OpenSL --- Alc/backends/jack.c | 34 ++++++++-------------------------- Alc/backends/opensl.c | 36 ++++++++---------------------------- 2 files changed, 16 insertions(+), 54 deletions(-) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index f1141ce9..09f778c7 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -150,7 +150,7 @@ typedef struct ALCjackPlayback { jack_port_t *Port[MAX_OUTPUT_CHANNELS]; ll_ringbuffer_t *Ring; - alcnd_t Cond; + alsem_t Sem; volatile int killNow; althrd_t thread; @@ -184,7 +184,7 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCjackPlayback, ALCbackend, self); - alcnd_init(&self->Cond); + alsem_init(&self->Sem, 0); self->Client = NULL; for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) @@ -210,7 +210,7 @@ static void ALCjackPlayback_Destruct(ALCjackPlayback *self) self->Client = NULL; } - alcnd_destroy(&self->Cond); + alsem_destroy(&self->Sem); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -287,7 +287,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg) } ll_ringbuffer_read_advance(self->Ring, total); - alcnd_signal(&self->Cond); + alsem_post(&self->Sem); if(numframes > total) { @@ -316,23 +316,11 @@ static int ALCjackPlayback_mixerProc(void *arg) { ALuint todo, len1, len2; - /* NOTE: Unfortunately, there is an unavoidable race condition here. - * It's possible for the process() method to run, updating the read - * pointer and signaling the condition variable, in between the mixer - * loop checking the write size and waiting for the condition variable. - * This will cause the mixer loop to wait until the *next* process() - * invocation, most likely writing silence for it. - * - * However, this should only happen if the mixer is running behind - * anyway (as ideally we'll be asleep in alcnd_wait by the time the - * process() method is invoked), so this behavior is not unwarranted. - * It's unfortunate since it'll be wasting time sleeping that could be - * used to catch up, but there's no way around it without blocking in - * the process() method. - */ if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize) { - alcnd_wait(&self->Cond, &STATIC_CAST(ALCbackend,self)->mMutex); + ALCjackPlayback_unlock(self); + alsem_wait(&self->Sem); + ALCjackPlayback_lock(self); continue; } @@ -509,13 +497,7 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) return; self->killNow = 1; - /* Lock the backend to ensure we don't flag the mixer to die and signal the - * mixer to wake up in between it checking the flag and going to sleep and - * wait for a wakeup (potentially leading to it never waking back up to see - * the flag). */ - ALCjackPlayback_lock(self); - ALCjackPlayback_unlock(self); - alcnd_signal(&self->Cond); + alsem_post(&self->Sem); althrd_join(self->thread, &res); jack_deactivate(self->Client); diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 7edc9ff8..fb56b67c 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -146,7 +146,7 @@ typedef struct ALCopenslPlayback { SLObjectItf mBufferQueueObj; ll_ringbuffer_t *mRing; - alcnd_t mCond; + alsem_t mSem; ALsizei mFrameSize; @@ -184,7 +184,7 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi self->mBufferQueueObj = NULL; self->mRing = NULL; - alcnd_init(&self->mCond); + alsem_init(&self->mSem, 0); self->mFrameSize = 0; @@ -206,7 +206,7 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) self->mEngineObj = NULL; self->mEngine = NULL; - alcnd_destroy(&self->mCond); + alsem_destroy(&self->mSem); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -227,7 +227,7 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), */ ll_ringbuffer_read_advance(self->mRing, 1); - alcnd_signal(&self->mCond); + alsem_post(&self->mSem); } @@ -287,24 +287,11 @@ static int ALCopenslPlayback_mixerProc(void *arg) break; } - /* NOTE: Unfortunately, there is an unavoidable race condition - * here. It's possible for the process() method to run, updating - * the read pointer and signaling the condition variable, in - * between checking the write size and waiting for the condition - * variable here. This will cause alcnd_wait to wait until the - * *next* process() invocation signals the condition variable - * again. - * - * However, this should only happen if the mixer is running behind - * anyway (as ideally we'll be asleep in alcnd_wait by the time the - * process() method is invoked), so this behavior is not completely - * unwarranted. It's unfortunate since it'll be wasting time - * sleeping that could be used to catch up, but there's no way - * around it without blocking in the process() method. - */ if(ll_ringbuffer_write_space(self->mRing) <= padding) { - alcnd_wait(&self->mCond, &STATIC_CAST(ALCbackend,self)->mMutex); + ALCopenslPlayback_unlock(self); + alsem_wait(&self->mSem); + ALCopenslPlayback_lock(self); continue; } } @@ -623,14 +610,7 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE)) return; - /* Lock the backend to ensure we don't flag the mixer to die and signal the - * mixer to wake up in between it checking the flag and going to sleep and - * wait for a wakeup (potentially leading to it never waking back up to see - * the flag). - */ - ALCopenslPlayback_lock(self); - ALCopenslPlayback_unlock(self); - alcnd_signal(&self->mCond); + alsem_post(&self->mSem); althrd_join(self->mThread, &res); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); -- cgit v1.2.3 From ec14c98f2d7c2a01f62a2fcebf1d9479cb540a0d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 18:59:32 -0800 Subject: Use an atomic instead of volatile to tell a thread to quit --- Alc/backends/jack.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 09f778c7..14032d45 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -152,7 +152,7 @@ typedef struct ALCjackPlayback { ll_ringbuffer_t *Ring; alsem_t Sem; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCjackPlayback; @@ -191,7 +191,7 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device) self->Port[i] = NULL; self->Ring = NULL; - self->killNow = 1; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCjackPlayback_Destruct(ALCjackPlayback *self) @@ -312,7 +312,7 @@ static int ALCjackPlayback_mixerProc(void *arg) althrd_setname(althrd_current(), MIXER_THREAD_NAME); ALCjackPlayback_lock(self); - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && device->Connected) { ALuint todo, len1, len2; @@ -479,7 +479,7 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self) } jack_free(ports); - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success) { jack_deactivate(self->Client); @@ -493,10 +493,9 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - self->killNow = 1; alsem_post(&self->Sem); althrd_join(self->thread, &res); -- cgit v1.2.3 From 3a90fd575146a61d199014fda6b6420161575f41 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 19:11:23 -0800 Subject: Avoid an unnecessary temp variable --- common/threads.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/common/threads.c b/common/threads.c index c1b062cd..999bb768 100644 --- a/common/threads.c +++ b/common/threads.c @@ -751,8 +751,8 @@ void alcnd_destroy(alcnd_t *cond) int alsem_init(alsem_t *sem, unsigned int initial) { - int ret = sem_init(sem, 0, initial); - if(ret == 0) return althrd_success; + if(sem_init(sem, 0, initial) == 0) + return althrd_success; return althrd_error; } @@ -763,23 +763,21 @@ void alsem_destroy(alsem_t *sem) int alsem_post(alsem_t *sem) { - int ret = sem_post(sem); - if(ret == 0) return althrd_success; + if(sem_post(sem) == 0) + return althrd_success; return althrd_error; } int alsem_wait(alsem_t *sem) { - int ret = sem_wait(sem); - if(ret == 0) return althrd_success; + if(sem_wait(sem) == 0) return althrd_success; if(errno == EINTR) return -2; return althrd_error; } int alsem_timedwait(alsem_t *sem, const struct timespec *time_point) { - int ret = sem_timedwait(sem, time_point); - if(ret == 0) return althrd_success; + if(sem_timedwait(sem, time_point) == 0) return althrd_success; if(errno == ETIMEDOUT) return althrd_timedout; if(errno == EINTR) return -2; return althrd_error; -- cgit v1.2.3 From 3acd2a55addecf646475bbf45aed03927c7d84e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 21:07:55 -0800 Subject: Don't generate Buffer Completed events for static sources --- Alc/mixer.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index c34284d5..11b721f1 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -698,21 +698,45 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize Counter = maxi(DstBufferSize, Counter) - DstBufferSize; firstpass = false; - /* Handle looping source position */ - if(isstatic && BufferLoopItem) + if(isstatic) { - const ALbuffer *Buffer = BufferListItem->buffers[0]; - ALsizei LoopStart = Buffer->LoopStart; - ALsizei LoopEnd = Buffer->LoopEnd; - if(DataPosInt >= LoopEnd) + if(BufferLoopItem) { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + /* Handle looping static source */ + const ALbuffer *Buffer = BufferListItem->buffers[0]; + ALsizei LoopStart = Buffer->LoopStart; + ALsizei LoopEnd = Buffer->LoopEnd; + if(DataPosInt >= LoopEnd) + { + assert(LoopEnd > LoopStart); + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + } + } + else + { + /* Handle non-looping static source */ + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); + } + + if(DataPosInt >= CompLen) + { + isplaying = false; + BufferListItem = NULL; + DataPosInt = 0; + DataPosFrac = 0; + break; + } } } else while(1) { - /* Handle non-looping or buffer queue source position */ + /* Handle streaming source */ ALsizei CompLen = 0; ALsizei i; @@ -746,6 +770,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); + /* Send any events now, after the position/buffer info was updated. */ enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { -- cgit v1.2.3 From a114d6cbb56470db87c2b0bd7c76ce26bdaeb63c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 22:24:17 -0800 Subject: Remove unused _timed methods They're not reliably implemented anyway, as some systems will just flat out fail when trying to use them. --- common/threads.c | 119 ------------------------------------------------------- common/threads.h | 4 -- 2 files changed, 123 deletions(-) diff --git a/common/threads.c b/common/threads.c index 999bb768..b95cb548 100644 --- a/common/threads.c +++ b/common/threads.c @@ -208,12 +208,6 @@ void almtx_destroy(almtx_t *mtx) DeleteCriticalSection(mtx); } -int almtx_timedlock(almtx_t* UNUSED(mtx), const struct timespec* UNUSED(ts)) -{ - /* Windows CRITICAL_SECTIONs don't seem to have a timedlock method. */ - return althrd_error; -} - #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 int alcnd_init(alcnd_t *cond) { @@ -240,30 +234,6 @@ int alcnd_wait(alcnd_t *cond, almtx_t *mtx) return althrd_error; } -int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point) -{ - struct timespec curtime; - DWORD sleeptime; - - if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) - return althrd_error; - - if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && - curtime.tv_nsec >= time_point->tv_nsec)) - { - if(SleepConditionVariableCS(cond, mtx, 0) != 0) - return althrd_success; - } - else - { - sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; - sleeptime += (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000; - if(SleepConditionVariableCS(cond, mtx, sleeptime) != 0) - return althrd_success; - } - return (GetLastError()==ERROR_TIMEOUT) ? althrd_timedout : althrd_error; -} - void alcnd_destroy(alcnd_t* UNUSED(cond)) { /* Nothing to delete? */ @@ -348,37 +318,6 @@ int alcnd_wait(alcnd_t *cond, almtx_t *mtx) return althrd_success; } -int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point) -{ - _int_alcnd_t *icond = cond->Ptr; - struct timespec curtime; - DWORD sleeptime; - int res; - - if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) - return althrd_error; - - if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && - curtime.tv_nsec >= time_point->tv_nsec)) - sleeptime = 0; - else - { - sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; - sleeptime += (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000; - } - - IncrementRef(&icond->wait_count); - LeaveCriticalSection(mtx); - - res = WaitForMultipleObjects(2, icond->events, FALSE, sleeptime); - - if(DecrementRef(&icond->wait_count) == 0 && res == WAIT_OBJECT_0+BROADCAST) - ResetEvent(icond->events[BROADCAST]); - EnterCriticalSection(mtx); - - return (res == WAIT_TIMEOUT) ? althrd_timedout : althrd_success; -} - void alcnd_destroy(alcnd_t *cond) { _int_alcnd_t *icond = cond->Ptr; @@ -415,29 +354,6 @@ int alsem_wait(alsem_t *sem) return althrd_error; } -int alsem_timedwait(alsem_t *sem, const struct timespec *time_point) -{ - struct timespec curtime; - DWORD sleeptime, ret; - - if(altimespec_get(&curtime, AL_TIME_UTC) != AL_TIME_UTC) - return althrd_error; - - if(curtime.tv_sec > time_point->tv_sec || (curtime.tv_sec == time_point->tv_sec && - curtime.tv_nsec >= time_point->tv_nsec)) - sleeptime = 0; - else - { - sleeptime = (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000; - sleeptime += (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000; - } - - ret = WaitForSingleObject(*sem, sleeptime); - if(ret == WAIT_OBJECT_0) return althrd_success; - if(ret == WAIT_TIMEOUT) return althrd_timedout; - return althrd_error; -} - /* An associative map of uint:void* pairs. The key is the TLS index (given by * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, @@ -654,15 +570,9 @@ int almtx_init(almtx_t *mtx, int type) int ret; if(!mtx) return althrd_error; -#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK - if((type&~(almtx_recursive|almtx_timed)) != 0) - return althrd_error; -#else if((type&~almtx_recursive) != 0) return althrd_error; -#endif - type &= ~almtx_timed; if(type == almtx_plain) ret = pthread_mutex_init(mtx, NULL); else @@ -694,20 +604,6 @@ void almtx_destroy(almtx_t *mtx) pthread_mutex_destroy(mtx); } -int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) -{ -#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK - int ret = pthread_mutex_timedlock(mtx, ts); - switch(ret) - { - case 0: return althrd_success; - case ETIMEDOUT: return althrd_timedout; - case EBUSY: return althrd_busy; - } -#endif - return althrd_error; -} - int alcnd_init(alcnd_t *cond) { if(pthread_cond_init(cond, NULL) == 0) @@ -736,13 +632,6 @@ int alcnd_wait(alcnd_t *cond, almtx_t *mtx) return althrd_error; } -int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point) -{ - if(pthread_cond_timedwait(cond, mtx, time_point) == 0) - return althrd_success; - return althrd_error; -} - void alcnd_destroy(alcnd_t *cond) { pthread_cond_destroy(cond); @@ -775,14 +664,6 @@ int alsem_wait(alsem_t *sem) return althrd_error; } -int alsem_timedwait(alsem_t *sem, const struct timespec *time_point) -{ - if(sem_timedwait(sem, time_point) == 0) return althrd_success; - if(errno == ETIMEDOUT) return althrd_timedout; - if(errno == EINTR) return -2; - return althrd_error; -} - int altss_create(altss_t *tss_id, altss_dtor_t callback) { diff --git a/common/threads.h b/common/threads.h index a8096546..ffd7fac5 100644 --- a/common/threads.h +++ b/common/threads.h @@ -28,7 +28,6 @@ enum { enum { almtx_plain = 0, almtx_recursive = 1, - almtx_timed = 2 }; typedef int (*althrd_start_t)(void*); @@ -227,20 +226,17 @@ void althrd_setname(althrd_t thr, const char *name); int almtx_init(almtx_t *mtx, int type); void almtx_destroy(almtx_t *mtx); -int almtx_timedlock(almtx_t *mtx, const struct timespec *ts); int alcnd_init(alcnd_t *cond); int alcnd_signal(alcnd_t *cond); int alcnd_broadcast(alcnd_t *cond); int alcnd_wait(alcnd_t *cond, almtx_t *mtx); -int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_point); void alcnd_destroy(alcnd_t *cond); int alsem_init(alsem_t *sem, unsigned int initial); void alsem_destroy(alsem_t *sem); int alsem_post(alsem_t *sem); int alsem_wait(alsem_t *sem); -int alsem_timedwait(alsem_t *sem, const struct timespec *time_point); int altss_create(altss_t *tss_id, altss_dtor_t callback); void altss_delete(altss_t tss_id); -- cgit v1.2.3 From 6a4a88f8f5c050b2a1e312984d072d806d7c387c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Feb 2018 23:56:35 -0800 Subject: Store an index to a given source's voice For more efficient voice lookups when needed. --- OpenAL32/Include/alSource.h | 5 +++++ OpenAL32/alSource.c | 25 +++++++++++++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index b346e619..2892a245 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -100,6 +100,11 @@ typedef struct ALsource { ATOMIC_FLAG PropsClean; + /* Index into the context's Voices array. Lazily updated, only checked and + * reset when looking up the voice. + */ + ALint VoiceIdx; + /** Self ID */ ALuint id; } ALsource; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b3e98bc9..a7e5fc17 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -187,16 +187,16 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); -static inline ALvoice *GetSourceVoice(const ALsource *source, const ALCcontext *context) +static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) { - ALvoice **voice = context->Voices; - ALvoice **voice_end = voice + context->VoiceCount; - while(voice != voice_end) + ALint idx = source->VoiceIdx; + if(idx >= 0 && idx < context->VoiceCount) { - if(ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire) == source) - return *voice; - ++voice; + ALvoice *voice = context->Voices[idx]; + if(ATOMIC_LOAD(&voice->Source, almemory_order_acquire) == source) + return voice; } + source->VoiceIdx = -1; return NULL; } @@ -2567,6 +2567,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ALbufferlistitem *BufferList; ALbuffer *buffer = NULL; bool start_fading = false; + ALint vidx = -1; ALsizei s; source = LookupSource(context, sources[i]); @@ -2630,12 +2631,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) { if(ATOMIC_LOAD(&context->Voices[j]->Source, almemory_order_acquire) == NULL) { - voice = context->Voices[j]; + vidx = j; break; } } - if(voice == NULL) - voice = context->Voices[context->VoiceCount++]; + if(vidx == -1) + vidx = context->VoiceCount++; + voice = context->Voices[vidx]; ATOMIC_STORE(&voice->Playing, false, almemory_order_release); ATOMIC_FLAG_TEST_AND_SET(&source->PropsClean, almemory_order_acquire); @@ -2690,6 +2692,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + source->VoiceIdx = vidx; finish_play: WriteUnlock(&source->queue_lock); } @@ -3163,6 +3166,8 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) * ignore the test. */ ATOMIC_FLAG_TEST_AND_SET(&Source->PropsClean, almemory_order_relaxed); + + Source->VoiceIdx = -1; } static void DeinitSource(ALsource *source, ALsizei num_sends) -- cgit v1.2.3 From 28fa82378b54ecbf3fb04de2ba1c61d7b6d90503 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Feb 2018 22:24:33 -0800 Subject: Remove the individual source queue and buffer locks They're inherently protected by the mutex for their respective lists. Should those mutexes be replaced by rwlocks the individual locks should also be reinstated, but they're unlikely to be unless a lot of contention starts happening in the read-only case. --- OpenAL32/Include/alBuffer.h | 2 -- OpenAL32/Include/alSource.h | 1 - OpenAL32/alBuffer.c | 68 +++++++++++------------------------ OpenAL32/alSource.c | 87 +++------------------------------------------ 4 files changed, 24 insertions(+), 134 deletions(-) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 8eedddbc..fbe3e6e5 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -102,8 +102,6 @@ typedef struct ALbuffer { /* Number of times buffer was attached to a source (deletion can only occur when 0) */ RefCount ref; - RWLock lock; - /* Self ID */ ALuint id; } ALbuffer; diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 2892a245..277cf7f2 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -95,7 +95,6 @@ typedef struct ALsource { ATOMIC(ALenum) state; /** Source Buffer Queue head. */ - RWLock queue_lock; ALbufferlistitem *queue; ATOMIC_FLAG PropsClean; diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 10f661f6..02071abf 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -192,11 +192,7 @@ AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const else if(UNLIKELY(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)) alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - { - WriteLock(&albuf->lock); LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags); - WriteUnlock(&albuf->lock); - } UnlockBufferList(device); ALCcontext_DecRef(context); @@ -223,9 +219,7 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei buffer); else { - ALbitfieldSOFT unavailable; - WriteLock(&albuf->lock); - unavailable = (albuf->Access^access) & access; + ALbitfieldSOFT unavailable = (albuf->Access^access) & access; if(UNLIKELY(ReadRef(&albuf->ref) != 0 && !(access&AL_MAP_PERSISTENT_BIT_SOFT))) alSetError(context, AL_INVALID_OPERATION, "Mapping in-use buffer %u without persistent mapping", buffer); @@ -251,8 +245,6 @@ AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei albuf->MappedOffset = offset; albuf->MappedSize = length; } - - WriteUnlock(&albuf->lock); } UnlockBufferList(device); @@ -273,18 +265,13 @@ AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) LockBufferList(device); if((albuf=LookupBuffer(device, buffer)) == NULL) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(albuf->MappedAccess == 0) + alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); else { - WriteLock(&albuf->lock); - if(albuf->MappedAccess == 0) - alSetError(context, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); - else - { - albuf->MappedAccess = 0; - albuf->MappedOffset = 0; - albuf->MappedSize = 0; - } - WriteUnlock(&albuf->lock); + albuf->MappedAccess = 0; + albuf->MappedOffset = 0; + albuf->MappedSize = 0; } UnlockBufferList(device); @@ -304,27 +291,22 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A LockBufferList(device); if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + else if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) + alSetError(context, AL_INVALID_OPERATION, + "Flushing buffer %u while not mapped for writing", buffer); + else if(UNLIKELY(offset < albuf->MappedOffset || + offset >= albuf->MappedOffset+albuf->MappedSize || + length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) + alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + offset, length, buffer); else { - WriteLock(&albuf->lock); - if(UNLIKELY(!(albuf->MappedAccess&AL_MAP_WRITE_BIT_SOFT))) - alSetError(context, AL_INVALID_OPERATION, - "Flushing buffer %u while not mapped for writing", buffer); - else if(UNLIKELY(offset < albuf->MappedOffset || - offset >= albuf->MappedOffset+albuf->MappedSize || - length <= 0 || length > albuf->MappedOffset+albuf->MappedSize-offset)) - alSetError(context, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", - offset, length, buffer); - else - { - /* FIXME: Need to use some method of double-buffering for the mixer - * and app to hold separate memory, which can be safely transfered - * asynchronously. Currently we just say the app shouldn't write - * where OpenAL's reading, and hope for the best... - */ - ATOMIC_THREAD_FENCE(almemory_order_seq_cst); - } - WriteUnlock(&albuf->lock); + /* FIXME: Need to use some method of double-buffering for the mixer and + * app to hold separate memory, which can be safely transfered + * asynchronously. Currently we just say the app shouldn't write where + * OpenAL's reading, and hope for the best... + */ + ATOMIC_THREAD_FENCE(almemory_order_seq_cst); } UnlockBufferList(device); @@ -356,7 +338,6 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons ALsizei num_chans; void *dst; - WriteLock(&albuf->lock); unpack_align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign); align = SanitizeAlignment(srctype, unpack_align); if(UNLIKELY(align < 1)) @@ -412,8 +393,6 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons } } } - - WriteUnlock(&albuf->lock); } UnlockBufferList(device); @@ -638,7 +617,6 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val else switch(param) { case AL_LOOP_POINTS_SOFT: - WriteLock(&albuf->lock); if(UNLIKELY(ReadRef(&albuf->ref) != 0)) alSetError(context, AL_INVALID_OPERATION, "Modifying in-use buffer %u's loop points", buffer); @@ -650,7 +628,6 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val albuf->LoopStart = values[0]; albuf->LoopEnd = values[1]; } - WriteUnlock(&albuf->lock); break; default: @@ -776,10 +753,8 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_SIZE: - ReadLock(&albuf->lock); *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); - ReadUnlock(&albuf->lock); break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: @@ -857,10 +832,8 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values else switch(param) { case AL_LOOP_POINTS_SOFT: - ReadLock(&albuf->lock); values[0] = albuf->LoopStart; values[1] = albuf->LoopEnd; - ReadUnlock(&albuf->lock); break; default: @@ -1279,7 +1252,6 @@ static ALbuffer *AllocBuffer(ALCcontext *context) } memset(buffer, 0, sizeof(*buffer)); - RWLockInit(&buffer->lock); /* Add 1 to avoid buffer ID 0. */ buffer->id = ((lidx<<6) | slidx) + 1; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index a7e5fc17..7c978b98 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -651,14 +651,11 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p voice = GetSourceVoice(Source, Context); if(voice) { - WriteLock(&Source->queue_lock); if(ApplyOffset(Source, voice) == AL_FALSE) { - WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid offset"); } - WriteUnlock(&Source->queue_lock); } ALCdevice_Unlock(Context->Device); } @@ -784,7 +781,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_LOOPING: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - WriteLock(&Source->queue_lock); Source->Looping = (ALboolean)*values; if(IsPlayingOrPaused(Source)) { @@ -804,7 +800,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p althrd_yield(); } } - WriteUnlock(&Source->queue_lock); return AL_TRUE; case AL_BUFFER: @@ -816,11 +811,9 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values); } - WriteLock(&Source->queue_lock); if(buffer && buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) { - WriteUnlock(&Source->queue_lock); UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting non-persistently mapped buffer %u", buffer->id); @@ -830,7 +823,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALenum state = GetSourceState(Source, GetSourceVoice(Source, Context)); if(state == AL_PLAYING || state == AL_PAUSED) { - WriteUnlock(&Source->queue_lock); UnlockBufferList(device); SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting buffer on playing or paused source %u", Source->id); @@ -858,7 +850,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->SourceType = AL_UNDETERMINED; Source->queue = NULL; } - WriteUnlock(&Source->queue_lock); UnlockBufferList(device); /* Delete all elements in the previous queue */ @@ -893,15 +884,12 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p voice = GetSourceVoice(Source, Context); if(voice) { - WriteLock(&Source->queue_lock); if(ApplyOffset(Source, voice) == AL_FALSE) { - WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); SETERR_RETURN(Context, AL_INVALID_VALUE, AL_FALSE, "Invalid source offset"); } - WriteUnlock(&Source->queue_lock); } ALCdevice_Unlock(Context->Device); } @@ -1298,7 +1286,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_SEC_LENGTH_SOFT: - ReadLock(&Source->queue_lock); if(!(BufferList=Source->queue)) *values = 0; else @@ -1322,7 +1309,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p } while(BufferList != NULL); *values = (ALdouble)length / (ALdouble)freq; } - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_SOURCE_RADIUS: @@ -1436,11 +1422,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_BUFFER: - ReadLock(&Source->queue_lock); BufferList = (Source->SourceType == AL_STATIC) ? Source->queue : NULL; *values = (BufferList && BufferList->num_buffers >= 1 && BufferList->buffers[0]) ? BufferList->buffers[0]->id : 0; - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_SOURCE_STATE: @@ -1448,7 +1432,6 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p return AL_TRUE; case AL_BYTE_LENGTH_SOFT: - ReadLock(&Source->queue_lock); if(!(BufferList=Source->queue)) *values = 0; else @@ -1491,11 +1474,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } while(BufferList != NULL); *values = length; } - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_SAMPLE_LENGTH_SOFT: - ReadLock(&Source->queue_lock); if(!(BufferList=Source->queue)) *values = 0; else @@ -1514,11 +1495,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } while(BufferList != NULL); *values = length; } - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_BUFFERS_QUEUED: - ReadLock(&Source->queue_lock); if(!(BufferList=Source->queue)) *values = 0; else @@ -1530,11 +1509,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } while(BufferList != NULL); *values = count; } - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_BUFFERS_PROCESSED: - ReadLock(&Source->queue_lock); if(Source->Looping || Source->SourceType != AL_STREAMING) { /* Buffers on a looping source are in a perpetual state of @@ -1561,7 +1538,6 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p } *values = played; } - ReadUnlock(&Source->queue_lock); return AL_TRUE; case AL_SOURCE_TYPE: @@ -2571,7 +2547,6 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ALsizei s; source = LookupSource(context, sources[i]); - WriteLock(&source->queue_lock); /* Check that there is a queue containing at least one valid, non zero * length Buffer. */ @@ -2598,7 +2573,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; - goto finish_play; + continue; } voice = GetSourceVoice(source, context); @@ -2610,14 +2585,14 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); - goto finish_play; + continue; case AL_PAUSED: assert(voice != NULL); /* A source that's paused simply resumes. */ ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); - goto finish_play; + continue; default: break; @@ -2693,8 +2668,6 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); source->VoiceIdx = vidx; - finish_play: - WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2732,7 +2705,6 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - WriteLock(&source->queue_lock); if((voice=GetSourceVoice(source, context)) != NULL) { ATOMIC_STORE(&voice->Playing, false, almemory_order_release); @@ -2741,7 +2713,6 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) } if(GetSourceState(source, voice) == AL_PLAYING) ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release); - WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2779,7 +2750,6 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - WriteLock(&source->queue_lock); if((voice=GetSourceVoice(source, context)) != NULL) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); @@ -2791,7 +2761,6 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; - WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2829,7 +2798,6 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - WriteLock(&source->queue_lock); if((voice=GetSourceVoice(source, context)) != NULL) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); @@ -2841,7 +2809,6 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; - WriteUnlock(&source->queue_lock); } ALCdevice_Unlock(device); @@ -2875,10 +2842,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu if((source=LookupSource(context, src)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); - WriteLock(&source->queue_lock); if(source->SourceType == AL_STATIC) { - WriteUnlock(&source->queue_lock); /* Can't queue on a Static Source */ SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); } @@ -2903,11 +2868,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu { ALbuffer *buffer = NULL; if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - { - WriteUnlock(&source->queue_lock); SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", buffers[i]); - } if(!BufferListStart) { @@ -2927,18 +2889,11 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList->buffers[0] = buffer; if(!buffer) continue; - /* Hold a read lock on each buffer being queued while checking all - * provided buffers. This is done so other threads don't see an extra - * reference on some buffers if this operation ends up failing. */ - ReadLock(&buffer->lock); IncrementRef(&buffer->ref); if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) - { - WriteUnlock(&source->queue_lock); SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, "Queueing non-persistently mapped buffer %u", buffer->id); - } if(BufferFmt == NULL) BufferFmt = buffer; @@ -2946,7 +2901,6 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferFmt->FmtChannels != buffer->FmtChannels || BufferFmt->OriginalType != buffer->OriginalType) { - WriteUnlock(&source->queue_lock); alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); buffer_error: @@ -2959,10 +2913,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu for(i = 0;i < BufferListStart->num_buffers;i++) { if((buffer=BufferListStart->buffers[i]) != NULL) - { DecrementRef(&buffer->ref); - ReadUnlock(&buffer->lock); - } } al_free(BufferListStart); BufferListStart = next; @@ -2971,17 +2922,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu goto done; } } - /* All buffers good, unlock them now. */ - BufferList = BufferListStart; - while(BufferList != NULL) - { - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) ReadUnlock(&buffer->lock); - } - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } + /* All buffers good. */ UnlockBufferList(device); /* Source is now streaming */ @@ -2996,7 +2937,6 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = next; ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); } - WriteUnlock(&source->queue_lock); done: UnlockSourceList(context); @@ -3025,18 +2965,11 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint /* Nothing to unqueue. */ if(nb == 0) goto done; - WriteLock(&source->queue_lock); if(source->Looping) - { - WriteUnlock(&source->queue_lock); SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from looping source %u", src); - } if(source->SourceType != AL_STREAMING) - { - WriteUnlock(&source->queue_lock); SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", src); - } /* Find the new buffer queue head */ OldTail = source->queue; @@ -3055,15 +2988,11 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint } } if(i != nb) - { - WriteUnlock(&source->queue_lock); SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); - } /* Swap it, and cut the new head from the old. */ OldHead = source->queue; source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel); - WriteUnlock(&source->queue_lock); while(OldHead != NULL) { @@ -3092,8 +3021,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) { ALsizei i; - RWLockInit(&Source->queue_lock); - Source->InnerAngle = 360.0f; Source->OuterAngle = 360.0f; Source->Pitch = 1.0f; @@ -3319,7 +3246,6 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui ALuint refcount; ALvoice *voice; - ReadLock(&Source->queue_lock); do { Current = NULL; readPos = 0; @@ -3359,7 +3285,6 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui readPos = minu64(readPos, U64(0x7fffffffffffffff)); } - ReadUnlock(&Source->queue_lock); return (ALint64)readPos; } @@ -3377,7 +3302,6 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint ALdouble offset; ALvoice *voice; - ReadLock(&Source->queue_lock); do { Current = NULL; readPos = 0; @@ -3435,7 +3359,6 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint (ALdouble)BufferFmt->Frequency; } - ReadUnlock(&Source->queue_lock); return offset; } @@ -3455,7 +3378,6 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte ALdouble offset; ALvoice *voice; - ReadLock(&Source->queue_lock); do { Current = NULL; readPos = readPosFrac = 0; @@ -3552,7 +3474,6 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte } } - ReadUnlock(&Source->queue_lock); return offset; } -- cgit v1.2.3 From 80cc32d77b73e7c7625c35e37340c14e430c2618 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Feb 2018 22:59:06 -0800 Subject: Remove the unused thunk code --- Alc/ALc.c | 4 -- CMakeLists.txt | 1 - OpenAL32/Include/alThunk.h | 20 --------- OpenAL32/alAuxEffectSlot.c | 1 - OpenAL32/alBuffer.c | 1 - OpenAL32/alEffect.c | 1 - OpenAL32/alFilter.c | 1 - OpenAL32/alSource.c | 1 - OpenAL32/alThunk.c | 108 --------------------------------------------- 9 files changed, 138 deletions(-) delete mode 100644 OpenAL32/Include/alThunk.h delete mode 100644 OpenAL32/alThunk.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 8ed10ac6..dfda8381 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -32,7 +32,6 @@ #include "alMain.h" #include "alSource.h" #include "alListener.h" -#include "alThunk.h" #include "alSource.h" #include "alBuffer.h" #include "alAuxEffectSlot.h" @@ -882,8 +881,6 @@ static void alc_init(void) ret = almtx_init(&ListLock, almtx_recursive); assert(ret == althrd_success); - - ThunkInit(); } static void alc_initconfig(void) @@ -1237,7 +1234,6 @@ static void alc_deinit_safe(void) FreeHrtfs(); FreeALConfig(); - ThunkExit(); almtx_destroy(&ListLock); altss_delete(LocalContext); diff --git a/CMakeLists.txt b/CMakeLists.txt index b5c65c55..5d665e72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -707,7 +707,6 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c OpenAL32/alListener.c OpenAL32/alSource.c OpenAL32/alState.c - OpenAL32/alThunk.c OpenAL32/event.c OpenAL32/sample_cvt.c ) diff --git a/OpenAL32/Include/alThunk.h b/OpenAL32/Include/alThunk.h deleted file mode 100644 index adc77dec..00000000 --- a/OpenAL32/Include/alThunk.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef ALTHUNK_H -#define ALTHUNK_H - -#include "alMain.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void ThunkInit(void); -void ThunkExit(void); -ALenum NewThunkEntry(ALuint *index); -void FreeThunkEntry(ALuint index); - -#ifdef __cplusplus -} -#endif - -#endif //ALTHUNK_H - diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 5400a914..038adbb0 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -27,7 +27,6 @@ #include "AL/alc.h" #include "alMain.h" #include "alAuxEffectSlot.h" -#include "alThunk.h" #include "alError.h" #include "alListener.h" #include "alSource.h" diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index 02071abf..ed712434 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -32,7 +32,6 @@ #include "alu.h" #include "alError.h" #include "alBuffer.h" -#include "alThunk.h" #include "sample_cvt.h" diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 39f6f330..f4258e60 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -28,7 +28,6 @@ #include "AL/alc.h" #include "alMain.h" #include "alEffect.h" -#include "alThunk.h" #include "alError.h" diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index de527fea..70ae901c 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -25,7 +25,6 @@ #include "alMain.h" #include "alu.h" #include "alFilter.h" -#include "alThunk.h" #include "alError.h" diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 7c978b98..e56e252c 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -31,7 +31,6 @@ #include "alError.h" #include "alSource.h" #include "alBuffer.h" -#include "alThunk.h" #include "alAuxEffectSlot.h" #include "backends/base.h" diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c deleted file mode 100644 index 0d90760a..00000000 --- a/OpenAL32/alThunk.c +++ /dev/null @@ -1,108 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alThunk.h" - -#include "almalloc.h" - - -static ATOMIC_FLAG *ThunkArray; -static ALsizei ThunkArraySize; -static RWLock ThunkLock; - -void ThunkInit(void) -{ - RWLockInit(&ThunkLock); - ThunkArraySize = 1024; - ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray)); -} - -void ThunkExit(void) -{ - al_free(ThunkArray); - ThunkArray = NULL; - ThunkArraySize = 0; -} - -ALenum NewThunkEntry(ALuint *index) -{ - void *NewList; - ALsizei i; - - ReadLock(&ThunkLock); - for(i = 0;i < ThunkArraySize;i++) - { - if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel)) - { - ReadUnlock(&ThunkLock); - *index = i+1; - return AL_NO_ERROR; - } - } - ReadUnlock(&ThunkLock); - - WriteLock(&ThunkLock); - /* Double-check that there's still no free entries, in case another - * invocation just came through and increased the size of the array. - */ - for(;i < ThunkArraySize;i++) - { - if(!ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_acq_rel)) - { - WriteUnlock(&ThunkLock); - *index = i+1; - return AL_NO_ERROR; - } - } - - NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray)); - if(!NewList) - { - WriteUnlock(&ThunkLock); - ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2); - return AL_OUT_OF_MEMORY; - } - memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray)); - al_free(ThunkArray); - ThunkArray = NewList; - ThunkArraySize *= 2; - - ATOMIC_FLAG_TEST_AND_SET(&ThunkArray[i], almemory_order_seq_cst); - *index = ++i; - - for(;i < ThunkArraySize;i++) - ATOMIC_FLAG_CLEAR(&ThunkArray[i], almemory_order_relaxed); - WriteUnlock(&ThunkLock); - - return AL_NO_ERROR; -} - -void FreeThunkEntry(ALuint index) -{ - ReadLock(&ThunkLock); - if(index > 0 && (ALsizei)index <= ThunkArraySize) - ATOMIC_FLAG_CLEAR(&ThunkArray[index-1], almemory_order_release); - ReadUnlock(&ThunkLock); -} -- cgit v1.2.3 From 8f4c078fb569d47dcd53bfb1b69ac2da8ebb0341 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Feb 2018 23:08:29 -0800 Subject: Add missing header for UINT_MAX --- Alc/ringbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c index e029e9b6..c594331e 100644 --- a/Alc/ringbuffer.c +++ b/Alc/ringbuffer.c @@ -22,6 +22,7 @@ #include #include +#include #include "ringbuffer.h" #include "align.h" -- cgit v1.2.3 From 40bda4d93f15b5b089b6736eb9fd2d04f8e683eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Feb 2018 01:07:06 -0800 Subject: Add a disconnected event type --- Alc/ALu.c | 17 +++++++++++++++++ Alc/inprogext.h | 1 + OpenAL32/Include/alMain.h | 1 + OpenAL32/Include/alu.h | 2 +- OpenAL32/event.c | 2 ++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 8d2e5727..2a89f455 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -38,6 +38,7 @@ #include "uhjfilter.h" #include "bformatdec.h" #include "static_assert.h" +#include "ringbuffer.h" #include "fpu_modes.h" #include "cpu_caps.h" @@ -1859,6 +1860,22 @@ void aluHandleDisconnect(ALCdevice *device) while(ctx) { ALsizei i; + + if((ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire)&EventType_Disconnected)) + { + AsyncEvent evt; + evt.EnumType = EventType_Disconnected; + evt.Type = AL_EVENT_TYPE_DISCONNECTED_SOFT; + evt.ObjectId = 0; + evt.Param = 0; + strcpy(evt.Message, "Device disconnected"); + if(ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) + { + ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1); + alsem_post(&ctx->EventSem); + } + } + for(i = 0;i < ctx->VoiceCount;i++) { ALvoice *voice = ctx->Voices[i]; diff --git a/Alc/inprogext.h b/Alc/inprogext.h index 721f2370..619b604f 100644 --- a/Alc/inprogext.h +++ b/Alc/inprogext.h @@ -56,6 +56,7 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A #define AL_EVENT_TYPE_ERROR_SOFT 0x1224 #define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 #define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 +#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x1227 typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index bc5a27c8..5c2435a4 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -612,6 +612,7 @@ enum { EventType_Error = 1<<2, EventType_Performance = 1<<3, EventType_Deprecated = 1<<4, + EventType_Disconnected = 1<<5, }; typedef struct AsyncEvent { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 2e2e1f5a..0d39729d 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -519,7 +519,7 @@ inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); -/* Caller must lock the device. */ +/* Caller must lock the device, and the mixer must not be running. */ void aluHandleDisconnect(ALCdevice *device); void UpdateContextProps(ALCcontext *context); diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 38c12d98..f65efc7c 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -61,6 +61,8 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A flags |= EventType_Performance; else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT) flags |= EventType_Deprecated; + else if(types[i] == AL_EVENT_TYPE_DISCONNECTED_SOFT) + flags |= EventType_Disconnected; else SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); } -- cgit v1.2.3 From 4ef60d7214c28f58e2686006766556a92fc7d2c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Feb 2018 01:26:04 -0800 Subject: Add a couple missing lock calls --- OpenAL32/alSource.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e56e252c..c20226ca 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1324,7 +1324,9 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p * clock time with the device latency. Order is important. */ values[0] = GetSourceSecOffset(Source, Context, &srcclock); + almtx_lock(&device->BackendLock); clocktime = V0(device->Backend,getClockLatency)(); + almtx_unlock(&device->BackendLock); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = (ALdouble)clocktime.Latency / 1000000000.0; else @@ -1655,7 +1657,9 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp * clock time with the device latency. Order is important. */ values[0] = GetSourceSampleOffset(Source, Context, &srcclock); + almtx_lock(&device->BackendLock); clocktime = V0(device->Backend,getClockLatency)(); + almtx_unlock(&device->BackendLock); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = clocktime.Latency; else -- cgit v1.2.3 From e49607078e7d34eaf2f7daecc2ee6bf6ece353c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Feb 2018 01:58:55 -0800 Subject: Handle disconnected events in alffplay --- examples/alffplay.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 1c8d5697..7f83f61d 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -60,6 +60,7 @@ typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offs #define AL_EVENT_TYPE_ERROR_SOFT 0x1224 #define AL_EVENT_TYPE_PERFORMANCE_SOFT 0x1225 #define AL_EVENT_TYPE_DEPRECATED_SOFT 0x1226 +#define AL_EVENT_TYPE_DISCONNECTED_SOFT 0x1227 typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam); @@ -238,12 +239,13 @@ struct AudioState { std::mutex mSrcMutex; std::condition_variable mSrcCond; + std::atomic_flag mConnected; ALuint mSource{0}; std::vector mBuffers; ALsizei mBufferIdx{0}; AudioState(MovieState &movie) : mMovie(movie) - { } + { mConnected.test_and_set(std::memory_order_relaxed); } ~AudioState() { if(mSource) @@ -703,6 +705,7 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui case AL_EVENT_TYPE_ERROR_SOFT: std::cout<< "API error"; break; case AL_EVENT_TYPE_PERFORMANCE_SOFT: std::cout<< "Performance"; break; case AL_EVENT_TYPE_DEPRECATED_SOFT: std::cout<< "Deprecated"; break; + case AL_EVENT_TYPE_DISCONNECTED_SOFT: std::cout<< "Disconnected"; break; default: std::cout<< "0x"< lock(self->mSrcMutex); + self->mConnected.clear(std::memory_order_release); + } + std::unique_lock(self->mSrcMutex).unlock(); + self->mSrcCond.notify_one(); + } } int AudioState::handler() { - const std::array types{{ + const std::array types{{ AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, - AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT + AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT, + AL_EVENT_TYPE_DISCONNECTED_SOFT }}; std::unique_lock lock(mSrcMutex); milliseconds sleep_time = AudioBufferTime / 3; @@ -888,7 +901,8 @@ int AudioState::handler() } } - while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed)) + while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && + mConnected.test_and_set(std::memory_order_relaxed)) { /* First remove any processed buffers. */ ALint processed; -- cgit v1.2.3 From b99e64a0e3759d326b53578516a4ca5084046e7c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Feb 2018 13:54:42 -0800 Subject: Provide more descriptive messages to disconnection events --- Alc/ALc.c | 10 +++++----- Alc/ALu.c | 43 ++++++++++++++++++++++++++++++------------- Alc/backends/alsa.c | 13 +++++++------ Alc/backends/dsound.c | 14 ++++++++------ Alc/backends/jack.c | 2 +- Alc/backends/mmdevapi.c | 10 +++++----- Alc/backends/opensl.c | 9 +++++---- Alc/backends/oss.c | 9 +++++---- Alc/backends/pulseaudio.c | 17 +++++++++-------- Alc/backends/qsa.c | 11 ++++++----- Alc/backends/sndio.c | 2 +- Alc/backends/solaris.c | 5 +++-- Alc/backends/wave.c | 2 +- OpenAL32/Include/alu.h | 2 +- 14 files changed, 87 insertions(+), 62 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index dfda8381..3c9598ca 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3810,7 +3810,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(err == ALC_INVALID_DEVICE) { V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Device update failure"); V0(device->Backend,unlock)(); } ALCdevice_DecRef(device); @@ -4397,7 +4397,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) device->Flags |= DEVICE_RUNNING; else { - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Device start failure"); alcSetError(device, ALC_INVALID_DEVICE); } } @@ -4621,10 +4621,10 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) device->Flags |= DEVICE_RUNNING; else { - alcSetError(device, ALC_INVALID_DEVICE); V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Device start failure"); V0(device->Backend,unlock)(); + alcSetError(device, ALC_INVALID_DEVICE); } } } @@ -4694,7 +4694,7 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi if(err == ALC_INVALID_DEVICE) { V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Device start failure"); V0(device->Backend,unlock)(); } ALCdevice_DecRef(device); diff --git a/Alc/ALu.c b/Alc/ALu.c index 2a89f455..9f4f7a30 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1850,30 +1850,47 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) } -void aluHandleDisconnect(ALCdevice *device) +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) { ALCcontext *ctx; + AsyncEvent evt; + va_list args; + int msglen; device->Connected = ALC_FALSE; + evt.EnumType = EventType_Disconnected; + evt.Type = AL_EVENT_TYPE_DISCONNECTED_SOFT; + evt.ObjectId = 0; + evt.Param = 0; + + va_start(args, msg); + msglen = vsnprintf(evt.Message, sizeof(evt.Message), msg, args); + va_end(args); + + if(msglen < 0 || (size_t)msglen >= sizeof(evt.Message)) + { + evt.Message[sizeof(evt.Message)-1] = 0; + msglen = (int)strlen(evt.Message); + } + if(msglen > 0) + msg = evt.Message; + else + { + msg = ""; + msglen = (int)strlen(msg); + } + ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) { ALsizei i; - if((ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire)&EventType_Disconnected)) + if((ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire)&EventType_Disconnected) && + ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) { - AsyncEvent evt; - evt.EnumType = EventType_Disconnected; - evt.Type = AL_EVENT_TYPE_DISCONNECTED_SOFT; - evt.ObjectId = 0; - evt.Param = 0; - strcpy(evt.Message, "Device disconnected"); - if(ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) - { - ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1); - alsem_post(&ctx->EventSem); - } + ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1); + alsem_post(&ctx->EventSem); } for(i = 0;i < ctx->VoiceCount;i++) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 915d31d3..72e2936f 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -502,7 +502,7 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) { ERR("Invalid state detected: %s\n", snd_strerror(state)); ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); ALCplaybackAlsa_unlock(self); break; } @@ -592,7 +592,7 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) { ERR("Invalid state detected: %s\n", snd_strerror(state)); ALCplaybackAlsa_lock(self); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state)); ALCplaybackAlsa_unlock(self); break; } @@ -1155,7 +1155,8 @@ static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) if(err < 0) { ERR("start failed: %s\n", snd_strerror(err)); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s", + snd_strerror(err)); return ALC_FALSE; } @@ -1249,7 +1250,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); break; } /* If the amount available is less than what's asked, we lost it @@ -1290,7 +1291,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) if(avail < 0) { ERR("restore error: %s\n", snd_strerror(avail)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail)); } } @@ -1329,7 +1330,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) if(amt < 0) { ERR("restore error: %s\n", snd_strerror(amt)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt)); break; } avail = amt; diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 3d130615..bca8b7f0 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -267,7 +267,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) { ERR("Failed to get buffer caps: 0x%lx\n", err); ALCdevice_Lock(device); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err); ALCdevice_Unlock(device); return 1; } @@ -291,7 +291,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) { ERR("Failed to play buffer: 0x%lx\n", err); ALCdevice_Lock(device); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err); ALCdevice_Unlock(device); return 1; } @@ -339,7 +339,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) { ERR("Buffer lock error: %#lx\n", err); ALCdevice_Lock(device); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err); ALCdevice_Unlock(device); return 1; } @@ -894,7 +894,8 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failure starting capture: 0x%lx", hr); return ALC_FALSE; } @@ -909,7 +910,8 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self) if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failure stopping capture: 0x%lx", hr); } } @@ -959,7 +961,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) if(FAILED(hr)) { ERR("update failed: 0x%08lx\n", hr); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); } done: diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 14032d45..2f17bbf6 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -241,7 +241,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) if(!self->Ring) { ERR("Failed to reallocate ringbuffer\n"); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize); } ALCjackPlayback_unlock(self); return 0; diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index d63d22df..5f1dbba8 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -632,7 +632,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) { ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); V0(device->Backend,unlock)(); return 1; } @@ -649,7 +649,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) { ERR("Failed to get padding: 0x%08lx\n", hr); V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); V0(device->Backend,unlock)(); break; } @@ -679,7 +679,7 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) { ERR("Failed to buffer data: 0x%08lx\n", hr); V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); V0(device->Backend,unlock)(); break; } @@ -1326,7 +1326,7 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) { ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); V0(device->Backend,unlock)(); return 1; } @@ -1415,7 +1415,7 @@ FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) if(FAILED(hr)) { V0(device->Backend,lock)(); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); V0(device->Backend,unlock)(); break; } diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index fb56b67c..93d2e521 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -255,7 +255,7 @@ static int ALCopenslPlayback_mixerProc(void *arg) if(SL_RESULT_SUCCESS != result) { ALCopenslPlayback_lock(self); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); ALCopenslPlayback_unlock(self); return 1; } @@ -283,7 +283,7 @@ static int ALCopenslPlayback_mixerProc(void *arg) } if(SL_RESULT_SUCCESS != result) { - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result); break; } @@ -919,7 +919,8 @@ static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self) if(SL_RESULT_SUCCESS != result) { ALCopenslCapture_lock(self); - aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, + "Failed to start capture: 0x%08x", result); ALCopenslCapture_unlock(self); return ALC_FALSE; } @@ -1002,7 +1003,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * if(SL_RESULT_SUCCESS != result) { ALCopenslCapture_lock(self); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result); ALCopenslCapture_unlock(self); return ALC_INVALID_DEVICE; } diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index b2d9c555..9b0c2d42 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -299,7 +299,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr) if(errno == EINTR) continue; ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); break; } else if(sret == 0) @@ -319,7 +319,8 @@ static int ALCplaybackOSS_mixerProc(void *ptr) if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed writing playback samples: %s", + strerror(errno)); break; } @@ -566,7 +567,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) if(errno == EINTR) continue; ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno)); break; } else if(sret == 0) @@ -583,7 +584,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) { ERR("read failed: %s\n", strerror(errno)); ALCcaptureOSS_lock(self); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno)); ALCcaptureOSS_unlock(self); break; } diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index bcfbb6c2..28858a72 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -650,7 +650,7 @@ static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pda if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback state failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -661,7 +661,7 @@ static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback stream failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -835,7 +835,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr) if(len < 0) { ERR("Failed to get writable size: %ld", (long)len); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len); break; } @@ -1388,7 +1388,7 @@ static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdat if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture state failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -1399,7 +1399,7 @@ static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata) if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); - aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice); + aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture stream failure"); } pa_threaded_mainloop_signal(self->loop, 0); } @@ -1662,14 +1662,15 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu state = pa_stream_get_state(self->stream); if(!PA_STREAM_IS_GOOD(state)) { - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Bad capture state: %u", state); break; } 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(self->context))); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed retrieving capture samples: %s", + pa_strerror(pa_context_errno(self->context))); break; } self->cap_remain = self->cap_len; @@ -1710,7 +1711,7 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) if(got < 0) { ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got)); } else if((size_t)got > self->cap_len) readable += got - self->cap_len; diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 614d738c..484cadaa 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -220,7 +220,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) if(sret == -1) { ERR("select error: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno)); break; } if(sret == 0) @@ -251,7 +251,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) { if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0) { - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Playback recovery failed"); break; } } @@ -847,7 +847,7 @@ static ALCuint qsa_available_samples(CaptureWrapper *self) if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) { ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus)); return 0; } @@ -890,7 +890,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin switch (selectret) { case -1: - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to check capture samples"); return ALC_INVALID_DEVICE; case 0: break; @@ -921,7 +921,8 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0) { ERR("capture prepare failed: %s\n", snd_strerror(rstatus)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed capture recovery: %s", + snd_strerror(rstatus)); return ALC_INVALID_DEVICE; } snd_pcm_capture_go(data->pcmHandle); diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index f7b9af69..06a434d9 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -117,7 +117,7 @@ static int ALCsndioBackend_mixerProc(void *ptr) { ERR("sio_write failed\n"); ALCdevice_Lock(device); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to write playback samples"); ALCdevice_Unlock(device); break; } diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index 49bfad3c..fdc62562 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -135,7 +135,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr) if(errno == EINTR) continue; ERR("select failed: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno)); break; } else if(sret == 0) @@ -155,7 +155,8 @@ static int ALCsolarisBackend_mixerProc(void *ptr) if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue; ERR("write failed: %s\n", strerror(errno)); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to write playback samples: %s", + strerror(errno)); break; } diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index ecb066f8..13ffaeec 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -204,7 +204,7 @@ static int ALCwaveBackend_mixerProc(void *ptr) { ERR("Error writing to file\n"); ALCdevice_Lock(device); - aluHandleDisconnect(device); + aluHandleDisconnect(device, "Failed to write playback samples"); ALCdevice_Unlock(device); break; } diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 0d39729d..920b7b44 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -520,7 +520,7 @@ ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples); /* Caller must lock the device, and the mixer must not be running. */ -void aluHandleDisconnect(ALCdevice *device); +void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3); void UpdateContextProps(ALCcontext *context); -- cgit v1.2.3 From 1f61472e77faa0b57231b19236272d3e4d67fbc0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Feb 2018 13:57:04 -0800 Subject: Avoid potentially writing partial samples --- Alc/backends/pulseaudio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 28858a72..6ba82cd2 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -876,8 +876,10 @@ static int ALCpulsePlayback_mixerProc(void *ptr) free_func = pa_xfree; } - aluMixData(device, buf, newlen/frame_size); + newlen /= frame_size; + aluMixData(device, buf, newlen); + newlen *= frame_size; ret = pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); if(ret != PA_OK) { -- cgit v1.2.3 From 9b878c64f9ec83adc4886db553ca184952ff50b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Feb 2018 00:01:12 -0800 Subject: Make the Connected state atomic Also don't send the Disconnected event more than once. --- Alc/ALc.c | 20 +++++++++++--------- Alc/ALu.c | 3 ++- Alc/backends/alsa.c | 18 +++++++++--------- Alc/backends/dsound.c | 14 +++++++------- Alc/backends/jack.c | 3 ++- Alc/backends/null.c | 13 +++++++------ Alc/backends/opensl.c | 3 ++- Alc/backends/oss.c | 3 ++- Alc/backends/pulseaudio.c | 13 +++++++------ Alc/backends/qsa.c | 13 ++++++------- Alc/backends/sndio.c | 14 +++++++------- Alc/backends/solaris.c | 3 ++- Alc/backends/wave.c | 13 ++++++------- Alc/backends/winmm.c | 24 ++++++++++-------------- OpenAL32/Include/alMain.h | 2 +- OpenAL32/alSource.c | 2 +- 16 files changed, 82 insertions(+), 79 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3c9598ca..915addac 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -3248,7 +3248,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_CAPTURE_SAMPLES; values[i++] = V0(device->Backend,availableSamples)(); values[i++] = ALC_CONNECTED; - values[i++] = device->Connected; + values[i++] = ATOMIC_LOAD(&device->Connected, almemory_order_relaxed); almtx_unlock(&device->BackendLock); values[i++] = 0; @@ -3268,7 +3268,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - values[0] = device->Connected; + values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); return 1; default: @@ -3457,7 +3457,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_CONNECTED: - values[0] = device->Connected; + values[0] = ATOMIC_LOAD(&device->Connected, almemory_order_acquire); return 1; case ALC_HRTF_SOFT: @@ -3764,7 +3764,8 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin * properly cleaned up after being made. */ LockLists(); - if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected) + if(!VerifyDevice(&device) || device->Type == Capture || + !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) { UnlockLists(); alcSetError(device, ALC_INVALID_DEVICE); @@ -4034,7 +4035,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) //Validate device InitRef(&device->ref, 1); - device->Connected = ALC_TRUE; + ATOMIC_INIT(&device->Connected, ALC_TRUE); device->Type = Playback; ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); @@ -4290,7 +4291,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, //Validate device InitRef(&device->ref, 1); - device->Connected = ALC_TRUE; + ATOMIC_INIT(&device->Connected, ALC_TRUE); device->Type = Capture; InitDevice(device); @@ -4389,7 +4390,7 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) else { almtx_lock(&device->BackendLock); - if(!device->Connected) + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) alcSetError(device, ALC_INVALID_DEVICE); else if(!(device->Flags&DEVICE_RUNNING)) { @@ -4474,7 +4475,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN //Validate device InitRef(&device->ref, 1); - device->Connected = ALC_TRUE; + ATOMIC_INIT(&device->Connected, ALC_TRUE); device->Type = Loopback; ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); @@ -4675,7 +4676,8 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi ALCenum err; LockLists(); - if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected) + if(!VerifyDevice(&device) || device->Type == Capture || + !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) { UnlockLists(); alcSetError(device, ALC_INVALID_DEVICE); diff --git a/Alc/ALu.c b/Alc/ALu.c index 9f4f7a30..2435558d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1857,7 +1857,8 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) va_list args; int msglen; - device->Connected = ALC_FALSE; + if(!ATOMIC_EXCHANGE(&device->Connected, AL_FALSE, almemory_order_acq_rel)) + return; evt.EnumType = EventType_Disconnected; evt.Type = AL_EVENT_TYPE_DISCONNECTED_SOFT; diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 72e2936f..c75749de 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -438,7 +438,7 @@ typedef struct ALCplaybackAlsa { ALvoid *buffer; ALsizei size; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCplaybackAlsa; @@ -468,6 +468,8 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device) self->pcmHandle = NULL; self->buffer = NULL; + + ATOMIC_INIT(&self->killNow, AL_TRUE); } void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self) @@ -495,7 +497,7 @@ static int ALCplaybackAlsa_mixerProc(void *ptr) update_size = device->UpdateSize; num_updates = device->NumUpdates; - while(!self->killNow) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { int state = verify_state(self->pcmHandle); if(state < 0) @@ -585,7 +587,7 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr) update_size = device->UpdateSize; num_updates = device->NumUpdates; - while(!self->killNow) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { int state = verify_state(self->pcmHandle); if(state < 0) @@ -910,7 +912,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self) } thread_func = ALCplaybackAlsa_mixerProc; } - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, thread_func, self) != althrd_success) { ERR("Could not create playback thread\n"); @@ -931,10 +933,8 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - self->killNow = 1; althrd_join(self->thread, &res); al_free(self->buffer); @@ -1207,7 +1207,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff } self->last_avail -= samples; - while(device->Connected && samples > 0) + while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0) { snd_pcm_sframes_t amt = 0; @@ -1275,7 +1275,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self) ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; snd_pcm_sframes_t avail = 0; - if(device->Connected && self->doCapture) + if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture) avail = snd_pcm_avail_update(self->pcmHandle); if(avail < 0) { diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index bca8b7f0..0040a840 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -185,7 +185,7 @@ typedef struct ALCdsoundPlayback { IDirectSoundNotify *Notifies; HANDLE NotifyEvent; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCdsoundPlayback; @@ -217,6 +217,7 @@ static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *devi self->Buffer = NULL; self->Notifies = NULL; self->NotifyEvent = NULL; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self) @@ -276,7 +277,8 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) FragSize = device->UpdateSize * FrameSize; IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL); - while(!self->killNow) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { // Get current play cursor IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL); @@ -636,7 +638,7 @@ retry_open: static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self) { - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success) return ALC_FALSE; @@ -647,10 +649,8 @@ static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - self->killNow = 1; althrd_join(self->thread, &res); IDirectSoundBuffer_Stop(self->Buffer); @@ -930,7 +930,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) DWORD FrameSize; HRESULT hr; - if(!device->Connected) + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) goto done; FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 2f17bbf6..e6f4b435 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -312,7 +312,8 @@ static int ALCjackPlayback_mixerProc(void *arg) althrd_setname(althrd_current(), MIXER_THREAD_NAME); ALCjackPlayback_lock(self); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALuint todo, len1, len2; diff --git a/Alc/backends/null.c b/Alc/backends/null.c index d17c8bda..2c2db54e 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -36,7 +36,7 @@ typedef struct ALCnullBackend { DERIVE_FROM_TYPE(ALCbackend); - volatile int killNow; + ATOMIC(int) killNow; althrd_t thread; } ALCnullBackend; @@ -65,6 +65,8 @@ static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCnullBackend, ALCbackend, self); + + ATOMIC_INIT(&self->killNow, AL_TRUE); } @@ -86,7 +88,8 @@ static int ALCnullBackend_mixerProc(void *ptr) ERR("Failed to get starting time\n"); return 1; } - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) { @@ -142,7 +145,7 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self) static ALCboolean ALCnullBackend_start(ALCnullBackend *self) { - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success) return ALC_FALSE; return ALC_TRUE; @@ -152,10 +155,8 @@ static void ALCnullBackend_stop(ALCnullBackend *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - self->killNow = 1; althrd_join(self->thread, &res); } diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 93d2e521..b20d7841 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -266,7 +266,8 @@ static int ALCopenslPlayback_mixerProc(void *arg) padding = ll_ringbuffer_write_space(self->mRing) - device->NumUpdates; ALCopenslPlayback_lock(self); - while(ATOMIC_LOAD_SEQ(&self->mKillNow) == AL_FALSE && device->Connected) + while(!ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { size_t todo, len0, len1; diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 9b0c2d42..faf3ee99 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -284,7 +284,8 @@ static int ALCplaybackOSS_mixerProc(void *ptr) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCplaybackOSS_lock(self); - while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { FD_ZERO(&wfds); FD_SET(self->fd, &wfds); diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 6ba82cd2..96794e20 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -472,7 +472,7 @@ typedef struct ALCpulsePlayback { pa_stream *stream; pa_context *context; - volatile ALboolean killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCpulsePlayback; @@ -515,6 +515,7 @@ static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device self->loop = NULL; AL_STRING_INIT(self->device_name); + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self) @@ -829,7 +830,8 @@ static int ALCpulsePlayback_mixerProc(void *ptr) pa_threaded_mainloop_lock(self->loop); frame_size = pa_frame_size(&self->spec); - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { len = pa_stream_writable_size(self->stream); if(len < 0) @@ -1141,7 +1143,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self) { - self->killNow = AL_FALSE; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success) return ALC_FALSE; return ALC_TRUE; @@ -1152,10 +1154,9 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self) pa_operation *o; int res; - if(!self->stream || self->killNow) + if(!self->stream || ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - self->killNow = AL_TRUE; /* Signal the main loop in case PulseAudio isn't sending us audio requests * (e.g. if the device is suspended). We need to lock the mainloop in case * the mixer is between checking the killNow flag but before waiting for @@ -1705,7 +1706,7 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; size_t readable = self->cap_remain; - if(device->Connected) + if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ssize_t got; pa_threaded_mainloop_lock(self->loop); diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 484cadaa..8f87779b 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -46,7 +46,7 @@ typedef struct { ALvoid* buffer; ALsizei size; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } qsa_data; @@ -206,7 +206,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) ); V0(device->Backend,lock)(); - while(!data->killNow) + while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) { FD_ZERO(&wfds); FD_SET(data->audio_fd, &wfds); @@ -232,7 +232,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr) len = data->size; write_ptr = data->buffer; aluMixData(device, write_ptr, len/frame_size); - while(len>0 && !data->killNow) + while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire)) { int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len); if(wrote <= 0) @@ -282,6 +282,7 @@ static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceNam data = (qsa_data*)calloc(1, sizeof(qsa_data)); if(data == NULL) return ALC_OUT_OF_MEMORY; + ATOMIC_INIT(&data->killNow, AL_TRUE); if(!deviceName) deviceName = qsaDevice; @@ -595,7 +596,7 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self) { qsa_data *data = self->ExtraData; - data->killNow = 0; + ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success) return ALC_FALSE; @@ -607,10 +608,8 @@ static void qsa_stop_playback(PlaybackWrapper *self) qsa_data *data = self->ExtraData; int res; - if(data->killNow) + if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - data->killNow = 1; althrd_join(data->thread, &res); } diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 06a434d9..5aea457b 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -43,7 +43,7 @@ typedef struct ALCsndioBackend { ALvoid *mix_data; ALsizei data_size; - volatile int killNow; + ATOMIC(int) killNow; althrd_t thread; } ALCsndioBackend; @@ -75,6 +75,7 @@ static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device) self->sndHandle = NULL; self->mix_data = NULL; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCsndioBackend_Destruct(ALCsndioBackend *self) @@ -102,7 +103,8 @@ static int ALCsndioBackend_mixerProc(void *ptr) frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { ALsizei len = self->data_size; ALubyte *WritePtr = self->mix_data; @@ -110,7 +112,7 @@ static int ALCsndioBackend_mixerProc(void *ptr) ALCsndioBackend_lock(self); aluMixData(device, WritePtr, len/frameSize); ALCsndioBackend_unlock(self); - while(len > 0 && !self->killNow) + while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { wrote = sio_write(self->sndHandle, WritePtr, len); if(wrote == 0) @@ -253,7 +255,7 @@ static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) return ALC_FALSE; } - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success) { sio_stop(self->sndHandle); @@ -267,10 +269,8 @@ static void ALCsndioBackend_stop(ALCsndioBackend *self) { int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - self->killNow = 1; althrd_join(self->thread, &res); if(!sio_stop(self->sndHandle)) diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index fdc62562..f1c4aeaa 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -120,7 +120,8 @@ static int ALCsolarisBackend_mixerProc(void *ptr) frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); ALCsolarisBackend_lock(self); - while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { FD_ZERO(&wfds); FD_SET(self->fd, &wfds); diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 13ffaeec..557c2bf2 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -77,7 +77,7 @@ typedef struct ALCwaveBackend { ALvoid *mBuffer; ALuint mSize; - volatile int killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCwaveBackend; @@ -110,7 +110,7 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) self->mBuffer = NULL; self->mSize = 0; - self->killNow = 1; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCwaveBackend_Destruct(ALCwaveBackend *self) @@ -143,7 +143,8 @@ static int ALCwaveBackend_mixerProc(void *ptr) ERR("Failed to get starting time\n"); return 1; } - while(!self->killNow && device->Connected) + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) { @@ -355,7 +356,7 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) return ALC_FALSE; } - self->killNow = 0; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success) { free(self->mBuffer); @@ -373,10 +374,8 @@ static void ALCwaveBackend_stop(ALCwaveBackend *self) long size; int res; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - self->killNow = 1; althrd_join(self->thread, &res); free(self->mBuffer); diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 59164441..d6ecd7a9 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -148,7 +148,7 @@ typedef struct ALCwinmmPlayback { WAVEFORMATEX Format; - volatile ALboolean killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCwinmmPlayback; @@ -180,7 +180,7 @@ static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device InitRef(&self->WaveBuffersCommitted, 0); self->OutHdl = NULL; - self->killNow = AL_TRUE; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) @@ -224,7 +224,7 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) if(msg.message != WOM_DONE) continue; - if(self->killNow) + if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { if(ReadRef(&self->WaveBuffersCommitted) == 0) break; @@ -371,7 +371,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) ALint BufferSize; ALuint i; - self->killNow = AL_FALSE; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) return ALC_FALSE; @@ -402,11 +402,8 @@ static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) void *buffer = NULL; int i; - if(self->killNow) + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) return; - - // Set flag to stop processing headers - self->killNow = AL_TRUE; althrd_join(self->thread, &i); // Release the wave buffers @@ -433,7 +430,7 @@ typedef struct ALCwinmmCapture { WAVEFORMATEX Format; - volatile ALboolean killNow; + ATOMIC(ALenum) killNow; althrd_t thread; } ALCwinmmCapture; @@ -465,7 +462,7 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) InitRef(&self->WaveBuffersCommitted, 0); self->InHdl = NULL; - self->killNow = AL_TRUE; + ATOMIC_INIT(&self->killNow, AL_TRUE); } static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) @@ -474,9 +471,8 @@ static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) int i; /* Tell the processing thread to quit and wait for it to do so. */ - if(!self->killNow) + if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) { - self->killNow = AL_TRUE; PostThreadMessage(self->thread, WM_QUIT, 0, 0); althrd_join(self->thread, &i); @@ -536,7 +532,7 @@ static int ALCwinmmCapture_captureProc(void *arg) continue; /* Don't wait for other buffers to finish before quitting. We're * closing so we don't need them. */ - if(self->killNow) + if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) break; WaveHdr = ((WAVEHDR*)msg.lParam); @@ -656,7 +652,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) IncrementRef(&self->WaveBuffersCommitted); } - self->killNow = AL_FALSE; + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 5c2435a4..baf610b8 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -466,7 +466,7 @@ struct ALCdevice_struct { RefCount ref; - ALCboolean Connected; + ATOMIC(ALenum) Connected; enum DeviceType Type; ALuint Frequency; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index c20226ca..8c8b2149 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2518,7 +2518,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) device = context->Device; ALCdevice_Lock(device); /* If the device is disconnected, go right to stopped. */ - if(!device->Connected) + if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { for(i = 0;i < n;i++) { -- cgit v1.2.3 From 1d7a5dbede95c37958d06273dde07cf86db6275d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Feb 2018 15:01:04 -0800 Subject: Remove unsupported source queries --- OpenAL32/alSource.c | 124 ---------------------------------------------------- 1 file changed, 124 deletions(-) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 8c8b2149..95651f29 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -150,10 +150,6 @@ typedef enum SourceProp { /* AL_EXT_source_distance_model */ srcDistanceModel = AL_DISTANCE_MODEL, - srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT, - srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT, - srcSecLengthSOFT = AL_SEC_LENGTH_SOFT, - /* AL_SOFT_source_latency */ srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, @@ -270,9 +266,6 @@ static ALint FloatValsByProp(ALenum prop) case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: case AL_SOURCE_TYPE: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: @@ -337,9 +330,6 @@ static ALint DoubleValsByProp(ALenum prop) case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: case AL_SOURCE_TYPE: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: @@ -405,9 +395,6 @@ static ALint IntValsByProp(ALenum prop) case AL_BUFFERS_PROCESSED: case AL_SOURCE_TYPE: case AL_DIRECT_FILTER: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: @@ -469,9 +456,6 @@ static ALint Int64ValsByProp(ALenum prop) case AL_BUFFERS_PROCESSED: case AL_SOURCE_TYPE: case AL_DIRECT_FILTER: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: @@ -524,9 +508,6 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p switch(prop) { - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: case AL_SEC_OFFSET_LATENCY_SOFT: case AL_SEC_OFFSET_CLOCK_SOFT: /* Query only */ @@ -763,9 +744,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SOURCE_TYPE: case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: /* Query only */ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting read-only source property 0x%04x", prop); @@ -1115,9 +1093,6 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SOURCE_STATE: case AL_SAMPLE_OFFSET_LATENCY_SOFT: case AL_SAMPLE_OFFSET_CLOCK_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: - case AL_SEC_LENGTH_SOFT: /* Query only */ SETERR_RETURN(Context, AL_INVALID_OPERATION, AL_FALSE, "Setting read-only source property 0x%04x", prop); @@ -1214,7 +1189,6 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) { ALCdevice *device = Context->Device; - ALbufferlistitem *BufferList; ClockLatency clocktime; ALuint64 srcclock; ALint ivals[3]; @@ -1284,32 +1258,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p *values = Source->DopplerFactor; return AL_TRUE; - case AL_SEC_LENGTH_SOFT: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALint length = 0; - ALsizei freq = 1; - do { - ALsizei max_len = 0; - ALsizei i; - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer && buffer->SampleLen > 0) - { - freq = buffer->Frequency; - max_len = maxi(max_len, buffer->SampleLen); - } - } - length += max_len; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } while(BufferList != NULL); - *values = (ALdouble)length / (ALdouble)freq; - } - return AL_TRUE; - case AL_SOURCE_RADIUS: *values = Source->Radius; return AL_TRUE; @@ -1384,8 +1332,6 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: case AL_DISTANCE_MODEL: case AL_SOURCE_RESAMPLER_SOFT: case AL_SOURCE_SPATIALIZE_SOFT: @@ -1432,72 +1378,6 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p *values = GetSourceState(Source, GetSourceVoice(Source, Context)); return AL_TRUE; - case AL_BYTE_LENGTH_SOFT: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALint length = 0; - do { - ALsizei max_len = 0; - ALsizei i; - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer && buffer->SampleLen > 0) - { - ALuint byte_align, sample_align; - if(buffer->OriginalType == UserFmtIMA4) - { - ALsizei align = (buffer->OriginalAlign-1)/2 + 4; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - else if(buffer->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (buffer->OriginalAlign-2)/2 + 7; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - else - { - ALsizei align = buffer->OriginalAlign; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - - max_len = maxi(max_len, buffer->SampleLen / sample_align * byte_align); - } - } - length += max_len; - - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } while(BufferList != NULL); - *values = length; - } - return AL_TRUE; - - case AL_SAMPLE_LENGTH_SOFT: - if(!(BufferList=Source->queue)) - *values = 0; - else - { - ALint length = 0; - do { - ALsizei max_len = 0; - ALsizei i; - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) max_len = maxi(max_len, buffer->SampleLen); - } - length += max_len; - BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } while(BufferList != NULL); - *values = length; - } - return AL_TRUE; - case AL_BUFFERS_QUEUED: if(!(BufferList=Source->queue)) *values = 0; @@ -1591,7 +1471,6 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint)dvals[0]; @@ -1696,7 +1575,6 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_AIR_ABSORPTION_FACTOR: case AL_ROOM_ROLLOFF_FACTOR: case AL_CONE_OUTER_GAINHF: - case AL_SEC_LENGTH_SOFT: case AL_SOURCE_RADIUS: if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint64)dvals[0]; @@ -1733,8 +1611,6 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp case AL_SOURCE_STATE: case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: - case AL_BYTE_LENGTH_SOFT: - case AL_SAMPLE_LENGTH_SOFT: case AL_SOURCE_TYPE: case AL_DIRECT_FILTER_GAINHF_AUTO: case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: -- cgit v1.2.3 From da1ee3baba32e3a2525d90e97e172965d4f90287 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Feb 2018 19:57:22 -0800 Subject: Revert "Don't fade the all-pass delay changes" This reverts commit 799dfb732b4f49198d72649e86955ea82f45f229. --- Alc/effects/reverb.c | 76 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 64aa8916..864163be 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -226,7 +226,7 @@ typedef struct DelayLineI { typedef struct VecAllpass { DelayLineI Delay; - ALsizei Offset[NUM_LINES]; + ALsizei Offset[NUM_LINES][2]; } VecAllpass; typedef struct T60Filter { @@ -399,7 +399,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Delay.Line = NULL; for(i = 0;i < NUM_LINES;i++) { - state->Early.VecAp.Offset[i] = 0; + state->Early.VecAp.Offset[i][0] = 0; + state->Early.VecAp.Offset[i][1] = 0; state->Early.Offset[i][0] = 0; state->Early.Offset[i][1] = 0; state->Early.Coeff[i] = 0.0f; @@ -422,7 +423,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Offset[i][0] = 0; state->Late.Offset[i][1] = 0; - state->Late.VecAp.Offset[i] = 0; + state->Late.VecAp.Offset[i][0] = 0; + state->Late.VecAp.Offset[i][1] = 0; for(j = 0;j < 3;j++) { @@ -1030,7 +1032,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c length = EARLY_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Early->VecAp.Offset[i] = fastf2i(length * frequency); + Early->VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; @@ -1083,7 +1085,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Late->VecAp.Offset[i] = fastf2i(length * frequency); + Late->VecAp.Offset[i][1] = fastf2i(length * frequency); /* Calculate the length (in seconds) of each delay line. This also * applies the echo transformation. As the EAX echo depth approaches @@ -1300,8 +1302,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte for(i = 0;i < NUM_LINES;i++) { if(State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0] || + State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0] || State->Early.Offset[i][1] != State->Early.Offset[i][0] || State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || + State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || State->Late.Offset[i][1] != State->Late.Offset[i][0]) { State->FadeCount = 0; @@ -1436,26 +1440,38 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re * It works by vectorizing a regular all-pass filter and replacing the delay * element with a scattering matrix (like the one above) and a diagonal * matrix of delay elements. + * + * Two static specializations are used for transitional (cross-faded) delay + * line processing and non-transitional processing. */ -static void ApplyAllpass(ALfloat *restrict out, const ALfloat *restrict in, const ALsizei offset, - const ALfloat feedCoeff, const ALfloat xCoeff, const ALfloat yCoeff, - VecAllpass *Vap) -{ - ALfloat f[NUM_LINES], fs[NUM_LINES]; - ALfloat input; - ALsizei i; - - for(i = 0;i < NUM_LINES;i++) - { - input = in[i]; - out[i] = DelayLineOut(&Vap->Delay, offset-Vap->Offset[i], i) - - feedCoeff*input; - f[i] = input + feedCoeff*out[i]; - } - VectorPartialScatter(fs, f, xCoeff, yCoeff); - - DelayLineIn4(&Vap->Delay, offset, fs); +#define DECL_TEMPLATE(T) \ +static void VectorAllpass_##T(ALfloat *restrict out, \ + const ALfloat *restrict in, \ + const ALsizei offset, const ALfloat feedCoeff, \ + const ALfloat xCoeff, const ALfloat yCoeff, \ + const ALfloat mu, VecAllpass *Vap) \ +{ \ + ALfloat f[NUM_LINES], fs[NUM_LINES]; \ + ALfloat input; \ + ALsizei i; \ + \ + (void)mu; /* Ignore for Unfaded. */ \ + \ + for(i = 0;i < NUM_LINES;i++) \ + { \ + input = in[i]; \ + out[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ + offset-Vap->Offset[i][1], i, mu) - \ + feedCoeff*input; \ + f[i] = input + feedCoeff*out[i]; \ + } \ + VectorPartialScatter(fs, f, xCoeff, yCoeff); \ + \ + DelayLineIn4(&Vap->Delay, offset, fs); \ } +DECL_TEMPLATE(Unfaded) +DECL_TEMPLATE(Faded) +#undef DECL_TEMPLATE /* A helper to reverse vector components. */ static inline void VectorReverse(ALfloat *restrict out, const ALfloat *restrict in) @@ -1504,8 +1520,8 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ offset-State->EarlyDelayTap[j][1], j, fade \ ) * State->EarlyDelayCoeff[j]; \ \ - ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, \ - &State->Early.VecAp); \ + VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ + &State->Early.VecAp); \ \ DelayLineIn4Rev(&State->Early.Delay, offset, f); \ \ @@ -1597,7 +1613,8 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat ); LateT60Filter(fr, f, State->Late.T60); - ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, &State->Late.VecAp); + VectorAllpass_Faded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, + &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; @@ -1611,7 +1628,7 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade += FadeStep; } } -static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat UNUSED(fade), +static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALsizei (*restrict moddelay)[MAX_UPDATE_SAMPLES][2] = State->ModulationDelays; @@ -1636,7 +1653,8 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); LateT60Filter(fr, f, State->Late.T60); - ApplyAllpass(f, fr, offset, apFeedCoeff, mixX, mixY, &State->Late.VecAp); + VectorAllpass_Unfaded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, + &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; @@ -1717,8 +1735,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c for(c = 0;c < NUM_LINES;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; State->Early.Offset[c][0] = State->Early.Offset[c][1]; State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; + State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } State->Mod.Depth[0] = State->Mod.Depth[1]; -- cgit v1.2.3 From f5f996c14a7d7c46f0967eee01af9b6b77caa4a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 6 Feb 2018 02:35:08 -0800 Subject: Check for a cbrtf function --- CMakeLists.txt | 1 + common/math_defs.h | 7 +++++++ config.h.in | 3 +++ 3 files changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d665e72..17f561f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -510,6 +510,7 @@ CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F) +CHECK_SYMBOL_EXISTS(cbrtf math.h HAVE_CBRTF) IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP) diff --git a/common/math_defs.h b/common/math_defs.h index cbe9091f..428f5181 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -29,6 +29,13 @@ static inline float log2f(float f) } #endif +#ifndef HAVE_CBRTF +static inline float cbrtf(float f) +{ + return powf(f, 1.0f/3.0f); +} +#endif + #define DEG2RAD(x) ((float)(x) * (F_PI/180.0f)) #define RAD2DEG(x) ((float)(x) * (180.0f/F_PI)) diff --git a/config.h.in b/config.h.in index 8ef9057a..2abeedfd 100644 --- a/config.h.in +++ b/config.h.in @@ -89,6 +89,9 @@ /* Define if we have the log2f function */ #cmakedefine HAVE_LOG2F +/* Define if we have the cbrtf function */ +#cmakedefine HAVE_CBRTF + /* Define if we have the strtof function */ #cmakedefine HAVE_STRTOF -- cgit v1.2.3 From 4cd04f192d77d8e83a5d286e1edb1bcaf5f33ffd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Feb 2018 00:05:29 -0800 Subject: Alter tha curve of the density-related delay scale The delay scale is roughly linear with respect to room size, however the density is not linear with room size. The density is calculated by taking the room size cubed, then normalized by some factor. Unnormalizing the density and taking the cube root restores the original room size to use as a delay scale. The patch also alters the delay and all-pass line lengths to be based on a 1 meter room size, so the the room size recovered from the density acts as a direct multiple for the desired target length. Note that the room scale range is unchanged (5m to 50m), so the minimum and maximum delays are the same. It should also be noted that 50m may not be the correct room size for a density value of 1. A density value of 1 corresponds to an environment size of roughly 2.52m when converted from EAX (DENSITY_SCALE should be 16 rather than 125000), but sizes that low result in undesirable resonance in the feedback, indicating other changes are necessary for that to work. --- Alc/effects/reverb.c | 55 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 864163be..9fba183a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -82,14 +82,21 @@ static const aluMatrixf A2B = {{ static const ALfloat FadeStep = 1.0f / FADE_SAMPLES; /* The all-pass and delay lines have a variable length dependent on the - * effect's density parameter. The resulting density multiplier is: + * effect's density parameter, which helps alter the perceived environment + * size. The size-to-density conversion is a cubed scale: * - * multiplier = 1 + (density * LINE_MULTIPLIER) + * density = min(1.0, pow(size, 3.0) / DENSITY_SCALE); * - * Thus the line multiplier below will result in a maximum density multiplier - * of 10. + * The line lengths scale linearly with room size, so the inverse density + * conversion is needed, taking the cube root of the re-scaled density to + * calculate the line length multiplier: + * + * length_mult = max(5.0, cbrtf(density*DENSITY_SCALE)); + * + * The density scale below will result in a max line multiplier of 50, for an + * effective size range of 5m to 50m. */ -static const ALfloat LINE_MULTIPLIER = 9.0f; +static const ALfloat DENSITY_SCALE = 125000.0f; /* All delay line lengths are specified in seconds. * @@ -133,12 +140,11 @@ static const ALfloat LINE_MULTIPLIER = 9.0f; * T_i = R_i - r_0 * = (2^(i / (2 N - 1)) - 1) r_d * - * Assuming an average of 5m (up to 50m with the density multiplier), we get - * the following taps: + * Assuming an average of 1m, we get the following taps: */ static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = { - 0.000000e+0f, 1.010676e-3f, 2.126553e-3f, 3.358580e-3f + 0.0000000e+0f, 2.0213520e-4f, 4.2531060e-4f, 6.7171600e-4f }; /* The early all-pass filter lengths are based on the early tap lengths: @@ -149,7 +155,7 @@ static const ALfloat EARLY_TAP_LENGTHS[NUM_LINES] = */ static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = { - 4.854840e-4f, 5.360178e-4f, 5.918117e-4f, 6.534130e-4f + 9.7096800e-5f, 1.0720356e-4f, 1.1836234e-4f, 1.3068260e-4f }; /* The early delay lines are used to transform the primary reflections into @@ -172,11 +178,11 @@ static const ALfloat EARLY_ALLPASS_LENGTHS[NUM_LINES] = * = 2 (r_a - T_(N-i-1) - r_0) * = 2 r_a (1 - (2 / 3) 2^((N - i - 1) / (2 N - 1))) * - * Using an average dimension of 5m, we get: + * Using an average dimension of 1m, we get: */ static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = { - 2.992520e-3f, 5.456575e-3f, 7.688329e-3f, 9.709681e-3f + 5.9850400e-4f, 1.0913150e-3f, 1.5376658e-3f, 1.9419362e-3f }; /* The late all-pass filter lengths are based on the late line lengths: @@ -185,7 +191,7 @@ static const ALfloat EARLY_LINE_LENGTHS[NUM_LINES] = */ static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = { - 8.091400e-4f, 1.019453e-3f, 1.407968e-3f, 1.618280e-3f + 1.6182800e-4f, 2.0389060e-4f, 2.8159360e-4f, 3.2365600e-4f }; /* The late lines are used to approximate the decaying cycle of recursive @@ -201,19 +207,19 @@ static const ALfloat LATE_ALLPASS_LENGTHS[NUM_LINES] = * L_i = 2 r_a - L_(i-N/2) * = 2 r_a - 2^((i - N / 2) / (N - 1)) r_d * - * For our 5m average room, we get: + * For our 1m average room, we get: */ static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = { - 9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f + 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f }; /* This coefficient is used to define the delay scale from the sinus, according * to the modulation depth property. This value must be below the shortest late - * line length (0.0097), otherwise with certain parameters (high mod time, low - * density) the downswing can sample before the input. + * line length, otherwise with certain parameters (high mod time, low density) + * the downswing can sample before the input. */ -static const ALfloat MODULATION_DEPTH_COEFF = 0.0032f; +static const ALfloat MODULATION_DEPTH_COEFF = 0.001f; typedef struct DelayLineI { @@ -464,6 +470,11 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State) * Device Update * **************************************/ +static inline ALfloat CalcDelayLengthMult(ALfloat density) +{ + return maxf(5.0f, cbrtf(density*DENSITY_SCALE)); +} + /* Given the allocated sample buffer, this function updates each delay line * offset. */ @@ -514,7 +525,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) /* Multiplier for the maximum density value, i.e. density=1, which is * actually the least density... */ - multiplier = 1.0f + AL_EAXREVERB_MAX_DENSITY*LINE_MULTIPLIER; + multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); /* The main delay length includes the maximum early reflection delay, the * largest early tap width, the maximum late reverb delay, and the @@ -588,7 +599,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev if(!AllocLines(frequency, State)) return AL_FALSE; - multiplier = 1.0f + AL_EAXREVERB_MAX_DENSITY*LINE_MULTIPLIER; + multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); /* The late feed taps are set a fixed position past the latest delay tap. */ State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + @@ -993,7 +1004,7 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, ALfloat multiplier, length; ALuint i; - multiplier = 1.0f + density*LINE_MULTIPLIER; + multiplier = CalcDelayLengthMult(density); /* Early reflection taps are decorrelated by means of an average room * reflection approximation described above the definition of the taps. @@ -1024,7 +1035,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c ALfloat multiplier, length; ALsizei i; - multiplier = 1.0f + density*LINE_MULTIPLIER; + multiplier = CalcDelayLengthMult(density); for(i = 0;i < NUM_LINES;i++) { @@ -1059,7 +1070,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co * The average length of the delay lines is used to calculate the * attenuation coefficient. */ - multiplier = 1.0f + density*LINE_MULTIPLIER; + multiplier = CalcDelayLengthMult(density); length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; /* Include the echo transformation (see below). */ -- cgit v1.2.3 From 20bee69955380d9ff65838c2cb005637c5c348ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Feb 2018 01:08:02 -0800 Subject: Attempt to improve the reverb panning vectors This should now retain the original orientation of the soundfield and merely focus on the panning vector direction, as intended. --- Alc/effects/reverb.c | 62 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9fba183a..392c2258 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1124,17 +1124,19 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co } } -/* Creates a transform matrix given a reverb vector. This works by creating a - * Z-focus transform, then a rotate transform around X, then Y, to place the - * focal point in the direction of the vector, using the vector length as a - * focus strength. - * - * This isn't technically correct since the vector is supposed to define the - * aperture and not rotate the perceived soundfield, but in practice it's - * probably good enough. +/* Creates a transform matrix given a reverb vector. This works by first + * creating an inverse rotation around Y then X, applying a Z-focus transform, + * then non-inverse rotations back around X then Y, to place the focal point in + * the direction of the vector, using the vector length as a focus strength. + * + * This convoluted construction ultimately results in a B-Format transformation + * matrix that retains its original orientation, but spatially focuses the + * signal in the desired direction. There is probably a more efficient way to + * do this, but let's see how good the optimizer is. */ static aluMatrixf GetTransformFromVector(const ALfloat *vec) { + const ALfloat sqrt_3 = 1.732050808f; aluMatrixf zfocus, xrot, yrot; aluMatrixf tmp1, tmp2; ALfloat length; @@ -1145,12 +1147,12 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) /* Define a Z-focus (X in Ambisonics) transform, given the panning vector * length. */ - sa = sinf(minf(length, 1.0f) * (F_PI/4.0f)); + sa = sinf(minf(length, 1.0f) * (F_PI/2.0f)); aluMatrixfSet(&zfocus, - 1.0f/(1.0f+sa), 0.0f, 0.0f, (sa/(1.0f+sa))/1.732050808f, - 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, - 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, - (sa/(1.0f+sa))*1.732050808f, 0.0f, 0.0f, 1.0f/(1.0f+sa) + 1.0f/(1.0f+sa), 0.0f, 0.0f, sa/(1.0f+sa)/sqrt_3, + 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, + 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, + sa/(1.0f+sa)*sqrt_3, 0.0f, 0.0f, 1.0f/(1.0f+sa) ); /* Define rotation around X (Y in Ambisonics) */ @@ -1176,19 +1178,39 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) 0.0f, -sinf(a), 0.0f, cosf(a) ); + /* First, define a matrix that applies the inverse of the Y- then X- + * rotation matrices, so that the desired direction lands on Z. + */ +#define MATRIX_INVMULT(_res, _m1, _m2) do { \ + int row, col; \ + for(col = 0;col < 4;col++) \ + { \ + for(row = 0;row < 4;row++) \ + _res.m[row][col] = _m1.m[0][row]*_m2.m[col][0] + \ + _m1.m[1][row]*_m2.m[col][1] + \ + _m1.m[2][row]*_m2.m[col][2] + \ + _m1.m[3][row]*_m2.m[col][3]; \ + } \ +} while(0) + MATRIX_INVMULT(tmp1, xrot, yrot); +#undef MATRIX_INVMULT + #define MATRIX_MULT(_res, _m1, _m2) do { \ int row, col; \ for(col = 0;col < 4;col++) \ { \ for(row = 0;row < 4;row++) \ - _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + _m1.m[row][1]*_m2.m[1][col] + \ - _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ + _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + \ + _m1.m[row][1]*_m2.m[1][col] + \ + _m1.m[row][2]*_m2.m[2][col] + \ + _m1.m[row][3]*_m2.m[3][col]; \ } \ } while(0) - /* Define a matrix that first focuses on Z, then rotates around X then Y to - * focus the output in the direction of the vector. + /* Now apply matrices to focus on Z, then rotate back around X then Y, to + * result in a focus in the direction of the vector. */ - MATRIX_MULT(tmp1, xrot, zfocus); + MATRIX_MULT(tmp2, zfocus, tmp1); + MATRIX_MULT(tmp1, xrot, tmp2); MATRIX_MULT(tmp2, yrot, tmp1); #undef MATRIX_MULT @@ -1214,8 +1236,8 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection _m1.m[row][2]*_m2.m[2][col] + _m1.m[row][3]*_m2.m[3][col]; \ } \ } while(0) - /* Create a matrix that first converts A-Format to B-Format, then rotates - * the B-Format soundfield according to the panning vector. + /* Create a matrix that first converts A-Format to B-Format, then + * transforms the B-Format signal according to the panning vector. */ rot = GetTransformFromVector(ReflectionsPan); MATRIX_MULT(transform, rot, A2B); -- cgit v1.2.3 From c346baff5b5e86e7e7982b5e644ecf756a040170 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Feb 2018 18:43:34 -0800 Subject: Clarify some macro names using ambisonic mixed-mode notation --- Alc/bformatdec.c | 24 ++++++++++++------------ Alc/bformatdec.h | 16 ++++++++-------- Alc/panning.c | 24 ++++++++++++------------ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 0e79fd3f..9673b422 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -269,13 +269,13 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { periphonic = true; - dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD : - (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; + dec->UpSampler[0].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : + (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; for(i = 1;i < 4;i++) { - dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD : - (dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f; + dec->UpSampler[i].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; } } @@ -283,13 +283,13 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { periphonic = false; - dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD : - (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f; + dec->UpSampler[0].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : + (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; for(i = 1;i < 3;i++) { - dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD : - (dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f; + dec->UpSampler[i].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; } dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f; @@ -559,10 +559,10 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) else { /* Assumes full 3D/periphonic on the input and output mixes! */ - ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE3D_THIRD : - (device->Dry.NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f; - ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE3D_THIRD : - (device->Dry.NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f; + ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE_3H3P : + (device->Dry.NumChannels > 4) ? W_SCALE_2H2P : 1.0f; + ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE_3H3P : + (device->Dry.NumChannels > 4) ? XYZ_SCALE_2H2P : 1.0f; for(i = 0;i < 4;i++) { ALsizei index = GetChannelForACN(device->Dry, i); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index b017cfd3..c897ac3a 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -7,18 +7,18 @@ /* These are the necessary scales for first-order HF responses to play over * higher-order 2D (non-periphonic) decoders. */ -#define W_SCALE2D_SECOND 1.224744871f /* sqrt(1.5) */ -#define XYZ_SCALE2D_SECOND 1.0f -#define W_SCALE2D_THIRD 1.414213562f /* sqrt(2) */ -#define XYZ_SCALE2D_THIRD 1.082392196f +#define W_SCALE_2H0P 1.224744871f /* sqrt(1.5) */ +#define XYZ_SCALE_2H0P 1.0f +#define W_SCALE_3H0P 1.414213562f /* sqrt(2) */ +#define XYZ_SCALE_3H0P 1.082392196f /* These are the necessary scales for first-order HF responses to play over * higher-order 3D (periphonic) decoders. */ -#define W_SCALE3D_SECOND 1.341640787f /* sqrt(1.8) */ -#define XYZ_SCALE3D_SECOND 1.0f -#define W_SCALE3D_THIRD 1.695486018f -#define XYZ_SCALE3D_THIRD 1.136697713f +#define W_SCALE_2H2P 1.341640787f /* sqrt(1.8) */ +#define XYZ_SCALE_2H2P 1.0f +#define W_SCALE_3H3P 1.695486018f +#define XYZ_SCALE_3H3P 1.136697713f struct AmbDecConf; diff --git a/Alc/panning.c b/Alc/panning.c index 1691aacd..eaeb2646 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -679,10 +679,10 @@ static void InitPanning(ALCdevice *device) chanmap, count, &device->Dry.NumChannels); device->Dry.CoeffCount = coeffcount; - w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE2D_THIRD : - (device->Dry.CoeffCount > 4) ? W_SCALE2D_SECOND : 1.0f; - xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE2D_THIRD : - (device->Dry.CoeffCount > 4) ? XYZ_SCALE2D_SECOND : 1.0f; + w_scale = (device->Dry.CoeffCount > 9) ? W_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? W_SCALE_2H0P : 1.0f; + xyz_scale = (device->Dry.CoeffCount > 9) ? XYZ_SCALE_3H0P : + (device->Dry.CoeffCount > 4) ? XYZ_SCALE_2H0P : 1.0f; memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi)); for(i = 0;i < device->Dry.NumChannels;i++) @@ -713,26 +713,26 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A { if(conf->ChanMask > 0x1ff) { - w_scale = W_SCALE3D_THIRD; - xyz_scale = XYZ_SCALE3D_THIRD; + w_scale = W_SCALE_3H3P; + xyz_scale = XYZ_SCALE_3H3P; } else if(conf->ChanMask > 0xf) { - w_scale = W_SCALE3D_SECOND; - xyz_scale = XYZ_SCALE3D_SECOND; + w_scale = W_SCALE_2H2P; + xyz_scale = XYZ_SCALE_2H2P; } } else { if(conf->ChanMask > 0x1ff) { - w_scale = W_SCALE2D_THIRD; - xyz_scale = XYZ_SCALE2D_THIRD; + w_scale = W_SCALE_3H0P; + xyz_scale = XYZ_SCALE_3H0P; } else if(conf->ChanMask > 0xf) { - w_scale = W_SCALE2D_SECOND; - xyz_scale = XYZ_SCALE2D_SECOND; + w_scale = W_SCALE_2H0P; + xyz_scale = XYZ_SCALE_2H0P; } } -- cgit v1.2.3 From ee3d53a67373cae7ec13c29a4e3842e732ec06cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Feb 2018 05:16:28 -0800 Subject: Use an alternate virtual layout for Ambisonic HRTF decoding This uses 16 channels, an 8-channel octagon + 8-channel cube, which should improve horizontal resolution without affecting vertical too much. --- Alc/hrtf.c | 17 +++++++--- Alc/hrtf.h | 2 +- Alc/panning.c | 105 +++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 76 insertions(+), 48 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index d1cfe6b0..cf211470 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -194,7 +194,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount) +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain) { /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -248,12 +248,13 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N { for(i = 0;i < NumChannels;++i) { + ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; ALsizei lidx = ldelay, ridx = rdelay; ALsizei j = 0; while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) { - state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][0][i]; - state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][0][i]; + state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][i] * hfgain; + state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][i] * hfgain; j++; } } @@ -269,12 +270,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Apply left ear response with delay. */ for(i = 0;i < NumChannels;++i) { + ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; for(b = 0;b < NUM_BANDS;b++) { ALsizei lidx = ldelay; ALsizei j = 0; while(lidx < HRIR_LENGTH) - state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][b][i]; + state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][i] * + hfgain; + hfgain = 1.0f; } } @@ -287,12 +291,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Apply right ear response with delay. */ for(i = 0;i < NumChannels;++i) { + ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; for(b = 0;b < NUM_BANDS;b++) { ALsizei ridx = rdelay; ALsizei j = 0; while(ridx < HRIR_LENGTH) - state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][b][i]; + state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][i] * + hfgain; + hfgain = 1.0f; } } } diff --git a/Alc/hrtf.h b/Alc/hrtf.h index aaee4a8d..b041c911 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -79,6 +79,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * virtual speaker positions and HF/LF matrices for decoding to them. The * returned coefficients are ordered and scaled according to the matrices. */ -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount); +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index eaeb2646..e368c946 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -870,59 +870,79 @@ static void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ static const ALfloat AmbiPoints[][2] = { - { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, + }; + static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { + { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f }, + { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f }, + { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f }, + { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f }, + { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, 8.66025404e-002f }, + { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f }, + { 6.25000000e-002f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f }, + { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, -8.66025404e-002f }, + { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f }, + { 6.25000000e-002f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f }, + { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f }, + { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f }, + { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f }, + { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f }, + }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { + { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f, 4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f, -4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f, 4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f, -4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.29099445e-001f }, + { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f, 6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -1.29099445e-001f }, + { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f, -6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.29099445e-001f }, + { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f, 6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -1.29099445e-001f }, + { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f, -6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, + { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f, 4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f, -4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f, 4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, + { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f, -4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, }; - static const ALfloat AmbiMatrixFOA[][2][MAX_AMBI_COEFFS] = { - { { 1.88982237e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f } }, - { { 1.88982237e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f } }, - { { 1.88982237e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } }, - { { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } }, - { { 1.88982237e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f } } - }, AmbiMatrixHOA[][2][MAX_AMBI_COEFFS] = { - { { 1.43315266e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, - { { 1.39644596e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, - { { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } }, - { { 1.39644596e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } }, - { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } }, - { { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } }, + static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { + 2.82842712e+00, 1.63299316e+00 + }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { + 2.15665546e+00, 1.67053814e+00, 8.62662186e-01 }; - const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = device->AmbiUp ? AmbiMatrixHOA : - AmbiMatrixFOA; - ALsizei count = device->AmbiUp ? 9 : 4; + const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; + const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; + ALsizei count = 4; ALsizei i; + static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch"); + static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch"); static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small"); + if(device->AmbiUp) + { + AmbiMatrix = AmbiMatrixHOA; + AmbiOrderHFGain = AmbiOrderHFGainHOA; + count = 9; + } + device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count)); for(i = 0;i < count;i++) @@ -956,7 +976,8 @@ static void InitHrtfPanning(ALCdevice *device) device->RealOut.NumChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); BuildBFormatHrtf(device->HrtfHandle, - device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints) + device->Hrtf, device->Dry.NumChannels, AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints), + AmbiOrderHFGain ); InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, true); -- cgit v1.2.3 From 5b11129eaa3fbf094bbbc85688bf6339b5abb753 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Feb 2018 15:50:05 -0800 Subject: Use a function pointer for applying the dry mix post-process --- Alc/ALc.c | 2 + Alc/ALu.c | 165 +++++++++++++++++++++++++++------------------- OpenAL32/Include/alMain.h | 7 +- OpenAL32/Include/alu.h | 2 + 4 files changed, 106 insertions(+), 70 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 915addac..461934cc 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2216,6 +2216,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } TRACE("Output limiter %s\n", device->Limiter ? "enabled" : "disabled"); + aluSelectPostProcess(device); + /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. */ diff --git a/Alc/ALu.c b/Alc/ALu.c index 2435558d..a3de456b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -208,6 +208,98 @@ void aluInit(void) MixDirectHrtf = SelectHrtfMixer(); } + +static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) +{ + DirectHrtfState *state; + int lidx, ridx; + ALsizei c; + + if(device->AmbiUp) + ambiup_process(device->AmbiUp, + device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, + SamplesToDo + ); + + lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + state = device->Hrtf; + for(c = 0;c < device->Dry.NumChannels;c++) + { + MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer[c], state->Offset, state->IrSize, + state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo + ); + } + state->Offset += SamplesToDo; +} + +static void ProcessAmbiDec(ALCdevice *device, ALsizei SamplesToDo) +{ + if(device->Dry.Buffer != device->FOAOut.Buffer) + bformatdec_upSample(device->AmbiDecoder, + device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, + SamplesToDo + ); + bformatdec_process(device->AmbiDecoder, + device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, + SamplesToDo + ); +} + +static void ProcessAmbiUp(ALCdevice *device, ALsizei SamplesToDo) +{ + ambiup_process(device->AmbiUp, + device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, + SamplesToDo + ); +} + +static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) +{ + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + if(LIKELY(lidx != -1 && ridx != -1)) + { + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, + device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, SamplesToDo + ); + } +} + +static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) +{ + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + if(LIKELY(lidx != -1 && ridx != -1)) + { + /* Apply binaural/crossfeed filter */ + bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], + device->RealOut.Buffer[ridx], SamplesToDo); + } +} + +void aluSelectPostProcess(ALCdevice *device) +{ + if(device->HrtfHandle) + device->PostProcess = ProcessHrtf; + else if(device->AmbiDecoder) + device->PostProcess = ProcessAmbiDec; + else if(device->AmbiUp) + device->PostProcess = ProcessAmbiUp; + else if(device->Uhj_Encoder) + device->PostProcess = ProcessUhj; + else if(device->Bs2b) + device->PostProcess = ProcessBs2b; + else + device->PostProcess = NULL; +} + + /* Prepares the interpolator for a given rate (determined by increment). A * result of AL_FALSE indicates that the filter output will completely cut * the input signal. @@ -1723,74 +1815,11 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) device->SamplesDone %= device->Frequency; IncrementRef(&device->MixCount); - if(device->HrtfHandle) - { - DirectHrtfState *state; - int lidx, ridx; - - if(device->AmbiUp) - ambiup_process(device->AmbiUp, - device->Dry.Buffer, device->Dry.NumChannels, device->FOAOut.Buffer, - SamplesToDo - ); - - lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - state = device->Hrtf; - for(c = 0;c < device->Dry.NumChannels;c++) - { - MixDirectHrtf(device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer[c], state->Offset, state->IrSize, - state->Chan[c].Coeffs, state->Chan[c].Values, SamplesToDo - ); - } - state->Offset += SamplesToDo; - } - else if(device->AmbiDecoder) - { - if(device->Dry.Buffer != device->FOAOut.Buffer) - bformatdec_upSample(device->AmbiDecoder, - device->Dry.Buffer, device->FOAOut.Buffer, device->FOAOut.NumChannels, - SamplesToDo - ); - bformatdec_process(device->AmbiDecoder, - device->RealOut.Buffer, device->RealOut.NumChannels, device->Dry.Buffer, - SamplesToDo - ); - } - else if(device->AmbiUp) - { - ambiup_process(device->AmbiUp, - device->RealOut.Buffer, device->RealOut.NumChannels, device->FOAOut.Buffer, - SamplesToDo - ); - } - else if(device->Uhj_Encoder) - { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - if(lidx != -1 && ridx != -1) - { - /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, - device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo - ); - } - } - else if(device->Bs2b) - { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - if(lidx != -1 && ridx != -1) - { - /* Apply binaural/crossfeed filter */ - bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], - device->RealOut.Buffer[ridx], SamplesToDo); - } - } + /* Apply post-process for finalizing the Dry mix to the RealOut + * (Ambisonic decode, UHJ encode, etc). + */ + if(LIKELY(device->PostProcess)) + device->PostProcess(device, SamplesToDo); if(OutBuffer) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index baf610b8..8c2615cf 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -462,8 +462,9 @@ typedef struct RealMixParams { ALsizei NumChannels; } RealMixParams; -struct ALCdevice_struct -{ +typedef void (*POSTPROCESS)(ALCdevice *device, ALsizei SamplesToDo); + +struct ALCdevice_struct { RefCount ref; ATOMIC(ALenum) Connected; @@ -507,6 +508,8 @@ struct ALCdevice_struct vector_FilterSubList FilterList; almtx_t FilterLock; + POSTPROCESS PostProcess; + /* HRTF state and info */ struct DirectHrtfState *Hrtf; al_string HrtfName; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 920b7b44..a151c761 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -429,6 +429,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf void aluInitEffectPanning(struct ALeffectslot *slot); +void aluSelectPostProcess(ALCdevice *device); + /** * CalcDirectionCoeffs * -- cgit v1.2.3 From 1e93122470445810a77ee549c5945ead44fd5676 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Feb 2018 19:50:42 -0800 Subject: Remove unused reverb modulation code Still unsure how to handle reverb modulation without some kind of reference output, so remove the related functions to not waste CPU time. It'll remain in the Git history should it ever need to be resurrected. --- Alc/effects/reverb.c | 109 +-------------------------------------------------- 1 file changed, 2 insertions(+), 107 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 392c2258..caa02328 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -214,13 +214,6 @@ static const ALfloat LATE_LINE_LENGTHS[NUM_LINES] = 1.9419362e-3f, 2.4466860e-3f, 3.3791220e-3f, 3.8838720e-3f }; -/* This coefficient is used to define the delay scale from the sinus, according - * to the modulation depth property. This value must be below the shortest late - * line length, otherwise with certain parameters (high mod time, low density) - * the downswing can sample before the input. - */ -static const ALfloat MODULATION_DEPTH_COEFF = 0.001f; - typedef struct DelayLineI { /* The delay lines use interleaved samples, with the lengths being powers @@ -268,18 +261,6 @@ typedef struct EarlyReflections { ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; } EarlyReflections; -typedef struct Modulator { - /* The vibrato time is tracked with an index over a modulus-wrapped range - * (in samples). - */ - ALsizei Index; - ALsizei Range; - ALfloat IdxScale; - - /* The LFO delay scale (in samples scaled by FRACTIONONE). */ - ALfloat Depth[2]; -} Modulator; - typedef struct LateReverb { /* Attenuation to compensate for the modal density and decay rate of the * late lines. @@ -336,8 +317,6 @@ typedef struct ALreverbState { EarlyReflections Early; - Modulator Mod; - LateReverb Late; /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ @@ -347,7 +326,6 @@ typedef struct ALreverbState { ALsizei Offset; /* Temporary storage used when processing. */ - alignas(16) ALsizei ModulationDelays[NUM_LINES][MAX_UPDATE_SAMPLES][2]; alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat ReverbSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat EarlySamples[NUM_LINES][MAX_UPDATE_SAMPLES]; @@ -412,12 +390,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Coeff[i] = 0.0f; } - state->Mod.Index = 0; - state->Mod.Range = 1; - state->Mod.IdxScale = 0.0f; - state->Mod.Depth[0] = 0.0f; - state->Mod.Depth[1] = 0.0f; - state->Late.DensityGain = 0.0f; state->Late.Delay.Mask = 0; @@ -554,12 +526,9 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) &State->Late.VecAp.Delay); /* The late delay lines are calculated from the larger of the maximum - * density line length or the maximum echo time, and includes the maximum - * modulation-related delay. The modulator's delay is calculated from the - * depth coefficient. + * density line length or the maximum echo time. */ - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[NUM_LINES-1]*multiplier) + - MODULATION_DEPTH_COEFF; + length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[NUM_LINES-1]*multiplier); totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay); @@ -965,39 +934,6 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime } } -/* 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(const ALfloat modTime, const ALfloat modDepth, - const ALuint frequency, Modulator *Mod) -{ - ALsizei range; - - /* Modulation is calculated in two parts. - * - * The modulation time effects the speed of the sinus. An index out of the - * current range (both in samples) is incremented each sample, so a longer - * time implies a larger range. When the timing changes, the index is - * rescaled to the new range to keep the sinus consistent. - */ - range = fastf2i(modTime*frequency + 0.5f); - Mod->Index = (ALsizei)(Mod->Index * (ALint64)range / Mod->Range)%range; - Mod->Range = range; - Mod->IdxScale = F_TAU / range; - - /* The modulation depth effects the scale of the sinus, which varies the - * delay for the tapped output. This delay changing over time changes the - * pitch, creating the modulation effect. The scale needs to be multiplied - * by the modulation time (itself scaled by the max modulation time) so - * that a given depth produces a consistent shift in frequency over all - * ranges of time. - */ - Mod->Depth[1] = modDepth * MODULATION_DEPTH_COEFF * - (modTime / AL_EAXREVERB_MAX_MODULATION_TIME) * - frequency * FRACTIONONE; -} - /* Update the offsets for the main effect delay line. */ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State) { @@ -1313,10 +1249,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte hfDecayTime = clampf(props->Reverb.DecayTime * hfRatio, AL_EAXREVERB_MIN_DECAY_TIME, AL_EAXREVERB_MAX_DECAY_TIME); - /* Update the modulator parameters. */ - UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, - frequency, &State->Mod); - /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, @@ -1345,8 +1277,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte break; } } - if(State->Mod.Depth[1] != State->Mod.Depth[0]) - State->FadeCount = 0; } @@ -1392,34 +1322,6 @@ static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const AL Delay->Line[offset][i] = in[NUM_LINES-1-i]; } -static void CalcModulationDelays(Modulator *Mod, ALsizei (*restrict delays)[MAX_UPDATE_SAMPLES][2], - const ALsizei (*restrict offsets)[2], const ALsizei todo) -{ - const ALsizei phase_offset = Mod->Range >> 2; - ALfloat sinus; - ALsizei c, i; - - for(c = 0;c < NUM_LINES;c++) - { - ALsizei offset0 = offsets[c][0] << FRACTIONBITS; - ALsizei offset1 = offsets[c][1] << FRACTIONBITS; - ALsizei index = Mod->Index + phase_offset*c; - for(i = 0;i < todo;i++) - { - /* Calculate the sinus rhythm (dependent on modulation time and the - * sampling rate). - */ - sinus = sinf(index * Mod->IdxScale); - index = (index+1) % Mod->Range; - - /* Calculate the read offset. */ - delays[c][i][0] = fastf2i(sinus*Mod->Depth[0]) + offset0; - delays[c][i][1] = fastf2i(sinus*Mod->Depth[1]) + offset1; - } - } - Mod->Index = (Mod->Index+todo) % Mod->Range; -} - /* Applies a scattering matrix to the 4-line (vector) input. This is used * for both the below vector all-pass model and to perform modal feed-back * delay network (FDN) mixing. @@ -1619,15 +1521,12 @@ static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { - ALsizei (*restrict moddelay)[MAX_UPDATE_SAMPLES][2] = State->ModulationDelays; const ALfloat apFeedCoeff = State->ApFeedCoeff; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset; ALsizei i, j; - CalcModulationDelays(&State->Mod, moddelay, State->Late.Offset, todo); - offset = State->Offset; for(i = 0;i < todo;i++) { @@ -1664,15 +1563,12 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { - ALsizei (*restrict moddelay)[MAX_UPDATE_SAMPLES][2] = State->ModulationDelays; const ALfloat apFeedCoeff = State->ApFeedCoeff; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset; ALsizei i, j; - CalcModulationDelays(&State->Mod, moddelay, State->Late.Offset, todo); - offset = State->Offset; for(i = 0;i < todo;i++) { @@ -1774,7 +1670,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } - State->Mod.Depth[0] = State->Mod.Depth[1]; } /* Mix the A-Format results to output, implicitly converting back to -- cgit v1.2.3 From b11e31fbfd6744a6d938ebb4a0e85c173386322a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Feb 2018 21:42:45 -0800 Subject: Clear stale 'post's on the event semphaphore --- OpenAL32/event.c | 5 +++++ common/threads.c | 16 ++++++++++++++++ common/threads.h | 1 + 3 files changed, 22 insertions(+) diff --git a/OpenAL32/event.c b/OpenAL32/event.c index f65efc7c..ef36f977 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -13,6 +13,11 @@ static int EventThread(void *arg) { ALCcontext *context = arg; + /* Clear all pending posts on the semaphore. */ + while(alsem_trywait(&context->EventSem) == althrd_success) + { + } + while(1) { AsyncEvent evt; diff --git a/common/threads.c b/common/threads.c index b95cb548..88052d7e 100644 --- a/common/threads.c +++ b/common/threads.c @@ -354,6 +354,14 @@ int alsem_wait(alsem_t *sem) return althrd_error; } +int alsem_trywait(alsem_t *sem) +{ + DWORD ret = WaitForSingleObject(*sem, 0); + if(ret == WAIT_OBJECT_0) return althrd_success; + if(ret == WAIT_TIMEOUT) return althrd_busy; + return althrd_error; +} + /* An associative map of uint:void* pairs. The key is the TLS index (given by * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, @@ -664,6 +672,14 @@ int alsem_wait(alsem_t *sem) return althrd_error; } +int alsem_trywait(alsem_t *sem) +{ + if(sem_trywait(sem) == 0) return althrd_success; + if(errno == EWOULDBLOCK) return althrd_busy; + if(errno == EINTR) return -2; + return althrd_error; +} + int altss_create(altss_t *tss_id, altss_dtor_t callback) { diff --git a/common/threads.h b/common/threads.h index ffd7fac5..9a6fe1f7 100644 --- a/common/threads.h +++ b/common/threads.h @@ -237,6 +237,7 @@ int alsem_init(alsem_t *sem, unsigned int initial); void alsem_destroy(alsem_t *sem); int alsem_post(alsem_t *sem); int alsem_wait(alsem_t *sem); +int alsem_trywait(alsem_t *sem); int altss_create(altss_t *tss_id, altss_dtor_t callback); void altss_delete(altss_t tss_id); -- cgit v1.2.3 From 494e9fd61d1a4ca98bb314a6615e720556519a95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Feb 2018 16:58:34 -0800 Subject: Don't asynchronously modify the source on disconnect --- Alc/ALu.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index a3de456b..0f6c447e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1926,18 +1926,10 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) for(i = 0;i < ctx->VoiceCount;i++) { ALvoice *voice = ctx->Voices[i]; - ALsource *source; - source = ATOMIC_EXCHANGE_PTR(&voice->Source, NULL, almemory_order_acq_rel); + ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - - if(source) - { - ALenum playing = AL_PLAYING; - (void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&source->state, &playing, AL_STOPPED)); - } } - ctx->VoiceCount = 0; ctx = ctx->next; } -- cgit v1.2.3 From e63e0ee596e207d225e2340c867f0c0c83496cc8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Feb 2018 21:59:59 -0800 Subject: Combine multiple functions called sequentially --- Alc/ALc.c | 6 +- Alc/ALu.c | 30 +++------- Alc/mixer.c | 4 +- Alc/nfcfilter.c | 160 ++++++++++++++++++++++++++----------------------- Alc/nfcfilter.h | 32 +++++++--- OpenAL32/Include/alu.h | 2 +- OpenAL32/alSource.c | 8 +-- 7 files changed, 123 insertions(+), 119 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 461934cc..db100d7c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2331,11 +2331,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / (device->AvgSpeakerDist * device->Frequency); for(i = 0;i < voice->NumChannels;i++) - { - NfcFilterCreate1(&voice->Direct.Params[i].NFCtrlFilter[0], 0.0f, w1); - NfcFilterCreate2(&voice->Direct.Params[i].NFCtrlFilter[1], 0.0f, w1); - NfcFilterCreate3(&voice->Direct.Params[i].NFCtrlFilter[2], 0.0f, w1); - } + NfcFilterCreate(&voice->Direct.Params[i].NFCtrlFilter, 0.0f, w1); } } almtx_unlock(&context->SourceLock); diff --git a/Alc/ALu.c b/Alc/ALu.c index 0f6c447e..f73b1985 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -601,9 +601,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const w0 = minf(w0, w1*4.0f); /* Only need to adjust the first channel of a B-Format source. */ - NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], w0); - NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], w0); - NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], w0); + NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; @@ -660,9 +658,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const * is what we want for FOA input. The first channel may have * been previously re-adjusted if panned, so reset it. */ - NfcFilterAdjust1(&voice->Direct.Params[0].NFCtrlFilter[0], 0.0f); - NfcFilterAdjust2(&voice->Direct.Params[0].NFCtrlFilter[1], 0.0f); - NfcFilterAdjust3(&voice->Direct.Params[0].NFCtrlFilter[2], 0.0f); + NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, 0.0f); voice->Direct.ChannelsPerOrder[0] = 1; voice->Direct.ChannelsPerOrder[1] = mini(voice->Direct.Channels-1, 3); @@ -896,6 +892,10 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const */ w0 = minf(w0, w1*4.0f); + /* Adjust NFC filters. */ + for(c = 0;c < num_channels;c++) + NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + for(i = 0;i < MAX_AMBI_ORDER+1;i++) voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; voice->Flags |= VOICE_HAS_NFC; @@ -915,14 +915,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 0;c < num_channels;c++) { - /* Adjust NFC filters if needed. */ - if((voice->Flags&VOICE_HAS_NFC)) - { - NfcFilterAdjust1(&voice->Direct.Params[c].NFCtrlFilter[0], w0); - NfcFilterAdjust2(&voice->Direct.Params[c].NFCtrlFilter[1], w0); - NfcFilterAdjust3(&voice->Direct.Params[c].NFCtrlFilter[2], w0); - } - /* Special-case LFE */ if(chans[c].channel == LFE) { @@ -979,6 +971,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const w0 = SPEEDOFSOUNDMETRESPERSEC / (Device->AvgSpeakerDist * (ALfloat)Device->Frequency); + for(c = 0;c < num_channels;c++) + NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); + for(i = 0;i < MAX_AMBI_ORDER+1;i++) voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; voice->Flags |= VOICE_HAS_NFC; @@ -988,13 +983,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const { ALfloat coeffs[MAX_AMBI_COEFFS]; - if((voice->Flags&VOICE_HAS_NFC)) - { - NfcFilterAdjust1(&voice->Direct.Params[c].NFCtrlFilter[0], w0); - NfcFilterAdjust2(&voice->Direct.Params[c].NFCtrlFilter[1], w0); - NfcFilterAdjust3(&voice->Direct.Params[c].NFCtrlFilter[2], w0); - } - /* Special-case LFE */ if(chans[c].channel == LFE) { diff --git a/Alc/mixer.c b/Alc/mixer.c index 11b721f1..eb4568b2 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -564,8 +564,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize #define APPLY_NFC_MIX(order) \ if(voice->Direct.ChannelsPerOrder[order] > 0) \ { \ - NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \ - samples, DstBufferSize); \ + NfcFilterUpdate##order(&parms->NFCtrlFilter, nfcsamples, samples, \ + DstBufferSize); \ MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ diff --git a/Alc/nfcfilter.c b/Alc/nfcfilter.c index 758863c9..57a3e28f 100644 --- a/Alc/nfcfilter.c +++ b/Alc/nfcfilter.c @@ -52,13 +52,11 @@ static const float B[4][3] = { /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ }; -void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1) +static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) { float b_00, g_0; float r; - memset(nfc, 0, sizeof(*nfc)); - nfc->g = 1.0f; nfc->coeffs[0] = 1.0f; @@ -80,7 +78,7 @@ void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[1+1] = (2.0f * b_00) / g_0; } -void NfcFilterAdjust1(NfcFilter *nfc, const float w0) +static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) { float b_00, g_0; float r; @@ -93,36 +91,12 @@ void NfcFilterAdjust1(NfcFilter *nfc, const float w0) nfc->coeffs[1] = (2.0f * b_00) / g_0; } -void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) -{ - const float b0 = nfc->coeffs[0]; - const float a0 = nfc->coeffs[1]; - const float a1 = nfc->coeffs[2]; - float z1 = nfc->history[0]; - int i; - - for(i = 0;i < count;i++) - { - float out = src[i] * b0; - float y; - - y = out - (a1*z1); - out = y + (a0*z1); - z1 += y; - - dst[i] = out; - } - nfc->history[0] = z1; -} - -void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1) +static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) { float b_10, b_11, g_1; float r; - memset(nfc, 0, sizeof(*nfc)); - nfc->g = 1.0f; nfc->coeffs[0] = 1.0f; @@ -148,7 +122,7 @@ void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[2+2] = (4.0f * b_11) / g_1; } -void NfcFilterAdjust2(NfcFilter *nfc, const float w0) +static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) { float b_10, b_11, g_1; float r; @@ -163,42 +137,13 @@ void NfcFilterAdjust2(NfcFilter *nfc, const float w0) nfc->coeffs[2] = (4.0f * b_11) / g_1; } -void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) -{ - const float b0 = nfc->coeffs[0]; - const float a00 = nfc->coeffs[1]; - const float a01 = nfc->coeffs[2]; - const float a10 = nfc->coeffs[3]; - const float a11 = nfc->coeffs[4]; - float z1 = nfc->history[0]; - float z2 = nfc->history[1]; - int i; - for(i = 0;i < count;i++) - { - float out = src[i] * b0; - float y; - - y = out - (a10*z1) - (a11*z2); - out = y + (a00*z1) + (a01*z2); - z2 += z1; - z1 += y; - - dst[i] = out; - } - nfc->history[0] = z1; - nfc->history[1] = z2; -} - - -void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1) +static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) { float b_10, b_11, g_1; float b_00, g_0; float r; - memset(nfc, 0, sizeof(*nfc)); - nfc->g = 1.0f; nfc->coeffs[0] = 1.0f; @@ -237,7 +182,7 @@ void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1) nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0; } -void NfcFilterAdjust3(NfcFilter *nfc, const float w0) +static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) { float b_10, b_11, g_1; float b_00, g_0; @@ -259,18 +204,84 @@ void NfcFilterAdjust3(NfcFilter *nfc, const float w0) nfc->coeffs[2+1] = (2.0f * b_00) / g_0; } + +void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) +{ + memset(nfc, 0, sizeof(*nfc)); + NfcFilterCreate1(&nfc->first, w0, w1); + NfcFilterCreate2(&nfc->second, w0, w1); + NfcFilterCreate3(&nfc->third, w0, w1); +} + +void NfcFilterAdjust(NfcFilter *nfc, const float w0) +{ + NfcFilterAdjust1(&nfc->first, w0); + NfcFilterAdjust2(&nfc->second, w0); + NfcFilterAdjust3(&nfc->third, w0); +} + + +void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->first.coeffs[0]; + const float a0 = nfc->first.coeffs[1]; + const float a1 = nfc->first.coeffs[2]; + float z1 = nfc->first.history[0]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a1*z1); + out = y + (a0*z1); + z1 += y; + + dst[i] = out; + } + nfc->first.history[0] = z1; +} + +void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->second.coeffs[0]; + const float a00 = nfc->second.coeffs[1]; + const float a01 = nfc->second.coeffs[2]; + const float a10 = nfc->second.coeffs[3]; + const float a11 = nfc->second.coeffs[4]; + float z1 = nfc->second.history[0]; + float z2 = nfc->second.history[1]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a10*z1) - (a11*z2); + out = y + (a00*z1) + (a01*z2); + z2 += z1; + z1 += y; + + dst[i] = out; + } + nfc->second.history[0] = z1; + nfc->second.history[1] = z2; +} + void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) { - const float b0 = nfc->coeffs[0]; - const float a00 = nfc->coeffs[1]; - const float a01 = nfc->coeffs[2]; - const float a02 = nfc->coeffs[3]; - const float a10 = nfc->coeffs[4]; - const float a11 = nfc->coeffs[5]; - const float a12 = nfc->coeffs[6]; - float z1 = nfc->history[0]; - float z2 = nfc->history[1]; - float z3 = nfc->history[2]; + const float b0 = nfc->third.coeffs[0]; + const float a00 = nfc->third.coeffs[1]; + const float a01 = nfc->third.coeffs[2]; + const float a02 = nfc->third.coeffs[3]; + const float a10 = nfc->third.coeffs[4]; + const float a11 = nfc->third.coeffs[5]; + const float a12 = nfc->third.coeffs[6]; + float z1 = nfc->third.history[0]; + float z2 = nfc->third.history[1]; + float z3 = nfc->third.history[2]; int i; for(i = 0;i < count;i++) @@ -289,12 +300,11 @@ void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restri dst[i] = out; } - nfc->history[0] = z1; - nfc->history[1] = z2; - nfc->history[2] = z3; + nfc->third.history[0] = z1; + nfc->third.history[1] = z2; + nfc->third.history[2] = z3; } - #if 0 /* Original methods the above are derived from. */ static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) { diff --git a/Alc/nfcfilter.h b/Alc/nfcfilter.h index 199849fb..0bf9a5c4 100644 --- a/Alc/nfcfilter.h +++ b/Alc/nfcfilter.h @@ -3,12 +3,29 @@ #include "alMain.h" -typedef struct NfcFilter { +struct NfcFilter1 { + float g; + float coeffs[1*2 + 1]; + float history[1]; +}; +struct NfcFilter2 { float g; - float coeffs[MAX_AMBI_ORDER*2 + 1]; - float history[MAX_AMBI_ORDER]; + float coeffs[2*2 + 1]; + float history[2]; +}; +struct NfcFilter3 { + float g; + float coeffs[3*2 + 1]; + float history[3]; +}; + +typedef struct NfcFilter { + struct NfcFilter1 first; + struct NfcFilter2 second; + struct NfcFilter3 third; } NfcFilter; + /* NOTE: * w0 = speed_of_sound / (source_distance * sample_rate); * w1 = speed_of_sound / (control_distance * sample_rate); @@ -19,19 +36,16 @@ typedef struct NfcFilter { * small relative to the control distance. */ +void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); +void NfcFilterAdjust(NfcFilter *nfc, const float w0); + /* Near-field control filter for first-order ambisonic channels (1-3). */ -void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1); -void NfcFilterAdjust1(NfcFilter *nfc, const float w0); void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); /* Near-field control filter for second-order ambisonic channels (4-8). */ -void NfcFilterCreate2(NfcFilter *nfc, const float w0, const float w1); -void NfcFilterAdjust2(NfcFilter *nfc, const float w0); void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); /* Near-field control filter for third-order ambisonic channels (9-15). */ -void NfcFilterCreate3(NfcFilter *nfc, const float w0, const float w1); -void NfcFilterAdjust3(NfcFilter *nfc, const float w0); void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); #endif /* NFCFILTER_H */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index a151c761..609118bf 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -157,7 +157,7 @@ typedef struct DirectParams { ALfilterState LowPass; ALfilterState HighPass; - NfcFilter NFCtrlFilter[MAX_AMBI_ORDER]; + NfcFilter NFCtrlFilter; struct { HrtfParams Old; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 95651f29..2323da3e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2534,13 +2534,9 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) if(device->AvgSpeakerDist > 0.0f) { ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / - (device->AvgSpeakerDist * device->Frequency); + (device->AvgSpeakerDist * device->Frequency); for(j = 0;j < voice->NumChannels;j++) - { - NfcFilterCreate1(&voice->Direct.Params[j].NFCtrlFilter[0], 0.0f, w1); - NfcFilterCreate2(&voice->Direct.Params[j].NFCtrlFilter[1], 0.0f, w1); - NfcFilterCreate3(&voice->Direct.Params[j].NFCtrlFilter[2], 0.0f, w1); - } + NfcFilterCreate(&voice->Direct.Params[j].NFCtrlFilter, 0.0f, w1); } ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); -- cgit v1.2.3 From dce497fbca5d3b3b843e4475a94febd9105de87c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Feb 2018 20:33:31 -0800 Subject: Use a bitfield for enabled bformatdec channels --- Alc/bformatdec.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 9673b422..4dbca6a3 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -187,7 +187,7 @@ static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { /* NOTE: BandSplitter filters are unused with single-band decoding */ typedef struct BFormatDec { - ALboolean Enabled[MAX_OUTPUT_CHANNELS]; + ALuint Enabled; /* Bitfield of enabled channels. */ union { alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS]; @@ -251,10 +251,9 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount dec->SamplesHF = dec->Samples; dec->SamplesLF = dec->SamplesHF + dec->NumChannels; - for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) - dec->Enabled[i] = AL_FALSE; + dec->Enabled = 0; for(i = 0;i < conf->NumSpeakers;i++) - dec->Enabled[chanmap[i]] = AL_TRUE; + dec->Enabled |= 1 << chanmap[i]; if(conf->CoeffScale == ADS_SN3D) coeff_scale = SN3D2N3DScale; @@ -416,7 +415,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU for(chan = 0;chan < OutChannels;chan++) { - if(!dec->Enabled[chan]) + if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); @@ -435,7 +434,7 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU { for(chan = 0;chan < OutChannels;chan++) { - if(!dec->Enabled[chan]) + if(!(dec->Enabled&(1<ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); -- cgit v1.2.3 From 4d417f3dd4c6fee0e5050768a231c65a700ee417 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Feb 2018 20:48:28 -0800 Subject: Make bformatdec_free and ambiup_free clear the freed pointer --- Alc/ALc.c | 7 ++----- Alc/bformatdec.c | 22 +++++++++++++--------- Alc/bformatdec.h | 4 ++-- Alc/panning.c | 24 ++++++++---------------- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index db100d7c..8c743838 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2469,11 +2469,8 @@ static ALCvoid FreeDevice(ALCdevice *device) al_free(device->Uhj_Encoder); device->Uhj_Encoder = NULL; - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; + bformatdec_free(&device->AmbiDecoder); + ambiup_free(&device->AmbiUp); al_free(device->Stablizer); device->Stablizer = NULL; diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 4dbca6a3..5a3726e1 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -217,17 +217,17 @@ BFormatDec *bformatdec_alloc() return al_calloc(16, sizeof(BFormatDec)); } -void bformatdec_free(BFormatDec *dec) +void bformatdec_free(BFormatDec **dec) { if(dec) { - al_free(dec->Samples); - dec->Samples = NULL; - dec->SamplesHF = NULL; - dec->SamplesLF = NULL; + al_free((*dec)->Samples); + (*dec)->Samples = NULL; + (*dec)->SamplesHF = NULL; + (*dec)->SamplesLF = NULL; - memset(dec, 0, sizeof(*dec)); - al_free(dec); + al_free(*dec); + *dec = NULL; } } @@ -507,9 +507,13 @@ AmbiUpsampler *ambiup_alloc() return al_calloc(16, sizeof(AmbiUpsampler)); } -void ambiup_free(struct AmbiUpsampler *ambiup) +void ambiup_free(struct AmbiUpsampler **ambiup) { - al_free(ambiup); + if(ambiup) + { + al_free(*ambiup); + *ambiup = NULL; + } } void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index c897ac3a..c997c0b9 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -27,7 +27,7 @@ struct AmbiUpsampler; struct BFormatDec *bformatdec_alloc(); -void bformatdec_free(struct BFormatDec *dec); +void bformatdec_free(struct BFormatDec **dec); void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]); /* Decodes the ambisonic input to the given output channels. */ @@ -41,7 +41,7 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B * with bformatdec. */ struct AmbiUpsampler *ambiup_alloc(); -void ambiup_free(struct AmbiUpsampler *ambiup); +void ambiup_free(struct AmbiUpsampler **ambiup); void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); diff --git a/Alc/panning.c b/Alc/panning.c index e368c946..b90652a3 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -1086,25 +1086,20 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) { - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; + ambiup_free(&device->AmbiUp); if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); } else { - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; - if(device->FmtChans == DevFmtAmbi3D && device->AmbiOrder > 1) + bformatdec_free(&device->AmbiDecoder); + if(device->FmtChans != DevFmtAmbi3D || device->AmbiOrder < 2) + ambiup_free(&device->AmbiUp); + else { if(!device->AmbiUp) device->AmbiUp = ambiup_alloc(); } - else - { - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; - } } if(!pconf) @@ -1155,8 +1150,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf return; } - bformatdec_free(device->AmbiDecoder); - device->AmbiDecoder = NULL; + bformatdec_free(&device->AmbiDecoder); headphones = device->IsHeadphones; if(device->Type != Loopback) @@ -1248,8 +1242,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf /* Don't bother with HOA when using full HRTF rendering. Nothing * needs it, and it eases the CPU/memory load. */ - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; + ambiup_free(&device->AmbiUp); } else { @@ -1274,8 +1267,7 @@ no_hrtf: device->Render_Mode = StereoPair; - ambiup_free(device->AmbiUp); - device->AmbiUp = NULL; + ambiup_free(&device->AmbiUp); bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; -- cgit v1.2.3 From 59934b47de5d58fe20d920bee6879f5c78994c49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Feb 2018 20:58:39 -0800 Subject: Avoid using an enum for array indices --- Alc/bformatdec.c | 86 +++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 5a3726e1..4f8e725a 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -156,11 +156,9 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { }; -enum FreqBand { - FB_HighFreq, - FB_LowFreq, - FB_Max -}; +#define HF_BAND 0 +#define LF_BAND 1 +#define NUM_BANDS 2 /* These points are in AL coordinates! */ static const ALfloat Ambi3DPoints[8][3] = { @@ -173,7 +171,7 @@ static const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, -0.577350269f, 0.577350269f }, { 0.577350269f, -0.577350269f, 0.577350269f }, }; -static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = { +static const ALfloat Ambi3DDecoder[8][NUM_BANDS][MAX_AMBI_COEFFS] = { { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, @@ -190,7 +188,7 @@ typedef struct BFormatDec { ALuint Enabled; /* Bitfield of enabled channels. */ union { - alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS]; + alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS]; alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS]; } Matrix; @@ -205,7 +203,7 @@ typedef struct BFormatDec { struct { BandSplitter XOver; - ALfloat Gains[FB_Max]; + ALfloat Gains[NUM_BANDS]; } UpSampler[4]; ALsizei NumChannels; @@ -268,31 +266,31 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount { periphonic = true; - dec->UpSampler[0].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : - (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; - dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; + dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P : + (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f; + dec->UpSampler[0].Gains[LF_BAND] = 1.0f; for(i = 1;i < 4;i++) { - dec->UpSampler[i].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; - dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; + dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f; + dec->UpSampler[i].Gains[LF_BAND] = 1.0f; } } else { periphonic = false; - dec->UpSampler[0].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : - (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; - dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f; + dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P : + (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f; + dec->UpSampler[0].Gains[LF_BAND] = 1.0f; for(i = 1;i < 3;i++) { - dec->UpSampler[i].Gains[FB_HighFreq] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : - (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; - dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f; + dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P : + (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f; + dec->UpSampler[i].Gains[LF_BAND] = 1.0f; } - dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f; - dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f; + dec->UpSampler[3].Gains[HF_BAND] = 0.0f; + dec->UpSampler[3].Gains[LF_BAND] = 0.0f; } memset(&dec->Matrix, 0, sizeof(dec->Matrix)); @@ -359,8 +357,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 3) gain = conf->HFOrderGain[2] * ratio; else if(j == 5) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / - coeff_scale[l] * gain; + dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / + coeff_scale[l] * gain; } for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++) { @@ -370,8 +368,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 3) gain = conf->LFOrderGain[2] / ratio; else if(j == 5) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / - coeff_scale[l] * gain; + dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / + coeff_scale[l] * gain; } } else @@ -383,8 +381,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 4) gain = conf->HFOrderGain[2] * ratio; else if(j == 9) gain = conf->HFOrderGain[3] * ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] / - coeff_scale[j] * gain; + dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / + coeff_scale[j] * gain; } for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++) { @@ -393,8 +391,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount else if(j == 4) gain = conf->LFOrderGain[2] / ratio; else if(j == 9) gain = conf->LFOrderGain[3] / ratio; if((conf->ChanMask&(1<Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] / - coeff_scale[j] * gain; + dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / + coeff_scale[j] * gain; } } } @@ -419,10 +417,10 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU continue; memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat)); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq], + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND], dec->SamplesHF, dec->NumChannels, 0, SamplesToDo ); - MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq], + MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], dec->SamplesLF, dec->NumChannels, 0, SamplesToDo ); @@ -468,13 +466,13 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B * bands. */ bandsplit_process(&dec->UpSampler[i].XOver, - dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq], + dec->Samples[HF_BAND], dec->Samples[LF_BAND], InSamples[i], SamplesToDo ); /* Now write each band to the output. */ MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains, - dec->Samples, FB_Max, 0, SamplesToDo + dec->Samples, NUM_BANDS, 0, SamplesToDo ); } } @@ -495,11 +493,11 @@ static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsiz #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a)) typedef struct AmbiUpsampler { - alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE]; + alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE]; BandSplitter XOver[4]; - ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max]; + ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS]; } AmbiUpsampler; AmbiUpsampler *ambiup_alloc() @@ -551,11 +549,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) ALfloat hfgain=0.0f, lfgain=0.0f; for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) { - hfgain += Ambi3DDecoder[k][FB_HighFreq][i]*encgains[k][j]; - lfgain += Ambi3DDecoder[k][FB_LowFreq][i]*encgains[k][j]; + hfgain += Ambi3DDecoder[k][HF_BAND][i]*encgains[k][j]; + lfgain += Ambi3DDecoder[k][LF_BAND][i]*encgains[k][j]; } - ambiup->Gains[i][j][FB_HighFreq] = hfgain; - ambiup->Gains[i][j][FB_LowFreq] = lfgain; + ambiup->Gains[i][j][HF_BAND] = hfgain; + ambiup->Gains[i][j][LF_BAND] = lfgain; } } } @@ -572,8 +570,8 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) if(index != INVALID_UPSAMPLE_INDEX) { ALfloat scale = device->Dry.Ambi.Map[index].Scale; - ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale); - ambiup->Gains[i][index][FB_LowFreq] = scale; + ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale); + ambiup->Gains[i][index][LF_BAND] = scale; } } } @@ -586,13 +584,13 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[ for(i = 0;i < 4;i++) { bandsplit_process(&ambiup->XOver[i], - ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq], + ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], InSamples[i], SamplesToDo ); for(j = 0;j < OutChannels;j++) MixRowSamples(OutBuffer[j], ambiup->Gains[i][j], - ambiup->Samples, FB_Max, 0, SamplesToDo + ambiup->Samples, NUM_BANDS, 0, SamplesToDo ); } } -- cgit v1.2.3 From 6b76eddbe395dd7622ede8393f3561b7a7c2fa50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Feb 2018 21:24:58 -0800 Subject: Supply HF coefficient scales with a single-band ambisonic matrix --- Alc/bformatdec.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 4f8e725a..6141aaba 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -171,15 +171,19 @@ static const ALfloat Ambi3DPoints[8][3] = { { -0.577350269f, -0.577350269f, 0.577350269f }, { 0.577350269f, -0.577350269f, 0.577350269f }, }; -static const ALfloat Ambi3DDecoder[8][NUM_BANDS][MAX_AMBI_COEFFS] = { - { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } }, - { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } }, - { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } }, - { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } }, - { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } }, - { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } }, - { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } }, - { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } }, +static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = { + { 0.125f, 0.125f, 0.125f, 0.125f }, + { 0.125f, -0.125f, 0.125f, 0.125f }, + { 0.125f, 0.125f, 0.125f, -0.125f }, + { 0.125f, -0.125f, 0.125f, -0.125f }, + { 0.125f, 0.125f, -0.125f, 0.125f }, + { 0.125f, -0.125f, -0.125f, 0.125f }, + { 0.125f, 0.125f, -0.125f, -0.125f }, + { 0.125f, -0.125f, -0.125f, -0.125f }, +}; +static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = { + 2.0f, + 1.15470054f, 1.15470054f, 1.15470054f }; @@ -546,14 +550,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) { for(j = 0;j < device->Dry.NumChannels;j++) { - ALfloat hfgain=0.0f, lfgain=0.0f; + ALfloat gain=0.0f; for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - { - hfgain += Ambi3DDecoder[k][HF_BAND][i]*encgains[k][j]; - lfgain += Ambi3DDecoder[k][LF_BAND][i]*encgains[k][j]; - } - ambiup->Gains[i][j][HF_BAND] = hfgain; - ambiup->Gains[i][j][LF_BAND] = lfgain; + gain += Ambi3DDecoder[k][i] * encgains[k][j]; + ambiup->Gains[i][j][HF_BAND] = gain * Ambi3DDecoderHFScale[i]; + ambiup->Gains[i][j][LF_BAND] = gain; } } } -- cgit v1.2.3 From 2cb49e51a0d270f2a650d0969a5370ac50125c3f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 12 Feb 2018 22:20:43 -0800 Subject: Fix NULL pointer dereference --- Alc/bformatdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 6141aaba..bfd40b14 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -221,7 +221,7 @@ BFormatDec *bformatdec_alloc() void bformatdec_free(BFormatDec **dec) { - if(dec) + if(dec && *dec) { al_free((*dec)->Samples); (*dec)->Samples = NULL; -- cgit v1.2.3 From 59768674f1764706a2e59c4c314f80eca3b5de9d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Feb 2018 03:03:26 -0800 Subject: Use an alternate ambisonic HRTF decode layout Similar to the previous, but includes the top and bottom HRTF responses. The higher-order decode (for the "basic" HRTF output) also now uses 2H1P mixed- order instead of 2H1V, which seems more stable. --- Alc/bformatdec.c | 7 +--- Alc/bformatdec.h | 4 +- Alc/hrtf.h | 2 +- Alc/panning.c | 115 ++++++++++++++++++++++++++++++++----------------------- 4 files changed, 71 insertions(+), 57 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index bfd40b14..03ea865c 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -518,7 +518,7 @@ void ambiup_free(struct AmbiUpsampler **ambiup) } } -void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) +void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale) { ALfloat ratio; ALsizei i; @@ -560,11 +560,6 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device) } else { - /* Assumes full 3D/periphonic on the input and output mixes! */ - ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE_3H3P : - (device->Dry.NumChannels > 4) ? W_SCALE_2H2P : 1.0f; - ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE_3H3P : - (device->Dry.NumChannels > 4) ? XYZ_SCALE_2H2P : 1.0f; for(i = 0;i < 4;i++) { ALsizei index = GetChannelForACN(device->Dry, i); diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index c997c0b9..0011eb28 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -38,11 +38,11 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B /* Stand-alone first-order upsampler. Kept here because it shares some stuff - * with bformatdec. + * with bformatdec. Assumes a periphonic (4-channel) input mix! */ struct AmbiUpsampler *ambiup_alloc(); void ambiup_free(struct AmbiUpsampler **ambiup); -void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device); +void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale); void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index b041c911..60842e8d 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -12,7 +12,7 @@ /* The maximum number of virtual speakers used to generate HRTF coefficients * for decoding B-Format. */ -#define HRTF_AMBI_MAX_CHANNELS 16 +#define HRTF_AMBI_MAX_CHANNELS 18 #define HRTF_HISTORY_BITS (6) diff --git a/Alc/panning.c b/Alc/panning.c index b90652a3..6baff75f 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -649,6 +649,8 @@ static void InitPanning(ALCdevice *device) } else { + ALfloat w_scale=1.0f, xyz_scale=1.0f; + /* FOA output is always ACN+N3D for higher-order ambisonic output. * The upsampler expects this and will convert it for output. */ @@ -661,7 +663,17 @@ static void InitPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - ambiup_reset(device->AmbiUp, device); + if(device->AmbiOrder >= 3) + { + w_scale = W_SCALE_3H3P; + xyz_scale = XYZ_SCALE_3H3P; + } + else + { + w_scale = W_SCALE_2H2P; + xyz_scale = XYZ_SCALE_2H2P; + } + ambiup_reset(device->AmbiUp, device, w_scale, xyz_scale); } if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) @@ -870,62 +882,68 @@ static void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ static const ALfloat AmbiPoints[][2] = { - { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, - { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, - { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( 180.0f) }, + { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, + { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, + { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, + { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { - { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f }, - { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f }, - { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f }, - { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f }, - { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, 8.66025404e-002f }, - { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f }, - { 6.25000000e-002f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f }, - { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, -8.66025404e-002f }, - { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f }, - { 6.25000000e-002f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f }, - { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f }, - { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f }, - { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f }, - { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f }, + { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, + { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f }, + { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, + { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f }, }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { - { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f, 4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, 5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f, -4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, -5.00000000e-002f, 4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, -5.00000000e-002f, 1.25000000e-001f, 5.00000000e-002f, -4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.29099445e-001f }, - { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f, 6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, 8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -1.29099445e-001f }, - { 6.25000000e-002f, 6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f, -6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, 0.00000000e+000f, 0.00000000e+000f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.29099445e-001f }, - { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, -6.12372435e-002f, 6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, -8.66025404e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -1.29099445e-001f }, - { 6.25000000e-002f, -6.12372435e-002f, 0.00000000e+000f, 6.12372435e-002f, -6.83467648e-002f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f }, - { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f, 4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, 5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f, -4.55645099e-002f, -9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, -5.00000000e-002f, 4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, 9.68245837e-002f, 0.00000000e+000f }, - { 6.25000000e-002f, -5.00000000e-002f, -1.25000000e-001f, 5.00000000e-002f, -4.55645099e-002f, 9.68245837e-002f, 0.00000000e+000f, -9.68245837e-002f, 0.00000000e+000f }, + { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, }; static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { - 2.82842712e+00, 1.63299316e+00 + 3.00000000e+00f, 1.73205081e+00f }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { - 2.15665546e+00, 1.67053814e+00, 8.62662186e-01 + 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f }; const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; @@ -964,7 +982,8 @@ static void InitHrtfPanning(ALCdevice *device) device->FOAOut.CoeffCount = 0; device->FOAOut.NumChannels = 4; - ambiup_reset(device->AmbiUp, device); + ambiup_reset(device->AmbiUp, device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0], + AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]); } else { -- cgit v1.2.3 From 063ad490a24dfc28ad6ffe4b3b4c52273d596c8d Mon Sep 17 00:00:00 2001 From: Alexey Elymanov Date: Sun, 18 Feb 2018 20:55:31 +0300 Subject: freebsd fix: typo Alc/helpers.c:738:30: error: use of undeclared identifier 'KERN_PROCARGS' int mib[4] = { CTL_KERN, KERN_PROCARGS, getpid() }; /usr/include/sys/sysctl.h: `#define KERN_PROC_ARGS 7 /* get/set arguments/proctitle */` there's no KERN_PROCARGS --- Alc/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 96f9b681..45e137fd 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -735,7 +735,7 @@ void GetProcBinary(al_string *path, al_string *fname) size_t pathlen; #ifdef __FreeBSD__ - int mib[4] = { CTL_KERN, KERN_PROCARGS, getpid() }; + int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid() }; if(sysctl(mib, 3, NULL, &pathlen, NULL, 0) == -1) WARN("Failed to sysctl kern.procargs.%d: %s\n", mib[2], strerror(errno)); else -- cgit v1.2.3 From 7dafac0c34cb1cd07a783d1acdcd28fe43ef808a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Feb 2018 13:47:35 -0800 Subject: Avoid duplicating some scale tables --- Alc/bformatdec.c | 11 +++++++---- Alc/bformatdec.h | 8 ++++++++ Alc/panning.c | 48 ++---------------------------------------------- 3 files changed, 17 insertions(+), 50 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 03ea865c..28dbc742 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -114,11 +114,14 @@ void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, AL } -static const ALfloat UnitScale[MAX_AMBI_COEFFS] = { +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper N3D scalings. + */ +const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; -static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { +const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { 1.000000000f, /* ACN 0 (W), sqrt(1) */ 1.732050808f, /* ACN 1 (Y), sqrt(3) */ 1.732050808f, /* ACN 2 (Z), sqrt(3) */ @@ -136,7 +139,7 @@ static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { 2.645751311f, /* ACN 14 (N), sqrt(7) */ 2.645751311f, /* ACN 15 (P), sqrt(7) */ }; -static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { +const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { 1.414213562f, /* ACN 0 (W), sqrt(2) */ 1.732050808f, /* ACN 1 (Y), sqrt(3) */ 1.732050808f, /* ACN 2 (Z), sqrt(3) */ @@ -238,7 +241,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; - const ALfloat *coeff_scale = UnitScale; + const ALfloat *coeff_scale = N3D2N3DScale; bool periphonic; ALfloat ratio; ALsizei i; diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index 0011eb28..a6ca2209 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -21,6 +21,14 @@ #define XYZ_SCALE_3H3P 1.136697713f +/* NOTE: These are scale factors as applied to Ambisonics content. Decoder + * coefficients should be divided by these values to get proper N3D scalings. + */ +const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS]; +const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS]; +const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS]; + + struct AmbDecConf; struct BFormatDec; struct AmbiUpsampler; diff --git a/Alc/panning.c b/Alc/panning.c index 6baff75f..c8a245da 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -66,50 +66,6 @@ static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { 8, 9, 10, 11, 12, 13, 14, 15 }; -/* NOTE: These are scale factors as applied to Ambisonics content. Decoder - * coefficients should be divided by these values to get proper N3D scalings. - */ -static const ALfloat UnitScale[MAX_AMBI_COEFFS] = { - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f -}; -static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = { - 1.000000000f, /* ACN 0 (W), sqrt(1) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 2.236067978f, /* ACN 4 (V), sqrt(5) */ - 2.236067978f, /* ACN 5 (T), sqrt(5) */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 2.236067978f, /* ACN 7 (S), sqrt(5) */ - 2.236067978f, /* ACN 8 (U), sqrt(5) */ - 2.645751311f, /* ACN 9 (Q), sqrt(7) */ - 2.645751311f, /* ACN 10 (O), sqrt(7) */ - 2.645751311f, /* ACN 11 (M), sqrt(7) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.645751311f, /* ACN 13 (L), sqrt(7) */ - 2.645751311f, /* ACN 14 (N), sqrt(7) */ - 2.645751311f, /* ACN 15 (P), sqrt(7) */ -}; -static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { - 1.414213562f, /* ACN 0 (W), sqrt(2) */ - 1.732050808f, /* ACN 1 (Y), sqrt(3) */ - 1.732050808f, /* ACN 2 (Z), sqrt(3) */ - 1.732050808f, /* ACN 3 (X), sqrt(3) */ - 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ - 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ - 2.236067978f, /* ACN 6 (R), sqrt(5) */ - 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ - 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ - 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ - 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ - 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ - 2.645751311f, /* ACN 12 (K), sqrt(7) */ - 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ - 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ - 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ -}; - void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { @@ -626,7 +582,7 @@ static void InitPanning(ALCdevice *device) const ALsizei *acnmap = (device->AmbiLayout == AmbiLayout_FuMa) ? FuMa2ACN : ACN2ACN; const ALfloat *n3dscale = (device->AmbiScale == AmbiNorm_FuMa) ? FuMa2N3DScale : (device->AmbiScale == AmbiNorm_SN3D) ? SN3D2N3DScale : - /*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale; + /*(device->AmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale; ALfloat nfc_delay = 0.0f; count = (device->AmbiOrder == 3) ? 16 : @@ -712,7 +668,7 @@ static void InitPanning(ALCdevice *device) static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; - const ALfloat *coeff_scale = UnitScale; + const ALfloat *coeff_scale = N3D2N3DScale; ALfloat w_scale = 1.0f; ALfloat xyz_scale = 1.0f; ALsizei i, j; -- cgit v1.2.3 From 7f3d69fdbc838334b5e7135dc6b69c5ae596a771 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Feb 2018 21:42:26 -0800 Subject: Remove an unnecessary comment about if meters_per_unit is > 0 --- Alc/panning.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index c8a245da..72e3c5ae 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -446,9 +446,8 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde if(GetConfigValueBool(devname, "decoder", "nfc", 1) && ctrl_dist > 0.0f) { - /* NFC is only used when AvgSpeakerDist is greater than 0, and - * METERS_PER_UNIT is also greater than 0. In addition, NFC can only be - * used when rendering to an ambisonic buffer. + /* NFC is only used when AvgSpeakerDist is greater than 0, and can only + * be used when rendering to an ambisonic buffer. */ device->AvgSpeakerDist = ctrl_dist; -- cgit v1.2.3 From 7a974b2460156ea8af9e22b02ae1c06899a5047d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Feb 2018 17:15:51 -0800 Subject: Combine the vector reverse and partial scatter where they're together --- Alc/effects/reverb.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index caa02328..f6499bb7 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1363,10 +1363,20 @@ static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const AL static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *restrict in, const ALfloat xCoeff, const ALfloat yCoeff) { - out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); - out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); - out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); - out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); + out[0] = xCoeff*in[0] + yCoeff*( in[1] + -in[2] + in[3]); + out[1] = xCoeff*in[1] + yCoeff*(-in[0] + in[2] + in[3]); + out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); + out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); +} + +/* Same as above, but reverses the input. */ +static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat *restrict in, + const ALfloat xCoeff, const ALfloat yCoeff) +{ + out[0] = xCoeff*in[3] + yCoeff*(in[0] + -in[1] + in[2] ); + out[1] = xCoeff*in[2] + yCoeff*(in[0] + in[1] + -in[3]); + out[2] = xCoeff*in[1] + yCoeff*(in[0] + -in[2] + in[3]); + out[3] = xCoeff*in[0] + yCoeff*( + -in[1] + -in[2] + -in[3]); } /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass @@ -1408,14 +1418,6 @@ DECL_TEMPLATE(Unfaded) DECL_TEMPLATE(Faded) #undef DECL_TEMPLATE -/* A helper to reverse vector components. */ -static inline void VectorReverse(ALfloat *restrict out, const ALfloat *restrict in) -{ - ALsizei i; - for(i = 0;i < NUM_LINES;i++) - out[i] = in[NUM_LINES-1-i]; -} - /* This generates early reflections. * * This is done by obtaining the primary reflections (those arriving from the @@ -1469,10 +1471,9 @@ static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ for(j = 0;j < NUM_LINES;j++) \ out[j][i] = f[j]; \ \ - VectorReverse(fr, f); \ - VectorPartialScatter(f, fr, mixX, mixY); \ + VectorPartialScatterRev(fr, f, mixX, mixY); \ \ - DelayLineIn4(&State->Delay, offset-State->LateFeedTap, f); \ + DelayLineIn4(&State->Delay, offset-State->LateFeedTap, fr); \ \ offset++; \ fade += FadeStep; \ @@ -1551,10 +1552,9 @@ static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; - VectorReverse(fr, f); - VectorPartialScatter(f, fr, mixX, mixY); + VectorPartialScatterRev(fr, f, mixX, mixY); - DelayLineIn4(&State->Late.Delay, offset, f); + DelayLineIn4(&State->Late.Delay, offset, fr); offset++; fade += FadeStep; @@ -1588,10 +1588,9 @@ static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALflo for(j = 0;j < NUM_LINES;j++) out[j][i] = f[j]; - VectorReverse(fr, f); - VectorPartialScatter(f, fr, mixX, mixY); + VectorPartialScatterRev(fr, f, mixX, mixY); - DelayLineIn4(&State->Late.Delay, offset, f); + DelayLineIn4(&State->Late.Delay, offset, fr); offset++; } -- cgit v1.2.3 From 79604c3c0e0f3f71832a09348cc273a38882cc3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Feb 2018 18:10:35 -0800 Subject: Preserve RMS for the high-frequency HRTF ambisonic coefficients --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 72e3c5ae..cf42d3fb 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -896,9 +896,9 @@ static void InitHrtfPanning(ALCdevice *device) { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, }; static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { - 3.00000000e+00f, 1.73205081e+00f + 1.00000000e+00f, 5.77350269e-01f }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { - 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f + 9.80580676e-01f, 7.59554525e-01f, 3.92232270e-01f }; const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; -- cgit v1.2.3 From b5aa0c07599ce8e8fd17e4ec1a686f3cf0576458 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Feb 2018 18:16:39 -0800 Subject: Remove the unnecessary ComputeAmbientGains --- Alc/effects/distortion.c | 5 ++++- Alc/panning.c | 26 -------------------------- OpenAL32/Include/alu.h | 15 --------------- 3 files changed, 4 insertions(+), 42 deletions(-) diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index dcb2bfe4..6ee89594 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -77,6 +77,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex { const ALCdevice *device = context->Device; ALfloat frequency = (ALfloat)device->Frequency; + ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat bandwidth; ALfloat cutoff; ALfloat edge; @@ -103,7 +104,9 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); - ComputeAmbientGains(&device->Dry, slot->Params.Gain * props->Distortion.Gain, state->Gain); + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * props->Distortion.Gain, + state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/panning.c b/Alc/panning.c index cf42d3fb..08651736 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -38,7 +38,6 @@ extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -extern inline void ComputeAmbientGains(const DryMixParams *dry, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); extern inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); extern inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); @@ -162,31 +161,6 @@ void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, } -void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i; - - for(i = 0;i < numchans;i++) - gains[i] = chancoeffs[i][0] * 1.414213562f * ingain; - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - -void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALfloat gain = 0.0f; - ALsizei i; - - for(i = 0;i < numchans;i++) - { - if(chanmap[i].Index == 0) - gain += chanmap[i].Scale; - } - gains[0] = gain * 1.414213562f * ingain; - for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALsizei i, j; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 609118bf..14262d9b 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -467,21 +467,6 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, */ void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); -void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -/** - * ComputeAmbientGains - * - * Computes channel gains for ambient, omni-directional sounds. - */ -inline void ComputeAmbientGains(const DryMixParams *dry, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - if(dry->CoeffCount > 0) - ComputeAmbientGainsMC(dry->Ambi.Coeffs, dry->NumChannels, ingain, gains); - else - ComputeAmbientGainsBF(dry->Ambi.Map, dry->NumChannels, ingain, gains); -} - void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -- cgit v1.2.3 From fa9ab9af7cb559ff9ecc1846f2996265bfbea1ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Feb 2018 21:15:39 -0800 Subject: Minimize each response delay for the ambisonic HRTF decode --- Alc/hrtf.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index cf211470..b5d23a7c 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -204,6 +204,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N BandSplitter splitter; ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; + ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; ALsizei i, c, b; @@ -228,8 +229,6 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Calculate indices for left and right channels. */ idx[c] = evoffset + azidx; - - min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } memset(temps, 0, sizeof(temps)); @@ -237,8 +236,12 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N for(c = 0;c < AmbiCount;c++) { const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; - ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; - ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; + const ALsizei res_delay = mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1]); + ALsizei ldelay = Hrtf->delays[idx[c]][0] - res_delay; + ALsizei rdelay = Hrtf->delays[idx[c]][1] - res_delay; + + min_delay = mini(min_delay, res_delay); + max_delay = maxi(max_delay, res_delay); max_length = maxi(max_length, mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) @@ -308,7 +311,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N max_length += MOD_IR_SIZE-1; max_length -= max_length%MOD_IR_SIZE; - TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length); + TRACE("Skipped delay min: %d, max: %d, new FIR length: %d\n", min_delay, max_delay, + max_length); state->IrSize = max_length; #undef NUM_BANDS } -- cgit v1.2.3 From 6ff50558a04c9d59f0f9bd45d4588095b95c8ec5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 17 Feb 2018 22:12:54 -0800 Subject: Use a proper struct for specifying angular points --- Alc/hrtf.c | 8 ++++---- Alc/hrtf.h | 7 ++++++- Alc/panning.c | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index b5d23a7c..e0323146 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -194,7 +194,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, } -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain) +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain) { /* Set this to 2 for dual-band HRTF processing. May require a higher quality * band-splitter, or better calculation of the new IR length to deal with the @@ -216,15 +216,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALuint azcount; /* Calculate elevation index. */ - evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) * + evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c].Elev) * (Hrtf->evCount-1)/F_PI + 0.5f); - evidx = mini(evidx, Hrtf->evCount-1); + evidx = clampi(evidx, 0, Hrtf->evCount-1); azcount = Hrtf->azCount[evidx]; evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) * + azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c].Azim) * azcount/F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ diff --git a/Alc/hrtf.h b/Alc/hrtf.h index 60842e8d..cb6dfddc 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -63,6 +63,11 @@ typedef struct DirectHrtfState { } Chan[]; } DirectHrtfState; +struct AngularPoint { + ALfloat Elev; + ALfloat Azim; +}; + void FreeHrtfs(void); @@ -79,6 +84,6 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, * virtual speaker positions and HF/LF matrices for decoding to them. The * returned coefficients are ordered and scaled according to the matrices. */ -void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain); +void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 08651736..37802791 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -810,7 +810,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz static void InitHrtfPanning(ALCdevice *device) { /* NOTE: azimuth goes clockwise. */ - static const ALfloat AmbiPoints[][2] = { + static const struct AngularPoint AmbiPoints[] = { { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, -- cgit v1.2.3 From 1002bc36e04c79cf1e00d0d2e89558e45134bf86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 18 Feb 2018 23:54:40 -0800 Subject: Add an example for multi-zone reverb --- CMakeLists.txt | 9 + examples/almultireverb.c | 584 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 593 insertions(+) create mode 100644 examples/almultireverb.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 17f561f2..d5c219f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1525,6 +1525,15 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common OpenAL) + ADD_EXECUTABLE(almultireverb examples/almultireverb.c) + TARGET_COMPILE_DEFINITIONS(almultireverb PRIVATE ${CPP_DEFS}) + TARGET_INCLUDE_DIRECTORIES(almultireverb + PRIVATE ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) + TARGET_COMPILE_OPTIONS(almultireverb PRIVATE ${C_FLAGS}) + TARGET_LINK_LIBRARIES(almultireverb + PRIVATE ${LINKER_FLAGS} ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ex-common common + OpenAL ${MATH_LIB}) + ADD_EXECUTABLE(allatency examples/allatency.c) TARGET_COMPILE_DEFINITIONS(allatency PRIVATE ${CPP_DEFS}) TARGET_INCLUDE_DIRECTORIES(allatency diff --git a/examples/almultireverb.c b/examples/almultireverb.c new file mode 100644 index 00000000..cc8ae5dc --- /dev/null +++ b/examples/almultireverb.c @@ -0,0 +1,584 @@ +/* + * OpenAL Multi-Zone Reverb Example + * + * Copyright (c) 2018 by Chris Robinson + * + * 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 controlling multiple reverb zones to + * smoothly transition between reverb environments. The general concept is to + * extend single-reverb by also tracking the closest adjacent environment, and + * utilizing EAX Reverb's panning vectors to position them relative to the + * listener. + */ + +#include +#include + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx-presets.h" + +#include "common/alhelpers.h" + + +/* Filter object functions */ +static LPALGENFILTERS alGenFilters; +static LPALDELETEFILTERS alDeleteFilters; +static LPALISFILTER alIsFilter; +static LPALFILTERI alFilteri; +static LPALFILTERIV alFilteriv; +static LPALFILTERF alFilterf; +static LPALFILTERFV alFilterfv; +static LPALGETFILTERI alGetFilteri; +static LPALGETFILTERIV alGetFilteriv; +static LPALGETFILTERF alGetFilterf; +static LPALGETFILTERFV alGetFilterfv; + +/* Effect object functions */ +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 */ +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 initial reverb properties into the given OpenAL + * effect object, and returns non-zero on success. + */ +static int LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES *reverb) +{ + ALenum err; + + alGetError(); + + /* Prepate the effect for EAX Reverb (standard reverb doesn't contain + * the needed panning vectors). + */ + alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if((err=alGetError()) != AL_NO_ERROR) + { + fprintf(stderr, "Failed to set EAX Reverb: %s (0x%04x)\n", alGetString(err), err); + return 0; + } + + /* Load the reverb properties. */ + alEffectf(effect, AL_EAXREVERB_DENSITY, reverb->flDensity); + alEffectf(effect, AL_EAXREVERB_DIFFUSION, reverb->flDiffusion); + alEffectf(effect, AL_EAXREVERB_GAIN, reverb->flGain); + alEffectf(effect, AL_EAXREVERB_GAINHF, reverb->flGainHF); + alEffectf(effect, AL_EAXREVERB_GAINLF, reverb->flGainLF); + alEffectf(effect, AL_EAXREVERB_DECAY_TIME, reverb->flDecayTime); + alEffectf(effect, AL_EAXREVERB_DECAY_HFRATIO, reverb->flDecayHFRatio); + alEffectf(effect, AL_EAXREVERB_DECAY_LFRATIO, reverb->flDecayLFRatio); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_GAIN, reverb->flReflectionsGain); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_DELAY, reverb->flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, reverb->flReflectionsPan); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_GAIN, reverb->flLateReverbGain); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_DELAY, reverb->flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, reverb->flLateReverbPan); + alEffectf(effect, AL_EAXREVERB_ECHO_TIME, reverb->flEchoTime); + alEffectf(effect, AL_EAXREVERB_ECHO_DEPTH, reverb->flEchoDepth); + alEffectf(effect, AL_EAXREVERB_MODULATION_TIME, reverb->flModulationTime); + alEffectf(effect, AL_EAXREVERB_MODULATION_DEPTH, reverb->flModulationDepth); + alEffectf(effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, reverb->flAirAbsorptionGainHF); + alEffectf(effect, AL_EAXREVERB_HFREFERENCE, reverb->flHFReference); + alEffectf(effect, AL_EAXREVERB_LFREFERENCE, reverb->flLFReference); + alEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, reverb->flRoomRolloffFactor); + alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, reverb->iDecayHFLimit); + + /* Check if an error occured, and return failure if so. */ + if((err=alGetError()) != AL_NO_ERROR) + { + fprintf(stderr, "Error setting up reverb: %s\n", alGetString(err)); + return 0; + } + + return 1; +} + + +/* LoadBuffer loads the named audio file into an OpenAL buffer object, and + * returns the new buffer ID. + */ +static ALuint LoadSound(const char *filename) +{ + Sound_Sample *sample; + ALenum err, format; + ALuint buffer; + Uint32 slen; + + /* Open the audio file */ + sample = Sound_NewSampleFromFile(filename, NULL, 65536); + if(!sample) + { + fprintf(stderr, "Could not open audio in %s\n", filename); + return 0; + } + + /* Get the sound format, and figure out the OpenAL format */ + if(sample->actual.channels == 1) + { + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_MONO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_MONO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } + } + else if(sample->actual.channels == 2) + { + if(sample->actual.format == AUDIO_U8) + format = AL_FORMAT_STEREO8; + else if(sample->actual.format == AUDIO_S16SYS) + format = AL_FORMAT_STEREO16; + else + { + fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format); + Sound_FreeSample(sample); + return 0; + } + } + else + { + fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels); + Sound_FreeSample(sample); + return 0; + } + + /* Decode the whole audio stream to a buffer. */ + slen = Sound_DecodeAll(sample); + if(!sample->buffer || slen == 0) + { + fprintf(stderr, "Failed to read audio from %s\n", filename); + Sound_FreeSample(sample); + return 0; + } + + /* Buffer the audio data into a new buffer object, then free the data and + * close the file. */ + buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate); + Sound_FreeSample(sample); + + /* 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(buffer && alIsBuffer(buffer)) + alDeleteBuffers(1, &buffer); + return 0; + } + + return buffer; +} + + +/* Helper to calculate the dot-product of the two given vectors. */ +static ALfloat dot_product(const ALfloat vec0[3], const ALfloat vec1[3]) +{ + return vec0[0]*vec1[0] + vec0[1]*vec1[1] + vec0[2]*vec1[2]; +} + + +int main(int argc, char **argv) +{ + const int MaxTransitions = 8; + EFXEAXREVERBPROPERTIES reverb0 = EFX_REVERB_PRESET_CASTLE_LARGEROOM; + EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_CASTLE_LONGPASSAGE; + struct timespec basetime; + ALCdevice *device = NULL; + ALCcontext *context = NULL; + ALuint effects[2] = { 0, 0 }; + ALuint slots[2] = { 0, 0 }; + ALuint direct_filter = 0; + ALuint buffer = 0; + ALuint source = 0; + ALCint num_sends = 0; + ALenum state = AL_INITIAL; + ALfloat direct_gain = 1.0f; + int loops = 0; + + /* Print out usage if no arguments were specified */ + if(argc < 2) + { + fprintf(stderr, "Usage: %s [-device ] [options] \n\n" + "Options:\n" + "\t-nodirect\tSilence direct path output (easier to hear reverb)\n\n", + argv[0]); + return 1; + } + + /* Initialize OpenAL, and check for EFX support with at least 2 auxiliary + * sends (if multiple sends are supported, 2 are provided by default; if + * you want more, you have to request it through alcCreateContext). + */ + argv++; argc--; + if(InitAL(&argv, &argc) != 0) + return 1; + + while(argc > 0) + { + if(strcmp(argv[0], "-nodirect") == 0) + direct_gain = 0.0f; + else + break; + argv++; + argc--; + } + if(argc < 1) + { + fprintf(stderr, "Usage: %s [-device ] [options] \n\n" + "Options:\n" + "\t-nodirect\tSilence direct path output (easier to hear reverb).\n\n", + argv[0]); + CloseAL(); + return 1; + } + + context = alcGetCurrentContext(); + device = alcGetContextsDevice(context); + + if(!alcIsExtensionPresent(device, "ALC_EXT_EFX")) + { + fprintf(stderr, "Error: EFX not supported\n"); + CloseAL(); + return 1; + } + + num_sends = 0; + alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &num_sends); + if(alcGetError(device) != ALC_NO_ERROR || num_sends < 2) + { + fprintf(stderr, "Error: Device does not support multiple sends (got %d, need 2)\n", + num_sends); + CloseAL(); + return 1; + } + + /* Define a macro to help load the function pointers. */ +#define LOAD_PROC(x) ((x) = alGetProcAddress(#x)) + LOAD_PROC(alGenFilters); + LOAD_PROC(alDeleteFilters); + LOAD_PROC(alIsFilter); + LOAD_PROC(alFilteri); + LOAD_PROC(alFilteriv); + LOAD_PROC(alFilterf); + LOAD_PROC(alFilterfv); + LOAD_PROC(alGetFilteri); + LOAD_PROC(alGetFilteriv); + LOAD_PROC(alGetFilterf); + LOAD_PROC(alGetFilterfv); + + LOAD_PROC(alGenEffects); + LOAD_PROC(alDeleteEffects); + LOAD_PROC(alIsEffect); + LOAD_PROC(alEffecti); + LOAD_PROC(alEffectiv); + LOAD_PROC(alEffectf); + LOAD_PROC(alEffectfv); + LOAD_PROC(alGetEffecti); + LOAD_PROC(alGetEffectiv); + LOAD_PROC(alGetEffectf); + LOAD_PROC(alGetEffectfv); + + LOAD_PROC(alGenAuxiliaryEffectSlots); + LOAD_PROC(alDeleteAuxiliaryEffectSlots); + LOAD_PROC(alIsAuxiliaryEffectSlot); + LOAD_PROC(alAuxiliaryEffectSloti); + LOAD_PROC(alAuxiliaryEffectSlotiv); + LOAD_PROC(alAuxiliaryEffectSlotf); + LOAD_PROC(alAuxiliaryEffectSlotfv); + LOAD_PROC(alGetAuxiliaryEffectSloti); + LOAD_PROC(alGetAuxiliaryEffectSlotiv); + LOAD_PROC(alGetAuxiliaryEffectSlotf); + LOAD_PROC(alGetAuxiliaryEffectSlotfv); +#undef LOAD_PROC + + /* Initialize SDL_sound. */ + Sound_Init(); + + /* Load the sound into a buffer. */ + buffer = LoadSound(argv[0]); + if(!buffer) + { + CloseAL(); + Sound_Quit(); + return 1; + } + + /* Generate two effects for two "zones", and load a reverb into each one. + * Note that unlike single-zone reverb, where you can store one effect per + * preset, for multi-zone reverb you should have one effect per environment + * instance, or one per audible zone. This is because we'll be changing the + * effects' properties in real-time based on the environment instance. + */ + alGenEffects(2, effects); + if(!LoadEffect(effects[0], &reverb0) || !LoadEffect(effects[1], &reverb1)) + { + alDeleteEffects(2, effects); + alDeleteBuffers(1, &buffer); + Sound_Quit(); + CloseAL(); + return 1; + } + + /* Create the effect slot objects, one for each "active" effect. */ + alGenAuxiliaryEffectSlots(2, slots); + + /* Tell the effect slots to use the loaded effect objects, with slot 0 for + * Zone 0 and slot 1 for Zone 1. Note that this effectively copies the + * effect properties. Modifying or deleting the effect object afterward + * won't directly affect the effect slot until they're reapplied like this. + */ + alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); + alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); + assert(alGetError()==AL_NO_ERROR && "Failed to set effect slot"); + + /* For the purposes of this example, prepare a filter that optionally + * silences the direct path. This allows us to hear just the reverberation. + * A filter like this is normally used for obstruction, where the path + * directly between the listener and source is blocked (the exact + * properties depending on the type and thickness of the obstructing + * material). + */ + alGenFilters(1, &direct_filter); + alFilteri(direct_filter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilterf(direct_filter, AL_LOWPASS_GAIN, direct_gain); + assert(alGetError()==AL_NO_ERROR && "Failed to set direct filter"); + + /* Create the source to play the sound with. */ + source = 0; + alGenSources(1, &source); + alSourcei(source, AL_LOOPING, AL_TRUE); + alSourcei(source, AL_DIRECT_FILTER, direct_filter); + alSourcei(source, AL_BUFFER, buffer); + + /* Connect the source to the effect slots. Here, we connect source send 0 + * to Zone 0's slot, and send 1 to Zone 1's slot. Filters can be specified + * to occlude the source from each zone by varying amounts; for example, a + * source within a particular zone would be unfiltered, while a source that + * can only see a zone through a window may be attenuated for that zone. + */ + alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[0], 0, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[1], 1, AL_FILTER_NULL); + assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); + + /* Get the base time, and set the example to stop after a number of + * transitions. + */ + altimespec_get(&basetime, AL_TIME_UTC); + loops = MaxTransitions; + printf("Transition %d of %d...\n", (MaxTransitions-loops+1), MaxTransitions); + + /* Play the sound for a while. */ + alSourcePlay(source); + do { + /* Individual reverb zones are connected via "portals". Each portal has + * a position (center point of the connecting area), a normal (facing + * direction), and a radius (approximate size of the connecting area). + * For this example it also has movement velocity, although normally it + * would be the listener that moves relative to the portal instead of + * the portal itself. + */ + const ALfloat portal_pos[3] = { -10.0f, 0.0f, 0.0f }; + const ALfloat portal_norm[3] = { 1.0f, 0.0f, 0.0f }; + const ALfloat portal_vel[3] = { 5.0f, 0.0f, 0.0f }; + const ALfloat portal_radius = 2.5f; + ALfloat other_dir[3], this_dir[3]; + ALfloat local_norm[3]; + ALfloat dist, timediff; + struct timespec curtime; + + /* Start a batch update, to ensure all changes apply simultaneously. */ + alcSuspendContext(context); + + /* Get the current time to track the amount of time that passed. + * Convert the difference to seconds. + */ + altimespec_get(&curtime, AL_TIME_UTC); + timediff = (ALfloat)(curtime.tv_sec - basetime.tv_sec); + timediff += (ALfloat)(curtime.tv_nsec - basetime.tv_nsec) / 1000000000.0f; + + /* Avoid negative time deltas, in case of non-monotonic clocks. */ + if(timediff < 0.0f) + timediff = 0.0f; + else while(timediff >= 4.0f) + { + /* For this example, each transition occurs over 4 seconds. + * Decrease the delta and increase the base time to start a new + * transition. + */ + timediff -= 4.0f; + basetime.tv_sec += 4; + if(--loops > 0) + printf("Transition %d of %d...\n", (MaxTransitions-loops+1), MaxTransitions); + } + + /* Move the portal according to the amount of time passed. other_dir + * represents the listener-relative point from the current zone to the + * other adjacent zone. + */ + other_dir[0] = portal_pos[0] + portal_vel[0]*timediff; + other_dir[1] = portal_pos[1] + portal_vel[1]*timediff; + other_dir[2] = portal_pos[2] + portal_vel[2]*timediff; + /* In a normal application you may also want to scale down the portal's + * apparent radius depending on its local angle, since less of the + * adjacent zone would be in view of the listener. You would also want + * to rotate the portal's normal according to the listener orientation. + * + * For this example, the portal is always head-on so there's no need to + * adjust the radius. But every other transition iteration inverts the + * normal, which essentially simulates a different portal moving in + * closer than the last one, switching the old adjacent zone to a new + * one. + */ + local_norm[0] = portal_norm[0] * ((loops&1) ? -1.0f : 1.0f); + local_norm[1] = portal_norm[1] * ((loops&1) ? -1.0f : 1.0f); + local_norm[2] = portal_norm[2] * ((loops&1) ? -1.0f : 1.0f); + + /* Calculate the distance from the listener to the portal. */ + dist = sqrtf(dot_product(other_dir, other_dir)); + if(!(dist > 0.00001f)) + { + /* We're practically in the center of the portal. Give the panning + * vectors a 50/50 split, with Zone 0 covering the half in front of + * the normal, and Zone 1 covering the half behind. + */ + this_dir[0] = local_norm[0] / 2.0f; + this_dir[1] = local_norm[1] / 2.0f; + this_dir[2] = local_norm[2] / 2.0f; + + other_dir[0] = local_norm[0] / -2.0f; + other_dir[1] = local_norm[1] / -2.0f; + other_dir[2] = local_norm[2] / -2.0f; + + alEffectfv(effects[0], AL_EAXREVERB_REFLECTIONS_PAN, this_dir); + alEffectfv(effects[0], AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + + alEffectfv(effects[1], AL_EAXREVERB_REFLECTIONS_PAN, other_dir); + alEffectfv(effects[1], AL_EAXREVERB_LATE_REVERB_PAN, other_dir); + } + else + { + ALuint other_effect, this_effect; + ALfloat spread; + + /* Normalize the direction to the portal. */ + other_dir[0] /= dist; + other_dir[1] /= dist; + other_dir[2] /= dist; + + /* Calculate the 'spread' of the portal, which is the amount of + * coverage the other zone has. + */ + spread = atan2f(portal_radius, dist) / ((ALfloat)M_PI); + + /* Figure out which zone we're in, given the direction to the + * portal and its normal. + */ + if(dot_product(other_dir, local_norm) <= 0.0f) + { + /* We're in front of the portal, so we're in Zone 0. */ + this_effect = effects[0]; + other_effect = effects[1]; + } + else + { + /* We're behind the portal, so we're in Zone 1. */ + this_effect = effects[1]; + other_effect = effects[0]; + } + + /* Pan the current zone to the opposite direction of the portal, + * and take the remaining percentage of the portal's spread. As the + * portal's spread increases, this zone's spread decreases, which + * is indicated by a larger panning vector. + */ + this_dir[0] = other_dir[0] * -spread; + this_dir[1] = other_dir[1] * -spread; + this_dir[2] = other_dir[2] * -spread; + /* Scale the other zone's panning vector down as the portal's + * spread increases, so that it covers more. + */ + other_dir[0] *= 1.0f-spread; + other_dir[1] *= 1.0f-spread; + other_dir[2] *= 1.0f-spread; + + /* Now set the effects' panning vectors. */ + alEffectfv(this_effect, AL_EAXREVERB_REFLECTIONS_PAN, this_dir); + alEffectfv(this_effect, AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + + alEffectfv(other_effect, AL_EAXREVERB_REFLECTIONS_PAN, other_dir); + alEffectfv(other_effect, AL_EAXREVERB_LATE_REVERB_PAN, other_dir); + } + + /* Finally, update the effect slots with the updated effect parameters, + * and finish the update batch. + */ + alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); + alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); + alcProcessContext(context); + + al_nssleep(10000000); + + alGetSourcei(source, AL_SOURCE_STATE, &state); + } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING && loops > 0); + + /* All done. Delete resources, and close down SDL_sound and OpenAL. */ + alDeleteSources(1, &source); + alDeleteAuxiliaryEffectSlots(2, slots); + alDeleteEffects(2, effects); + alDeleteFilters(1, &direct_filter); + alDeleteBuffers(1, &buffer); + + Sound_Quit(); + CloseAL(); + + return 0; +} -- cgit v1.2.3 From d7d043a5ef9ede70e656862442c1eda6cc386762 Mon Sep 17 00:00:00 2001 From: Alexey Elymanov Date: Tue, 20 Feb 2018 11:53:55 +0300 Subject: fix building on freebsd (clang) fixes error: 'pow' is not a member of 'std' --- examples/alffplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 7f83f61d..6f6773a4 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -18,6 +18,7 @@ #include #include #include +#include extern "C" { #include "libavcodec/avcodec.h" -- cgit v1.2.3 From 51c6d13c0f68cddee53083f02fb01028d0e04c71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Feb 2018 03:21:29 -0800 Subject: Add almultireverb to the install target --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5c219f9..bd531128 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1562,7 +1562,7 @@ IF(ALSOFT_EXAMPLES) OpenAL ${MATH_LIB}) IF(ALSOFT_INSTALL) - INSTALL(TARGETS alplay alstream alreverb allatency alloopback alhrtf + INSTALL(TARGETS alplay alstream alreverb almultireverb allatency alloopback alhrtf RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -- cgit v1.2.3 From 9fc2dbe063aecb8947abfb5edfb351d0514eb432 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Feb 2018 21:46:08 -0800 Subject: Update the multi-zone reverb example for clarity --- examples/almultireverb.c | 99 +++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index cc8ae5dc..5adab269 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -25,7 +25,7 @@ /* This file contains an example for controlling multiple reverb zones to * smoothly transition between reverb environments. The general concept is to * extend single-reverb by also tracking the closest adjacent environment, and - * utilizing EAX Reverb's panning vectors to position them relative to the + * utilize EAX Reverb's panning vectors to position them relative to the * listener. */ @@ -42,6 +42,11 @@ #include "common/alhelpers.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + /* Filter object functions */ static LPALGENFILTERS alGenFilters; static LPALDELETEFILTERS alDeleteFilters; @@ -91,7 +96,7 @@ static int LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES *reverb) alGetError(); - /* Prepate the effect for EAX Reverb (standard reverb doesn't contain + /* Prepare the effect for EAX Reverb (standard reverb doesn't contain * the needed panning vectors). */ alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); @@ -228,7 +233,7 @@ static ALfloat dot_product(const ALfloat vec0[3], const ALfloat vec1[3]) int main(int argc, char **argv) { - const int MaxTransitions = 8; + static const int MaxTransitions = 8; EFXEAXREVERBPROPERTIES reverb0 = EFX_REVERB_PRESET_CASTLE_LARGEROOM; EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_CASTLE_LONGPASSAGE; struct timespec basetime; @@ -356,7 +361,8 @@ int main(int argc, char **argv) * Note that unlike single-zone reverb, where you can store one effect per * preset, for multi-zone reverb you should have one effect per environment * instance, or one per audible zone. This is because we'll be changing the - * effects' properties in real-time based on the environment instance. + * effects' properties in real-time based on the environment instance + * relative to the listener. */ alGenEffects(2, effects); if(!LoadEffect(effects[0], &reverb0) || !LoadEffect(effects[1], &reverb1)) @@ -381,7 +387,7 @@ int main(int argc, char **argv) assert(alGetError()==AL_NO_ERROR && "Failed to set effect slot"); /* For the purposes of this example, prepare a filter that optionally - * silences the direct path. This allows us to hear just the reverberation. + * silences the direct path which allows us to hear just the reverberation. * A filter like this is normally used for obstruction, where the path * directly between the listener and source is blocked (the exact * properties depending on the type and thickness of the obstructing @@ -409,12 +415,10 @@ int main(int argc, char **argv) alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[1], 1, AL_FILTER_NULL); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); - /* Get the base time, and set the example to stop after a number of - * transitions. - */ + /* Get the current time as the base for timing in the main loop. */ altimespec_get(&basetime, AL_TIME_UTC); - loops = MaxTransitions; - printf("Transition %d of %d...\n", (MaxTransitions-loops+1), MaxTransitions); + loops = 0; + printf("Transition %d of %d...\n", loops+1, MaxTransitions); /* Play the sound for a while. */ alSourcePlay(source); @@ -432,6 +436,8 @@ int main(int argc, char **argv) const ALfloat portal_radius = 2.5f; ALfloat other_dir[3], this_dir[3]; ALfloat local_norm[3]; + ALfloat local_dir[3]; + ALfloat local_radius; ALfloat dist, timediff; struct timespec curtime; @@ -456,34 +462,30 @@ int main(int argc, char **argv) */ timediff -= 4.0f; basetime.tv_sec += 4; - if(--loops > 0) - printf("Transition %d of %d...\n", (MaxTransitions-loops+1), MaxTransitions); + if(++loops < MaxTransitions) + printf("Transition %d of %d...\n", loops+1, MaxTransitions); } - /* Move the portal according to the amount of time passed. other_dir - * represents the listener-relative point from the current zone to the - * other adjacent zone. + /* Move the portal according to the amount of time passed. local_dir + * represents the listener-relative point to the adjacent zone. */ - other_dir[0] = portal_pos[0] + portal_vel[0]*timediff; - other_dir[1] = portal_pos[1] + portal_vel[1]*timediff; - other_dir[2] = portal_pos[2] + portal_vel[2]*timediff; - /* In a normal application you may also want to scale down the portal's - * apparent radius depending on its local angle, since less of the - * adjacent zone would be in view of the listener. You would also want - * to rotate the portal's normal according to the listener orientation. + local_dir[0] = portal_pos[0] + portal_vel[0]*timediff; + local_dir[1] = portal_pos[1] + portal_vel[1]*timediff; + local_dir[2] = portal_pos[2] + portal_vel[2]*timediff; + /* A normal application would also rotate the portal's normal given the + * listener orientation, to get the listener-relative normal. * - * For this example, the portal is always head-on so there's no need to - * adjust the radius. But every other transition iteration inverts the - * normal, which essentially simulates a different portal moving in - * closer than the last one, switching the old adjacent zone to a new - * one. + * For this example, the portal is always head-on but every other + * transition negates the normal. This effectively simulates a + * different portal moving in closer than the last one that faces the + * other way, switching the old adjacent zone to a new one. */ local_norm[0] = portal_norm[0] * ((loops&1) ? -1.0f : 1.0f); local_norm[1] = portal_norm[1] * ((loops&1) ? -1.0f : 1.0f); local_norm[2] = portal_norm[2] * ((loops&1) ? -1.0f : 1.0f); /* Calculate the distance from the listener to the portal. */ - dist = sqrtf(dot_product(other_dir, other_dir)); + dist = sqrtf(dot_product(local_dir, local_dir)); if(!(dist > 0.00001f)) { /* We're practically in the center of the portal. Give the panning @@ -510,19 +512,24 @@ int main(int argc, char **argv) ALfloat spread; /* Normalize the direction to the portal. */ - other_dir[0] /= dist; - other_dir[1] /= dist; - other_dir[2] /= dist; + local_dir[0] /= dist; + local_dir[1] /= dist; + local_dir[2] /= dist; + + /* Scale the radius according to its local angle. The visibility to + * the other zone reduces as the portal becomes perpendicular. + */ + local_radius = portal_radius * fabsf(dot_product(local_dir, local_norm)); /* Calculate the 'spread' of the portal, which is the amount of - * coverage the other zone has. + * coverage the other zone has around the listener. */ - spread = atan2f(portal_radius, dist) / ((ALfloat)M_PI); + spread = atan2f(local_radius, dist) / (ALfloat)M_PI; /* Figure out which zone we're in, given the direction to the * portal and its normal. */ - if(dot_product(other_dir, local_norm) <= 0.0f) + if(dot_product(local_dir, local_norm) <= 0.0f) { /* We're in front of the portal, so we're in Zone 0. */ this_effect = effects[0]; @@ -535,20 +542,18 @@ int main(int argc, char **argv) other_effect = effects[0]; } - /* Pan the current zone to the opposite direction of the portal, - * and take the remaining percentage of the portal's spread. As the - * portal's spread increases, this zone's spread decreases, which - * is indicated by a larger panning vector. - */ - this_dir[0] = other_dir[0] * -spread; - this_dir[1] = other_dir[1] * -spread; - this_dir[2] = other_dir[2] * -spread; /* Scale the other zone's panning vector down as the portal's - * spread increases, so that it covers more. + * spread increases, so that it envelops the listener more. + */ + other_dir[0] = local_dir[0] * (1.0f-spread); + other_dir[1] = local_dir[1] * (1.0f-spread); + other_dir[2] = local_dir[2] * (1.0f-spread); + /* Pan the current zone to the opposite direction of the portal, + * and take the remaining percentage of the portal's spread. */ - other_dir[0] *= 1.0f-spread; - other_dir[1] *= 1.0f-spread; - other_dir[2] *= 1.0f-spread; + this_dir[0] = local_dir[0] * -spread; + this_dir[1] = local_dir[1] * -spread; + this_dir[2] = local_dir[2] * -spread; /* Now set the effects' panning vectors. */ alEffectfv(this_effect, AL_EAXREVERB_REFLECTIONS_PAN, this_dir); @@ -568,7 +573,7 @@ int main(int argc, char **argv) al_nssleep(10000000); alGetSourcei(source, AL_SOURCE_STATE, &state); - } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING && loops > 0); + } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING && loops < MaxTransitions); /* All done. Delete resources, and close down SDL_sound and OpenAL. */ alDeleteSources(1, &source); -- cgit v1.2.3 From bf886444d2b0024523416053d5eec971d8a54e56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Feb 2018 19:53:18 -0800 Subject: Avoid multiple GetChannelIdxByName calls --- Alc/panning.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 37802791..ae8315f3 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -293,7 +293,8 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp for(i = 0;i < conf->NumSpeakers;i++) { - int c = -1; + enum Channel ch; + int chidx = -1; /* NOTE: AmbDec does not define any standard speaker names, however * for this to work we have to by able to find the output channel @@ -316,62 +317,63 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp * and vice-versa. */ if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0) - c = GetChannelIdxByName(&device->RealOut, FrontLeft); + ch = FrontLeft; else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0) - c = GetChannelIdxByName(&device->RealOut, FrontRight); + ch = FrontRight; else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0) - c = GetChannelIdxByName(&device->RealOut, FrontCenter); + ch = FrontCenter; else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0) { if(device->FmtChans == DevFmtX51Rear) - c = GetChannelIdxByName(&device->RealOut, BackLeft); + ch = BackLeft; else - c = GetChannelIdxByName(&device->RealOut, SideLeft); + ch = SideLeft; } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0) { if(device->FmtChans == DevFmtX51Rear) - c = GetChannelIdxByName(&device->RealOut, BackRight); + ch = BackRight; else - c = GetChannelIdxByName(&device->RealOut, SideRight); + ch = SideRight; } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0) { if(device->FmtChans == DevFmtX51) - c = GetChannelIdxByName(&device->RealOut, SideLeft); + ch = SideLeft; else - c = GetChannelIdxByName(&device->RealOut, BackLeft); + ch = BackLeft; } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0) { if(device->FmtChans == DevFmtX51) - c = GetChannelIdxByName(&device->RealOut, SideRight); + ch = SideRight; else - c = GetChannelIdxByName(&device->RealOut, BackRight); + ch = BackRight; } else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0) - c = GetChannelIdxByName(&device->RealOut, BackCenter); + ch = BackCenter; else { const char *name = alstr_get_cstr(conf->Speakers[i].Name); unsigned int n; - char ch; + char c; - if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16) - c = GetChannelIdxByName(&device->RealOut, Aux0+n); + if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) + ch = Aux0+n; else { ERR("AmbDec speaker label \"%s\" not recognized\n", name); return false; } } - if(c == -1) + chidx = GetChannelIdxByName(&device->RealOut, ch); + if(chidx == -1) { ERR("Failed to lookup AmbDec speaker label %s\n", alstr_get_cstr(conf->Speakers[i].Name)); return false; } - speakermap[i] = c; + speakermap[i] = chidx; } return true; -- cgit v1.2.3 From 14bdc6c2ef295dd4c7a22faab1e834def125177d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Feb 2018 12:03:52 -0800 Subject: Use separate functions to add and remove active effect slots --- OpenAL32/alAuxEffectSlot.c | 139 +++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 56 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 038adbb0..d5c39051 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -38,6 +38,9 @@ extern inline void LockEffectSlotList(ALCcontext *context); extern inline void UnlockEffectSlotList(ALCcontext *context); +static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); +static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context); + static const struct { ALenum Type; ALeffectStateFactory* (*GetFactory)(void); @@ -105,7 +108,6 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo { ALCdevice *device; ALCcontext *context; - ALeffectslot **tmpslots = NULL; ALsizei cur; ALenum err; @@ -114,10 +116,10 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n); - tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n); + if(n == 0) goto done; - device = context->Device; LockEffectSlotList(context); + device = context->Device; if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n) { UnlockEffectSlotList(context); @@ -162,33 +164,12 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1; *iter = slot; - tmpslots[cur] = slot; effectslots[cur] = slot->id; } - if(n > 0) - { - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); - struct ALeffectslotArray *newarray = NULL; - ALsizei newcount = curarray->count + n; - ALCdevice *device; - - newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - newarray->count = newcount; - memcpy(newarray->slot, tmpslots, sizeof(ALeffectslot*)*n); - if(curarray) - memcpy(newarray->slot+n, curarray->slot, sizeof(ALeffectslot*)*curarray->count); - - newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, - almemory_order_acq_rel); - device = context->Device; - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(newarray); - } + AddActiveEffectSlots(effectslots, n, context); UnlockEffectSlotList(context); done: - al_free(tmpslots); ALCcontext_DecRef(context); } @@ -204,6 +185,8 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * LockEffectSlotList(context); if(!(n >= 0)) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); + if(n == 0) goto done; + for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) @@ -215,37 +198,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint * } // All effectslots are valid - if(n > 0) - { - struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); - struct ALeffectslotArray *newarray = NULL; - ALsizei newcount = curarray->count - n; - ALCdevice *device; - ALsizei j, k; - - assert(newcount >= 0); - newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - newarray->count = newcount; - for(i = j = 0;i < newarray->count;) - { - slot = curarray->slot[j++]; - for(k = 0;k < n;k++) - { - if(slot->id == effectslots[k]) - break; - } - if(k == n) - newarray->slot[i++] = slot; - } - - newarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, - almemory_order_acq_rel); - device = context->Device; - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - al_free(newarray); - } - + RemoveActiveEffectSlots(effectslots, n, context); for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) @@ -630,6 +583,80 @@ void ALeffectState_Destruct(ALeffectState *UNUSED(state)) } +static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, + almemory_order_acquire); + struct ALeffectslotArray *newarray = NULL; + ALsizei newcount = curarray->count + count; + ALCdevice *device = context->Device; + ALsizei i, j; + + /* Insert the new effect slots into the head of the array, followed by the + * existing ones. + */ + newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); + newarray->count = newcount; + for(i = 0;i < count;i++) + newarray->slot[i] = LookupEffectSlot(context, slotids[i]); + for(j = 0;i < newcount;) + newarray->slot[i++] = curarray->slot[j++]; + /* Remove any duplicates (first instance of each will be kept). */ + for(i = 1;i < newcount;i++) + { + for(j = i;j != 0;) + { + if(newarray->slot[i] == newarray->slot[--j]) + break; + } + if(j != 0) + { + newcount--; + for(j = i;j < newcount;j++) + newarray->slot[j] = newarray->slot[j+1]; + i--; + } + } + newarray->count = newcount; + + curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + +static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context) +{ + struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, + almemory_order_acquire); + struct ALeffectslotArray *newarray = NULL; + ALsizei newcount = curarray->count - count; + ALCdevice *device = context->Device; + ALsizei i, j; + + assert(newcount >= 0); + newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); + newarray->count = newcount; + for(i = j = 0;i < newarray->count;) + { + ALeffectslot *slot = curarray->slot[j++]; + ALsizei k = count; + while(k != 0) + { + if(slot->id == slotids[--k]) + break; + } + if(k == 0) + newarray->slot[i++] = slot; + } + + curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); + while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) + althrd_yield(); + al_free(curarray); +} + + ALenum InitEffectSlot(ALeffectslot *slot) { ALeffectStateFactory *factory; -- cgit v1.2.3 From a1ef5e38b6ee6db718fa7652d7831d2f86ec6b1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Feb 2018 09:24:18 -0800 Subject: Handle source state change events --- Alc/ALu.c | 51 +++++++++++++++++++++++++++++++++++++--- OpenAL32/alSource.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f73b1985..b130677d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -209,6 +209,41 @@ void aluInit(void) } +static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) +{ + ALbitfieldSOFT enabledevt; + AsyncEvent evt; + size_t strpos; + ALuint scale; + + enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(!(enabledevt&EventType_SourceStateChange)) return; + + evt.EnumType = EventType_SourceStateChange; + evt.Type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.ObjectId = id; + evt.Param = AL_STOPPED; + + /* Normally snprintf would be used, but this is called from the mixer and + * that function's not real-time safe, so we have to construct it manually. + */ + strcpy(evt.Message, "Source ID "); strpos = 10; + scale = 1000000000; + while(scale > 0 && scale > id) + scale /= 10; + while(scale > 0) + { + evt.Message[strpos++] = '0' + ((id/scale)%10); + scale /= 10; + } + strcpy(evt.Message+strpos, " state changed to AL_STOPPED"); + + if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) + ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); + alsem_post(&context->EventSem); +} + + static void ProcessHrtf(ALCdevice *device, ALsizei SamplesToDo) { DirectHrtfState *state; @@ -1778,6 +1813,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); + SendSourceStoppedEvent(ctx, source->id); } } } @@ -1902,10 +1938,10 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) { + ALbitfieldSOFT enabledevt = ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire); ALsizei i; - if((ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire)&EventType_Disconnected) && - ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) + if((enabledevt&EventType_Disconnected) && ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) { ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1); alsem_post(&ctx->EventSem); @@ -1914,8 +1950,17 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) for(i = 0;i < ctx->VoiceCount;i++) { ALvoice *voice = ctx->Voices[i]; + ALsource *source; - ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); + source = ATOMIC_EXCHANGE_PTR(&voice->Source, NULL, almemory_order_relaxed); + if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed)) + { + /* If the source's voice was playing, it's now effectively + * stopped (the source state will be updated the next time it's + * checked). + */ + SendSourceStoppedEvent(ctx, source->id); + } ATOMIC_STORE(&voice->Playing, false, almemory_order_release); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 2323da3e..bb3a62c3 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -32,6 +32,7 @@ #include "alSource.h" #include "alBuffer.h" #include "alAuxEffectSlot.h" +#include "ringbuffer.h" #include "backends/base.h" @@ -232,6 +233,36 @@ static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) IsPlayingOrPaused(source); } + +/** Can only be called while the mixer is locked! */ +static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) +{ + ALbitfieldSOFT enabledevt; + AsyncEvent evt; + + enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(!(enabledevt&EventType_SourceStateChange)) return; + + evt.EnumType = EventType_SourceStateChange; + evt.Type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.ObjectId = id; + evt.Param = state; + snprintf(evt.Message, sizeof(evt.Message), "Source ID %u state changed to %s", id, + (state==AL_INITIAL) ? "AL_INITIAL" : + (state==AL_PLAYING) ? "AL_PLAYING" : + (state==AL_PAUSED) ? "AL_PAUSED" : + (state==AL_STOPPED) ? "AL_STOPPED" : "" + ); + /* The mixer may have queued a state change that's not yet been processed, + * and we don't want state change messages to occur out of order, so send + * it through the async queue to ensure proper ordering. + */ + if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) + ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); + alsem_post(&context->EventSem); +} + + static ALint FloatValsByProp(ALenum prop) { if(prop != (ALenum)((SourceProp)prop)) @@ -2396,10 +2427,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* If the device is disconnected, go right to stopped. */ if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { + /* TODO: Send state change event? */ for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->OffsetType = AL_NONE; + source->Offset = 0.0; } ALCdevice_Unlock(device); goto done; @@ -2443,15 +2477,18 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) } /* If there's nothing to play, go right to stopped. */ - if(!BufferList) + if(UNLIKELY(!BufferList)) { /* NOTE: A source without any playable buffers should not have an * ALvoice since it shouldn't be in a playing or paused state. So * there's no need to look up its voice and clear the source. */ + ALenum oldstate = GetSourceState(source, NULL); ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; + if(oldstate != AL_STOPPED) + SendStateChangeEvent(context, source->id, AL_STOPPED); continue; } @@ -2471,6 +2508,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) /* A source that's paused simply resumes. */ ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + SendStateChangeEvent(context, source->id, AL_PLAYING); continue; default: @@ -2543,6 +2581,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->Playing, true, almemory_order_release); ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); source->VoiceIdx = vidx; + + SendStateChangeEvent(context, source->id, AL_PLAYING); } ALCdevice_Unlock(device); @@ -2581,13 +2621,12 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) { source = LookupSource(context, sources[i]); if((voice=GetSourceVoice(source, context)) != NULL) - { ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); - } if(GetSourceState(source, voice) == AL_PLAYING) + { ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release); + SendStateChangeEvent(context, source->id, AL_PAUSED); + } } ALCdevice_Unlock(device); @@ -2624,16 +2663,20 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) ALCdevice_Lock(device); for(i = 0;i < n;i++) { + ALenum oldstate; source = LookupSource(context, sources[i]); if((voice=GetSourceVoice(source, context)) != NULL) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); + voice = NULL; } - if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + oldstate = GetSourceState(source, voice); + if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) + { ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + SendStateChangeEvent(context, source->id, AL_STOPPED); + } source->OffsetType = AL_NONE; source->Offset = 0.0; } @@ -2677,11 +2720,13 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) { ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, false, almemory_order_release); - while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) - althrd_yield(); + voice = NULL; } - if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL) + if(GetSourceState(source, voice) != AL_INITIAL) + { ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed); + SendStateChangeEvent(context, source->id, AL_INITIAL); + } source->OffsetType = AL_NONE; source->Offset = 0.0; } -- cgit v1.2.3 From c7456affd541b7aef9ff252da51031e671c30734 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Feb 2018 09:44:52 -0800 Subject: Don't make the source state atomic --- OpenAL32/Include/alSource.h | 2 +- OpenAL32/alSource.c | 39 ++++++++++++++++----------------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 277cf7f2..5b9d66dc 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -92,7 +92,7 @@ typedef struct ALsource { ALint SourceType; /** Source state (initial, playing, paused, or stopped) */ - ATOMIC(ALenum) state; + ALenum state; /** Source Buffer Queue head. */ ALbufferlistitem *queue; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index bb3a62c3..d9a9da95 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -201,10 +201,7 @@ static inline ALvoice *GetSourceVoice(ALsource *source, ALCcontext *context) * not sync with the mixer voice. */ static inline bool IsPlayingOrPaused(ALsource *source) -{ - ALenum state = ATOMIC_LOAD(&source->state, almemory_order_acquire); - return state == AL_PLAYING || state == AL_PAUSED; -} +{ return source->state == AL_PLAYING || source->state == AL_PAUSED; } /** * Returns an updated source state using the matching voice's status (or lack @@ -212,15 +209,9 @@ static inline bool IsPlayingOrPaused(ALsource *source) */ static inline ALenum GetSourceState(ALsource *source, ALvoice *voice) { - if(!voice) - { - ALenum state = AL_PLAYING; - if(ATOMIC_COMPARE_EXCHANGE_STRONG(&source->state, &state, AL_STOPPED, - almemory_order_acq_rel, almemory_order_acquire)) - return AL_STOPPED; - return state; - } - return ATOMIC_LOAD(&source->state, almemory_order_acquire); + if(!voice && source->state == AL_PLAYING) + source->state = AL_STOPPED; + return source->state; } /** @@ -1439,7 +1430,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p if((voice=GetSourceVoice(Source, Context)) != NULL) Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); - else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL) + else if(Source->state == AL_INITIAL) Current = BufferList; while(BufferList && BufferList != Current) @@ -2431,9 +2422,9 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { source = LookupSource(context, sources[i]); - ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; + source->state = AL_STOPPED; } ALCdevice_Unlock(device); goto done; @@ -2484,11 +2475,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) * there's no need to look up its voice and clear the source. */ ALenum oldstate = GetSourceState(source, NULL); - ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); source->OffsetType = AL_NONE; source->Offset = 0.0; if(oldstate != AL_STOPPED) + { + source->state = AL_STOPPED; SendStateChangeEvent(context, source->id, AL_STOPPED); + } continue; } @@ -2507,7 +2500,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) assert(voice != NULL); /* A source that's paused simply resumes. */ ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + source->state = AL_PLAYING; SendStateChangeEvent(context, source->id, AL_PLAYING); continue; @@ -2579,7 +2572,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->Source, source, almemory_order_relaxed); ATOMIC_STORE(&voice->Playing, true, almemory_order_release); - ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release); + source->state = AL_PLAYING; source->VoiceIdx = vidx; SendStateChangeEvent(context, source->id, AL_PLAYING); @@ -2624,7 +2617,7 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->Playing, false, almemory_order_release); if(GetSourceState(source, voice) == AL_PLAYING) { - ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release); + source->state = AL_PAUSED; SendStateChangeEvent(context, source->id, AL_PAUSED); } } @@ -2674,7 +2667,7 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) oldstate = GetSourceState(source, voice); if(oldstate != AL_INITIAL && oldstate != AL_STOPPED) { - ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed); + source->state = AL_STOPPED; SendStateChangeEvent(context, source->id, AL_STOPPED); } source->OffsetType = AL_NONE; @@ -2724,7 +2717,7 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) } if(GetSourceState(source, voice) != AL_INITIAL) { - ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed); + source->state = AL_INITIAL; SendStateChangeEvent(context, source->id, AL_INITIAL); } source->OffsetType = AL_NONE; @@ -2896,7 +2889,7 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint Current = NULL; if((voice=GetSourceVoice(source, context)) != NULL) Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); - else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL) + else if(source->state == AL_INITIAL) Current = OldTail; if(OldTail != Current && OldTail->num_buffers == 1) { @@ -3005,7 +2998,7 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->Offset = 0.0; Source->OffsetType = AL_NONE; Source->SourceType = AL_UNDETERMINED; - ATOMIC_INIT(&Source->state, AL_INITIAL); + Source->state = AL_INITIAL; Source->queue = NULL; -- cgit v1.2.3 From 455763aa9a1e46470ffb2baf1ecb12e7276f8fb2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Feb 2018 09:51:07 -0800 Subject: Count all buffers in a list item for processed and queued --- Alc/mixer.c | 2 +- OpenAL32/alSource.c | 85 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index eb4568b2..4946cb7b 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -749,7 +749,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(CompLen > DataPosInt) break; - buffers_done++; + buffers_done += BufferListItem->num_buffers; BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index d9a9da95..b3cf9e3e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1407,7 +1407,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p { ALsizei count = 0; do { - ++count; + count += BufferList->num_buffers; BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } while(BufferList != NULL); *values = count; @@ -1429,13 +1429,13 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALvoice *voice; if((voice=GetSourceVoice(Source, Context)) != NULL) - Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); else if(Source->state == AL_INITIAL) Current = BufferList; while(BufferList && BufferList != Current) { - played++; + played += BufferList->num_buffers; BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, almemory_order_relaxed); } @@ -2860,11 +2860,10 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint { ALCcontext *context; ALsource *source; - ALbufferlistitem *OldHead; - ALbufferlistitem *OldTail; + ALbufferlistitem *BufferList; ALbufferlistitem *Current; ALvoice *voice; - ALsizei i = 0; + ALsizei i; context = GetContextRef(); if(!context) return; @@ -2884,44 +2883,62 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing from a non-streaming source %u", src); - /* Find the new buffer queue head */ - OldTail = source->queue; + /* Make sure enough buffers have been processed to unqueue. */ + BufferList = source->queue; Current = NULL; if((voice=GetSourceVoice(source, context)) != NULL) - Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); else if(source->state == AL_INITIAL) - Current = OldTail; - if(OldTail != Current && OldTail->num_buffers == 1) - { - for(i = 1;i < nb;i++) - { - ALbufferlistitem *next = ATOMIC_LOAD(&OldTail->next, almemory_order_relaxed); - if(!next || next == Current || next->num_buffers != 1) break; - OldTail = next; - } - } - if(i != nb) + Current = BufferList; + if(BufferList == Current) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); - /* Swap it, and cut the new head from the old. */ - OldHead = source->queue; - source->queue = ATOMIC_EXCHANGE_PTR(&OldTail->next, NULL, almemory_order_acq_rel); - - while(OldHead != NULL) + i = BufferList->num_buffers; + while(i < nb) { - ALbufferlistitem *next = ATOMIC_LOAD(&OldHead->next, almemory_order_relaxed); - ALbuffer *buffer = OldHead->buffers[0]; + /* If the next bufferlist to check is NULL or is the current one, it's + * trying to unqueue pending buffers. + */ + ALbufferlistitem *next = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + if(!next || next == Current) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Unqueueing pending buffers"); + BufferList = next; - if(!buffer) - *(buffers++) = 0; - else + i += BufferList->num_buffers; + } + + while(nb > 0) + { + ALbufferlistitem *head = source->queue; + ALbufferlistitem *next = ATOMIC_LOAD(&head->next, almemory_order_relaxed); + for(i = 0;i < head->num_buffers && nb > 0;i++,nb--) { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); + ALbuffer *buffer = head->buffers[i]; + if(!buffer) + *(buffers++) = 0; + else + { + *(buffers++) = buffer->id; + DecrementRef(&buffer->ref); + } + } + if(i < head->num_buffers) + { + /* This head has some buffers left over, so move them to the front + * and update the count. + */ + ALsizei j = 0; + while(i < head->num_buffers) + head->buffers[j++] = head->buffers[i++]; + head->num_buffers = j; + break; } - al_free(OldHead); - OldHead = next; + /* Otherwise, free this item and set the source queue head to the next + * one. + */ + al_free(head); + source->queue = next; } done: -- cgit v1.2.3 From 654a45833acb4ba3eb6c71906346fcd60034cb41 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Feb 2018 10:05:25 -0800 Subject: Only send one buffer completed event per update The 'param' callback parameter indicates the number of buffers that were completed. --- Alc/mixer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Alc/mixer.c b/Alc/mixer.c index 4946cb7b..96a5335b 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -774,11 +774,9 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) { - do { - SendAsyncEvent(Context, EventType_BufferCompleted, - AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, 0, "Buffer completed" - ); - } while(--buffers_done > 0); + SendAsyncEvent(Context, EventType_BufferCompleted, + AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" + ); alsem_post(&Context->EventSem); } -- cgit v1.2.3 From d25398d2c7efb02a9b8e630b15be3a7ab2578aa8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Feb 2018 13:14:14 -0800 Subject: Avoid using static inline in headers --- Alc/helpers.c | 10 ++++++++++ OpenAL32/Include/alMain.h | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 45e137fd..6de1fdc3 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -121,6 +121,16 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x extern inline ALuint NextPowerOf2(ALuint value); extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); +#ifndef __GNUC__ +#if defined(HAVE_BITSCANFORWARD64_INTRINSIC) +extern inline int msvc64_ctz64(ALuint64 v); +#elif defined(HAVE_BITSCANFORWARD_INTRINSIC) +extern inline int msvc_ctz64(ALuint64 v); +#else +extern inline int fallback_popcnt64(ALuint64 v); +extern inline int fallback_ctz64(ALuint64 value); +#endif +#endif int CPUCapFlags = 0; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 8c2615cf..1726cb37 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -99,7 +99,7 @@ typedef ALuint64SOFT ALuint64; #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) -static inline int msvc64_ctz64(ALuint64 v) +inline int msvc64_ctz64(ALuint64 v) { unsigned long idx = 64; _BitScanForward64(&idx, v); @@ -109,7 +109,7 @@ static inline int msvc64_ctz64(ALuint64 v) #elif defined(HAVE_BITSCANFORWARD_INTRINSIC) -static inline int msvc_ctz64(ALuint64 v) +inline int msvc_ctz64(ALuint64 v) { unsigned long idx = 64; if(!_BitScanForward(&idx, v&0xffffffff)) @@ -130,7 +130,7 @@ static inline int msvc_ctz64(ALuint64 v) * as the ntz2 variant. These likely aren't the most efficient methods, but * they're good enough if the GCC or MSVC intrinsics aren't available. */ -static inline int fallback_popcnt64(ALuint64 v) +inline int fallback_popcnt64(ALuint64 v) { v = v - ((v >> 1) & U64(0x5555555555555555)); v = (v & U64(0x3333333333333333)) + ((v >> 2) & U64(0x3333333333333333)); @@ -138,7 +138,7 @@ static inline int fallback_popcnt64(ALuint64 v) return (int)((v * U64(0x0101010101010101)) >> 56); } -static inline int fallback_ctz64(ALuint64 value) +inline int fallback_ctz64(ALuint64 value) { return fallback_popcnt64(~value & (value - 1)); } -- cgit v1.2.3 From a211c2f5e4d14678a77ab11d5d1879b2f442fe4c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Feb 2018 19:37:12 -0800 Subject: Avoid AL prefix on internal effect state factory types Also avoid using the generic V/V0 macros for them --- Alc/effects/chorus.c | 32 ++++++++++++++--------------- Alc/effects/compressor.c | 16 +++++++-------- Alc/effects/dedicated.c | 16 +++++++-------- Alc/effects/distortion.c | 16 +++++++-------- Alc/effects/echo.c | 16 +++++++-------- Alc/effects/equalizer.c | 16 +++++++-------- Alc/effects/modulator.c | 16 +++++++-------- Alc/effects/null.c | 18 ++++++++--------- Alc/effects/reverb.c | 16 +++++++-------- OpenAL32/Include/alAuxEffectSlot.h | 41 +++++++++++++++++++------------------- OpenAL32/alAuxEffectSlot.c | 38 +++++++++++++++++------------------ 11 files changed, 121 insertions(+), 120 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 666933a8..4f8c7ce3 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -285,11 +285,11 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c } -typedef struct ALchorusStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALchorusStateFactory; +typedef struct ChorusStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} ChorusStateFactory; -static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory)) +static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory)) { ALchorusState *state; @@ -299,14 +299,14 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory); -ALeffectStateFactory *ALchorusStateFactory_getFactory(void) +EffectStateFactory *ChorusStateFactory_getFactory(void) { - static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } }; + static ChorusStateFactory ChorusFactory = { { GET_VTABLE2(ChorusStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &ChorusFactory); + return STATIC_CAST(EffectStateFactory, &ChorusFactory); } @@ -422,11 +422,11 @@ DEFINE_ALEFFECT_VTABLE(ALchorus); /* Flanger is basically a chorus with a really short delay. They can both use * the same processing functions, so piggyback flanger on the chorus functions. */ -typedef struct ALflangerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALflangerStateFactory; +typedef struct FlangerStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} FlangerStateFactory; -ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory)) +ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory)) { ALchorusState *state; @@ -436,13 +436,13 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory); -ALeffectStateFactory *ALflangerStateFactory_getFactory(void) +EffectStateFactory *FlangerStateFactory_getFactory(void) { - static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } }; + static FlangerStateFactory FlangerFactory = { { GET_VTABLE2(FlangerStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &FlangerFactory); + return STATIC_CAST(EffectStateFactory, &FlangerFactory); } diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index bb9be8b9..4ec28f9a 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -179,11 +179,11 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample } -typedef struct ALcompressorStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALcompressorStateFactory; +typedef struct CompressorStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} CompressorStateFactory; -static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory)) +static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory)) { ALcompressorState *state; @@ -193,13 +193,13 @@ static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory * return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory); -ALeffectStateFactory *ALcompressorStateFactory_getFactory(void) +EffectStateFactory *CompressorStateFactory_getFactory(void) { - static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } }; + static CompressorStateFactory CompressorFactory = { { GET_VTABLE2(CompressorStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &CompressorFactory); + return STATIC_CAST(EffectStateFactory, &CompressorFactory); } diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 70a97ea9..b9dd7db3 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -114,11 +114,11 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesT } -typedef struct ALdedicatedStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALdedicatedStateFactory; +typedef struct DedicatedStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} DedicatedStateFactory; -ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory)) +ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory)) { ALdedicatedState *state; @@ -128,14 +128,14 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory); -ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void) +EffectStateFactory *DedicatedStateFactory_getFactory(void) { - static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } }; + static DedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(DedicatedStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory); + return STATIC_CAST(EffectStateFactory, &DedicatedFactory); } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 6ee89594..b112032c 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -176,11 +176,11 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample } -typedef struct ALdistortionStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALdistortionStateFactory; +typedef struct DistortionStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} DistortionStateFactory; -static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory)) +static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory)) { ALdistortionState *state; @@ -190,14 +190,14 @@ static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory * return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory); -ALeffectStateFactory *ALdistortionStateFactory_getFactory(void) +EffectStateFactory *DistortionStateFactory_getFactory(void) { - static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } }; + static DistortionStateFactory DistortionFactory = { { GET_VTABLE2(DistortionStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &DistortionFactory); + return STATIC_CAST(EffectStateFactory, &DistortionFactory); } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index d8cbd214..34010c47 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -206,11 +206,11 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const } -typedef struct ALechoStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALechoStateFactory; +typedef struct EchoStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} EchoStateFactory; -ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory)) +ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory)) { ALechoState *state; @@ -220,13 +220,13 @@ ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory)) return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory); -ALeffectStateFactory *ALechoStateFactory_getFactory(void) +EffectStateFactory *EchoStateFactory_getFactory(void) { - static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } }; + static EchoStateFactory EchoFactory = { { GET_VTABLE2(EchoStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &EchoFactory); + return STATIC_CAST(EffectStateFactory, &EchoFactory); } diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 8c2b31e2..22db5d54 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -196,11 +196,11 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesT } -typedef struct ALequalizerStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALequalizerStateFactory; +typedef struct EqualizerStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} EqualizerStateFactory; -ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory)) +ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory)) { ALequalizerState *state; @@ -210,13 +210,13 @@ ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(fa return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory); -ALeffectStateFactory *ALequalizerStateFactory_getFactory(void) +EffectStateFactory *EqualizerStateFactory_getFactory(void) { - static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } }; + static EqualizerStateFactory EqualizerFactory = { { GET_VTABLE2(EqualizerStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory); + return STATIC_CAST(EffectStateFactory, &EqualizerFactory); } diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index ed0851d6..74a0d0c5 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -186,11 +186,11 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT } -typedef struct ALmodulatorStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALmodulatorStateFactory; +typedef struct ModulatorStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} ModulatorStateFactory; -static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory)) +static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory)) { ALmodulatorState *state; @@ -200,13 +200,13 @@ static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UN return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory); -ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void) +EffectStateFactory *ModulatorStateFactory_getFactory(void) { - static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } }; + static ModulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ModulatorStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory); + return STATIC_CAST(EffectStateFactory, &ModulatorFactory); } diff --git a/Alc/effects/null.c b/Alc/effects/null.c index f9583011..e57359e3 100644 --- a/Alc/effects/null.c +++ b/Alc/effects/null.c @@ -85,12 +85,12 @@ static void ALnullState_Delete(void *ptr) } -typedef struct ALnullStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALnullStateFactory; +typedef struct NullStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} NullStateFactory; /* Creates ALeffectState objects of the appropriate type. */ -ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory)) +ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory)) { ALnullState *state; @@ -100,13 +100,13 @@ ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory)) return STATIC_CAST(ALeffectState, state); } -/* Define the ALeffectStateFactory vtable for this type. */ -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory); +/* Define the EffectStateFactory vtable for this type. */ +DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory); -ALeffectStateFactory *ALnullStateFactory_getFactory(void) +EffectStateFactory *NullStateFactory_getFactory(void) { - static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &NullFactory); + static NullStateFactory NullFactory = { { GET_VTABLE2(NullStateFactory, EffectStateFactory) } }; + return STATIC_CAST(EffectStateFactory, &NullFactory); } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f6499bb7..f9650c8b 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1691,11 +1691,11 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c } -typedef struct ALreverbStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALreverbStateFactory; +typedef struct ReverbStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} ReverbStateFactory; -static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory)) +static ALeffectState *ReverbStateFactory_create(ReverbStateFactory* UNUSED(factory)) { ALreverbState *state; @@ -1705,13 +1705,13 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f return STATIC_CAST(ALeffectState, state); } -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory); +DEFINE_EFFECTSTATEFACTORY_VTABLE(ReverbStateFactory); -ALeffectStateFactory *ALreverbStateFactory_getFactory(void) +EffectStateFactory *ReverbStateFactory_getFactory(void) { - static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } }; + static ReverbStateFactory ReverbFactory = { { GET_VTABLE2(ReverbStateFactory, EffectStateFactory) } }; - return STATIC_CAST(ALeffectStateFactory, &ReverbFactory); + return STATIC_CAST(EffectStateFactory, &ReverbFactory); } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index aa3a0118..29de7a14 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -59,21 +59,22 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \ } -struct ALeffectStateFactoryVtable; +struct EeffectStateFactoryVtable; -typedef struct ALeffectStateFactory { - const struct ALeffectStateFactoryVtable *vtbl; -} ALeffectStateFactory; +typedef struct EffectStateFactory { + const struct EffectStateFactoryVtable *vtab; +} EffectStateFactory; -struct ALeffectStateFactoryVtable { - ALeffectState *(*const create)(ALeffectStateFactory *factory); +struct EffectStateFactoryVtable { + ALeffectState *(*const create)(EffectStateFactory *factory); }; +#define EffectStateFactory_create(x) ((x)->vtab->create((x))) -#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \ -DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \ +#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \ +DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \ \ -static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \ - T##_ALeffectStateFactory_create, \ +static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \ + T##_EffectStateFactory_create, \ } @@ -156,17 +157,17 @@ void UpdateAllEffectSlotProps(ALCcontext *context); ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); -ALeffectStateFactory *ALnullStateFactory_getFactory(void); -ALeffectStateFactory *ALreverbStateFactory_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); +EffectStateFactory *NullStateFactory_getFactory(void); +EffectStateFactory *ReverbStateFactory_getFactory(void); +EffectStateFactory *ChorusStateFactory_getFactory(void); +EffectStateFactory *CompressorStateFactory_getFactory(void); +EffectStateFactory *DistortionStateFactory_getFactory(void); +EffectStateFactory *EchoStateFactory_getFactory(void); +EffectStateFactory *EqualizerStateFactory_getFactory(void); +EffectStateFactory *FlangerStateFactory_getFactory(void); +EffectStateFactory *ModulatorStateFactory_getFactory(void); -ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void); +EffectStateFactory *DedicatedStateFactory_getFactory(void); ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect); diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index d5c39051..04edcc09 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -43,23 +43,23 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon static const struct { ALenum Type; - ALeffectStateFactory* (*GetFactory)(void); + EffectStateFactory* (*GetFactory)(void); } FactoryList[] = { - { AL_EFFECT_NULL, ALnullStateFactory_getFactory }, - { AL_EFFECT_EAXREVERB, ALreverbStateFactory_getFactory }, - { AL_EFFECT_REVERB, ALreverbStateFactory_getFactory }, - { AL_EFFECT_CHORUS, ALchorusStateFactory_getFactory }, - { AL_EFFECT_COMPRESSOR, ALcompressorStateFactory_getFactory }, - { AL_EFFECT_DISTORTION, ALdistortionStateFactory_getFactory }, - { AL_EFFECT_ECHO, ALechoStateFactory_getFactory }, - { AL_EFFECT_EQUALIZER, ALequalizerStateFactory_getFactory }, - { AL_EFFECT_FLANGER, ALflangerStateFactory_getFactory }, - { AL_EFFECT_RING_MODULATOR, ALmodulatorStateFactory_getFactory }, - { AL_EFFECT_DEDICATED_DIALOGUE, ALdedicatedStateFactory_getFactory }, - { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, ALdedicatedStateFactory_getFactory } + { AL_EFFECT_NULL, NullStateFactory_getFactory }, + { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_REVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, + { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, + { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, + { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, + { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, + { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, + { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } }; -static inline ALeffectStateFactory *getFactoryByType(ALenum type) +static inline EffectStateFactory *getFactoryByType(ALenum type) { size_t i; for(i = 0;i < COUNTOF(FactoryList);i++) @@ -498,7 +498,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect if(newtype != EffectSlot->Effect.Type) { - ALeffectStateFactory *factory; + EffectStateFactory *factory; factory = getFactoryByType(newtype); if(!factory) @@ -506,7 +506,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } - State = V0(factory,create)(); + State = EffectStateFactory_create(factory); if(!State) return AL_OUT_OF_MEMORY; START_MIXER_MODE(); @@ -659,13 +659,13 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon ALenum InitEffectSlot(ALeffectslot *slot) { - ALeffectStateFactory *factory; + EffectStateFactory *factory; slot->Effect.Type = AL_EFFECT_NULL; factory = getFactoryByType(AL_EFFECT_NULL); - if(!(slot->Effect.State=V0(factory,create)())) - return AL_OUT_OF_MEMORY; + slot->Effect.State = EffectStateFactory_create(factory); + if(!slot->Effect.State) return AL_OUT_OF_MEMORY; slot->Gain = 1.0; slot->AuxSendAuto = AL_TRUE; -- cgit v1.2.3 From 812cb6261742689612dfd7fec4dce3d6322dd658 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Feb 2018 20:39:53 -0800 Subject: Fix a comment regarding the effect slot channel scaling --- OpenAL32/Include/alAuxEffectSlot.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 29de7a14..060ab533 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -139,9 +139,9 @@ typedef struct ALeffectslot { BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS]; /* Wet buffer configuration is ACN channel order with N3D scaling: * * Channel 0 is the unattenuated mono signal. - * * Channel 1 is OpenAL -X - * * Channel 2 is OpenAL Y - * * Channel 3 is OpenAL -Z + * * Channel 1 is OpenAL -X * sqrt(3) + * * Channel 2 is OpenAL Y * sqrt(3) + * * Channel 3 is OpenAL -Z * sqrt(3) * Consequently, effects that only want to work with mono input can use * channel 0 by itself. Effects that want multichannel can process the * ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for -- cgit v1.2.3 From abc6e37e6ec162007c90f672b1650898bd3f330d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Feb 2018 20:59:41 -0800 Subject: Apply distance attenuation to reverb zones in almultireverb --- examples/almultireverb.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 5adab269..9c97e334 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -500,16 +500,20 @@ int main(int argc, char **argv) other_dir[1] = local_norm[1] / -2.0f; other_dir[2] = local_norm[2] / -2.0f; + alEffectf(effects[0], AL_EAXREVERB_GAIN, reverb0.flGain); alEffectfv(effects[0], AL_EAXREVERB_REFLECTIONS_PAN, this_dir); alEffectfv(effects[0], AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + alEffectf(effects[1], AL_EAXREVERB_GAIN, reverb1.flGain); alEffectfv(effects[1], AL_EAXREVERB_REFLECTIONS_PAN, other_dir); alEffectfv(effects[1], AL_EAXREVERB_LATE_REVERB_PAN, other_dir); } else { + const EFXEAXREVERBPROPERTIES *other_reverb; + const EFXEAXREVERBPROPERTIES *this_reverb; ALuint other_effect, this_effect; - ALfloat spread; + ALfloat spread, attn; /* Normalize the direction to the portal. */ local_dir[0] /= dist; @@ -521,6 +525,12 @@ int main(int argc, char **argv) */ local_radius = portal_radius * fabsf(dot_product(local_dir, local_norm)); + /* Calculate distance attenuation for the other zone, using the + * standard inverse distance model with the radius as a reference. + */ + attn = local_radius / dist; + if(attn > 1.0f) attn = 1.0f; + /* Calculate the 'spread' of the portal, which is the amount of * coverage the other zone has around the listener. */ @@ -534,12 +544,16 @@ int main(int argc, char **argv) /* We're in front of the portal, so we're in Zone 0. */ this_effect = effects[0]; other_effect = effects[1]; + this_reverb = &reverb0; + other_reverb = &reverb1; } else { /* We're behind the portal, so we're in Zone 1. */ this_effect = effects[1]; other_effect = effects[0]; + this_reverb = &reverb1; + other_reverb = &reverb0; } /* Scale the other zone's panning vector down as the portal's @@ -555,10 +569,12 @@ int main(int argc, char **argv) this_dir[1] = local_dir[1] * -spread; this_dir[2] = local_dir[2] * -spread; - /* Now set the effects' panning vectors. */ + /* Now set the effects' panning vectors and distance attenuation. */ + alEffectf(this_effect, AL_EAXREVERB_GAIN, this_reverb->flGain); alEffectfv(this_effect, AL_EAXREVERB_REFLECTIONS_PAN, this_dir); alEffectfv(this_effect, AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + alEffectf(other_effect, AL_EAXREVERB_GAIN, other_reverb->flGain * attn); alEffectfv(other_effect, AL_EAXREVERB_REFLECTIONS_PAN, other_dir); alEffectfv(other_effect, AL_EAXREVERB_LATE_REVERB_PAN, other_dir); } -- cgit v1.2.3 From 0d91d63cf32357853587be5227be3c1319fc2fba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Feb 2018 21:04:45 -0800 Subject: Fix use of argv[0] as the program name after incrementing --- examples/almultireverb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 9c97e334..6f583a50 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -278,10 +278,7 @@ int main(int argc, char **argv) } if(argc < 1) { - fprintf(stderr, "Usage: %s [-device ] [options] \n\n" - "Options:\n" - "\t-nodirect\tSilence direct path output (easier to hear reverb).\n\n", - argv[0]); + fprintf(stderr, "No filename spacified.\n"); CloseAL(); return 1; } -- cgit v1.2.3 From 4b85104c4f7ba4b78a36931672124f69f4f17711 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Mar 2018 16:16:37 -0800 Subject: Apply the limiter, distance comp, and others even with no output buffer --- Alc/ALu.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index b130677d..3fd561ae 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1845,31 +1845,32 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) if(LIKELY(device->PostProcess)) device->PostProcess(device, SamplesToDo); - if(OutBuffer) + if(device->Stablizer) { - ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; - ALsizei Channels = device->RealOut.NumChannels; + int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); + int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); + int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); + assert(lidx >= 0 && ridx >= 0 && cidx >= 0); - if(device->Stablizer) - { - int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); - int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - int cidx = GetChannelIdxByName(&device->RealOut, FrontCenter); - assert(lidx >= 0 && ridx >= 0 && cidx >= 0); + ApplyStablizer(device->Stablizer, device->RealOut.Buffer, lidx, ridx, cidx, + SamplesToDo, device->RealOut.NumChannels); + } - ApplyStablizer(device->Stablizer, Buffer, lidx, ridx, cidx, - SamplesToDo, Channels); - } + ApplyDistanceComp(device->RealOut.Buffer, device->ChannelDelay, device->TempBuffer[0], + SamplesToDo, device->RealOut.NumChannels); - ApplyDistanceComp(Buffer, device->ChannelDelay, device->TempBuffer[0], - SamplesToDo, Channels); + if(device->Limiter) + ApplyCompression(device->Limiter, device->RealOut.NumChannels, SamplesToDo, + device->RealOut.Buffer); - if(device->Limiter) - ApplyCompression(device->Limiter, Channels, SamplesToDo, Buffer); + if(device->DitherDepth > 0.0f) + ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, + SamplesToDo, device->RealOut.NumChannels); - if(device->DitherDepth > 0.0f) - ApplyDither(Buffer, &device->DitherSeed, device->DitherDepth, SamplesToDo, - Channels); + if(OutBuffer) + { + ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; + ALsizei Channels = device->RealOut.NumChannels; switch(device->FmtType) { -- cgit v1.2.3 From cba37819d1e68ff6473d0e10b42ac9465943d5cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Mar 2018 21:19:49 -0800 Subject: Add missing include --- examples/almultireverb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 6f583a50..2f820914 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -31,6 +31,7 @@ #include #include +#include #include -- cgit v1.2.3 From 6f62fed65c4dcdf999a612e258cca59a22355f3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 1 Mar 2018 21:23:13 -0800 Subject: Add an option to limit the write size of the ringbuffer --- Alc/backends/alsa.c | 3 ++- Alc/backends/coreaudio.c | 2 +- Alc/backends/dsound.c | 2 +- Alc/backends/jack.c | 6 ++++-- Alc/backends/mmdevapi.c | 3 ++- Alc/backends/opensl.c | 16 +++++----------- Alc/backends/oss.c | 2 +- Alc/backends/portaudio.c | 2 +- Alc/backends/winmm.c | 2 +- Alc/ringbuffer.c | 32 +++++++++++++++++--------------- Alc/ringbuffer.h | 2 +- OpenAL32/event.c | 2 +- 12 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index c75749de..d0f0e24e 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -1124,7 +1124,8 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) { self->ring = ll_ringbuffer_create( device->UpdateSize*device->NumUpdates + 1, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + false ); if(!self->ring) { diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 3db0d702..caa01167 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -664,7 +664,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar self->ring = ll_ringbuffer_create( device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1, - self->frameSize + self->frameSize, false ); if(!self->ring) goto error; diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 0040a840..4c52e0f8 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -857,7 +857,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi if(SUCCEEDED(hr)) { self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, - InputType.Format.nBlockAlign); + InputType.Format.nBlockAlign, false); if(self->Ring == NULL) hr = DSERR_OUTOFMEMORY; } diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index e6f4b435..003877a4 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -236,7 +236,8 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + true ); if(!self->Ring) { @@ -437,7 +438,8 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(bufsize, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + true ); if(!self->Ring) { diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 5f1dbba8..34dcf468 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1813,7 +1813,8 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len); ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder) + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + false ); if(!self->Ring) { diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index b20d7841..d930526d 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -239,7 +239,6 @@ static int ALCopenslPlayback_mixerProc(void *arg) ll_ringbuffer_data_t data[2]; SLPlayItf player; SLresult result; - size_t padding; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); @@ -260,18 +259,13 @@ static int ALCopenslPlayback_mixerProc(void *arg) return 1; } - /* NOTE: The ringbuffer will be larger than the desired buffer metrics. - * Calculate the amount of extra space so we know how much to keep unused. - */ - padding = ll_ringbuffer_write_space(self->mRing) - device->NumUpdates; - ALCopenslPlayback_lock(self); while(!ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { size_t todo, len0, len1; - if(ll_ringbuffer_write_space(self->mRing) <= padding) + if(ll_ringbuffer_write_space(self->mRing) == 0) { SLuint32 state = 0; @@ -288,7 +282,7 @@ static int ALCopenslPlayback_mixerProc(void *arg) break; } - if(ll_ringbuffer_write_space(self->mRing) <= padding) + if(ll_ringbuffer_write_space(self->mRing) == 0) { ALCopenslPlayback_unlock(self); alsem_wait(&self->mSem); @@ -298,7 +292,7 @@ static int ALCopenslPlayback_mixerProc(void *arg) } ll_ringbuffer_get_write_vector(self->mRing, data); - todo = data[0].len+data[1].len - padding; + todo = data[0].len+data[1].len; len0 = minu(todo, data[0].len); len1 = minu(todo-len0, data[1].len); @@ -577,7 +571,7 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) * buffer will not be writeable, and we only write in period-sized chunks. */ self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, - self->mFrameSize*device->UpdateSize); + self->mFrameSize*device->UpdateSize, true); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -854,7 +848,7 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, - device->UpdateSize * self->mFrameSize); + device->UpdateSize * self->mFrameSize, false); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index faf3ee99..61d25476 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -729,7 +729,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize); + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize, false); if(!self->ring) { ERR("Ring buffer create failed\n"); diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index fdc8a2a5..9b0d3487 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -395,7 +395,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - self->ring = ll_ringbuffer_create(samples, frame_size); + self->ring = ll_ringbuffer_create(samples, frame_size, false); if(self->ring == NULL) return ALC_INVALID_VALUE; self->params.device = -1; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index d6ecd7a9..787ba8e4 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -626,7 +626,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) CapturedDataSize = self->Format.nSamplesPerSec / 10; - self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign); + self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign, false); if(!self->Ring) goto failure; InitRef(&self->WaveBuffersCommitted, 0); diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c index c594331e..02fa857c 100644 --- a/Alc/ringbuffer.c +++ b/Alc/ringbuffer.c @@ -48,7 +48,7 @@ struct ll_ringbuffer { /* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. * The number of elements is rounded up to the next power of two. */ -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) { ll_ringbuffer_t *rb; size_t power_of_two = 0; @@ -73,8 +73,8 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) ATOMIC_INIT(&rb->write_ptr, 0); ATOMIC_INIT(&rb->read_ptr, 0); - rb->size = power_of_two; - rb->size_mask = rb->size - 1; + rb->size = limit_writes ? sz : power_of_two; + rb->size_mask = power_of_two - 1; rb->elem_size = elem_sz; return rb; } @@ -90,7 +90,7 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release); - memset(rb->buf, 0, rb->size*rb->elem_size); + memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); } /* Return the number of elements available for reading. This is the number of @@ -107,7 +107,8 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); - return (r-w-1) & rb->size_mask; + w = (r-w-1) & rb->size_mask; + return (w > rb->size) ? rb->size : w; } /* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. @@ -127,9 +128,9 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; cnt2 = read_ptr + to_read; - if(cnt2 > rb->size) + if(cnt2 > rb->size_mask+1) { - n1 = rb->size - read_ptr; + n1 = rb->size_mask+1 - read_ptr; n2 = cnt2 & rb->size_mask; } else @@ -168,9 +169,9 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask; cnt2 = read_ptr + to_read; - if(cnt2 > rb->size) + if(cnt2 > rb->size_mask+1) { - n1 = rb->size - read_ptr; + n1 = rb->size_mask+1 - read_ptr; n2 = cnt2 & rb->size_mask; } else @@ -206,9 +207,9 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask; cnt2 = write_ptr + to_write; - if(cnt2 > rb->size) + if(cnt2 > rb->size_mask+1) { - n1 = rb->size - write_ptr; + n1 = rb->size_mask+1 - write_ptr; n2 = cnt2 & rb->size_mask; } else @@ -257,12 +258,12 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data free_cnt = (w-r) & rb->size_mask; cnt2 = r + free_cnt; - if(cnt2 > rb->size) + if(cnt2 > rb->size_mask+1) { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ vec[0].buf = (char*)&rb->buf[r*rb->elem_size]; - vec[0].len = rb->size - r; + vec[0].len = rb->size_mask+1 - r; vec[1].buf = (char*)rb->buf; vec[1].len = cnt2 & rb->size_mask; } @@ -290,14 +291,15 @@ void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_dat w &= rb->size_mask; r &= rb->size_mask; free_cnt = (r-w-1) & rb->size_mask; + if(free_cnt > rb->size) free_cnt = rb->size; cnt2 = w + free_cnt; - if(cnt2 > rb->size) + if(cnt2 > rb->size_mask+1) { /* Two part vector: the rest of the buffer after the current write ptr, * plus some from the start of the buffer. */ vec[0].buf = (char*)&rb->buf[w*rb->elem_size]; - vec[0].len = rb->size - w; + vec[0].len = rb->size_mask+1 - w; vec[1].buf = (char*)rb->buf; vec[1].len = cnt2 & rb->size_mask; } diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index f764c20f..c1a7a6fa 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -10,7 +10,7 @@ typedef struct ll_ringbuffer_data { size_t len; } ll_ringbuffer_data_t; -ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz); +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); void ll_ringbuffer_free(ll_ringbuffer_t *rb); void ll_ringbuffer_reset(ll_ringbuffer_t *rb); diff --git a/OpenAL32/event.c b/OpenAL32/event.c index ef36f977..333b7613 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -78,7 +78,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A bool isrunning; almtx_lock(&context->EventThrdLock); if(!context->AsyncEvents) - context->AsyncEvents = ll_ringbuffer_create(64, sizeof(AsyncEvent)); + context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, -- cgit v1.2.3 From 03274a5b95146675c05b5b6a0340f45a7b122c50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Mar 2018 12:46:31 -0800 Subject: Ensure at least the specified ringbuffer size is writable Previously, all but one of the specified size could be written (so for a size of n, only n-1 was guaranteed writable). All users pretty much compensated for this, but it makes more sense to fix it at the source. --- Alc/backends/alsa.c | 2 +- Alc/backends/coreaudio.c | 2 +- Alc/backends/dsound.c | 2 +- Alc/backends/jack.c | 10 +++------- Alc/backends/mmdevapi.c | 2 +- Alc/backends/opensl.c | 12 ++++-------- Alc/backends/oss.c | 2 +- Alc/backends/winmm.c | 2 +- Alc/ringbuffer.c | 34 ++++++++-------------------------- Alc/ringbuffer.h | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 10 files changed, 65 insertions(+), 51 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index d0f0e24e..9fc36582 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -1123,7 +1123,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) if(needring) { self->ring = ll_ringbuffer_create( - device->UpdateSize*device->NumUpdates + 1, + device->UpdateSize*device->NumUpdates, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), false ); diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index caa01167..b2545c47 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -663,7 +663,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar goto error; self->ring = ll_ringbuffer_create( - device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1, + (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates), self->frameSize, false ); if(!self->ring) goto error; diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 4c52e0f8..6bab641c 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -856,7 +856,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL); if(SUCCEEDED(hr)) { - self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, + self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, InputType.Format.nBlockAlign, false); if(self->Ring == NULL) hr = DSERR_OUTOFMEMORY; diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 003877a4..67e3c106 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -229,8 +229,7 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg) bufsize = device->UpdateSize; if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - bufsize += device->UpdateSize; - device->NumUpdates = bufsize / device->UpdateSize; + device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates); @@ -391,9 +390,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) } /* Ignore the requested buffer metrics and just keep one JACK-sized buffer - * ready for when requested. Note that one period's worth of audio in the - * ring buffer will always be left unfilled because one element of the ring - * buffer will not be writeable, and we only write in period-sized chunks. + * ready for when requested. */ device->Frequency = jack_get_sample_rate(self->Client); device->UpdateSize = jack_get_buffer_size(self->Client); @@ -402,8 +399,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self) bufsize = device->UpdateSize; if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize)) bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize); - bufsize += device->UpdateSize; - device->NumUpdates = bufsize / device->UpdateSize; + device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize; /* Force 32-bit float output. */ device->FmtType = DevFmtFloat; diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index 34dcf468..961cba52 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -1810,7 +1810,7 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) return hr; } - buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len); + buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); ll_ringbuffer_free(self->Ring); self->Ring = ll_ringbuffer_create(buffer_len, FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index d930526d..a5ad3b09 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -566,12 +566,8 @@ static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) SLresult result; ll_ringbuffer_free(self->mRing); - /* NOTE: Add an extra update since one period's worth of audio in the ring - * buffer will always be left unfilled because one element of the ring - * buffer will not be writeable, and we only write in period-sized chunks. - */ - self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, - self->mFrameSize*device->UpdateSize, true); + self->mRing = ll_ringbuffer_create(device->NumUpdates, self->mFrameSize*device->UpdateSize, + true); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -847,8 +843,8 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { - self->mRing = ll_ringbuffer_create(device->NumUpdates + 1, - device->UpdateSize * self->mFrameSize, false); + self->mRing = ll_ringbuffer_create(device->NumUpdates, device->UpdateSize*self->mFrameSize, + false); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index 61d25476..c0c98c43 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -729,7 +729,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name) return ALC_INVALID_VALUE; } - self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize, false); + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false); if(!self->ring) { ERR("Ring buffer create failed\n"); diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 787ba8e4..2f4c65df 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -626,7 +626,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) CapturedDataSize = self->Format.nSamplesPerSec / 10; - self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign, false); + self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); if(!self->Ring) goto failure; InitRef(&self->WaveBuffersCommitted, 0); diff --git a/Alc/ringbuffer.c b/Alc/ringbuffer.c index 02fa857c..6c419cf8 100644 --- a/Alc/ringbuffer.c +++ b/Alc/ringbuffer.c @@ -46,8 +46,6 @@ struct ll_ringbuffer { alignas(16) char buf[]; }; -/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. - * The number of elements is rounded up to the next power of two. */ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes) { ll_ringbuffer_t *rb; @@ -55,7 +53,7 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_write if(sz > 0) { - power_of_two = sz - 1; + power_of_two = sz; power_of_two |= power_of_two>>1; power_of_two |= power_of_two>>2; power_of_two |= power_of_two>>4; @@ -79,13 +77,11 @@ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_write return rb; } -/* Free all data associated with the ringbuffer `rb'. */ void ll_ringbuffer_free(ll_ringbuffer_t *rb) { al_free(rb); } -/* Reset the read and write pointers to zero. This is not thread safe. */ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) { ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release); @@ -93,16 +89,14 @@ void ll_ringbuffer_reset(ll_ringbuffer_t *rb) memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size); } -/* Return the number of elements available for reading. This is the number of - * elements in front of the read pointer and behind the write pointer. */ + size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) { size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire); return (w-r) & rb->size_mask; } -/* Return the number of elements available for writing. This is the number of - * elements in front of the write pointer and behind the read pointer. */ + size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) { size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire); @@ -111,8 +105,7 @@ size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) return (w > rb->size) ? rb->size : w; } -/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. - * Returns the actual number of elements copied. */ + size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) { size_t read_ptr; @@ -151,9 +144,6 @@ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) return to_read; } -/* The copying data reader w/o read pointer advance. Copy at most `cnt' - * elements from `rb' to `dest'. Returns the actual number of elements copied. - */ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) { size_t free_cnt; @@ -190,8 +180,6 @@ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) return to_read; } -/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'. - * Returns the actual number of elements copied. */ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) { size_t write_ptr; @@ -230,22 +218,19 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) return to_write; } -/* Advance the read pointer `cnt' places. */ + void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) { ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel); } -/* Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) { ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel); } -/* The non-copying data reader. `vec' is an array of two places. Set the values - * at `vec' to hold the current readable data at `rb'. If the readable data is - * in one segment the second segment has zero length. */ -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec) + +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) { size_t free_cnt; size_t cnt2; @@ -277,10 +262,7 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data } } -/* The non-copying data writer. `vec' is an array of two places. Set the values - * at `vec' to hold the current writeable data at `rb'. If the writeable data - * is in one segment the second segment has zero length. */ -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec) +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]) { size_t free_cnt; size_t cnt2; diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index c1a7a6fa..bcf67374 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -10,20 +10,60 @@ typedef struct ll_ringbuffer_data { size_t len; } ll_ringbuffer_data_t; + +/** + * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. + * The number of elements is rounded up to the next power of two (even if it is + * already a power of two, to ensure the requested amount can be written). + */ ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes); +/** Free all data associated with the ringbuffer `rb'. */ void ll_ringbuffer_free(ll_ringbuffer_t *rb); +/** Reset the read and write pointers to zero. This is not thread safe. */ void ll_ringbuffer_reset(ll_ringbuffer_t *rb); -void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); -void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); +/** + * The non-copying data reader. `vec' is an array of two places. Set the values + * at `vec' to hold the current readable data at `rb'. If the readable data is + * in one segment the second segment has zero length. + */ +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]); +/** + * The non-copying data writer. `vec' is an array of two places. Set the values + * at `vec' to hold the current writeable data at `rb'. If the writeable data + * is in one segment the second segment has zero length. + */ +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]); +/** + * Return the number of elements available for reading. This is the number of + * elements in front of the read pointer and behind the write pointer. + */ +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); +/** + * The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. + * Returns the actual number of elements copied. + */ size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt); +/** + * The copying data reader w/o read pointer advance. Copy at most `cnt' + * elements from `rb' to `dest'. Returns the actual number of elements copied. + */ size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt); +/** Advance the read pointer `cnt' places. */ void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); -size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); +/** + * Return the number of elements available for writing. This is the number of + * elements in front of the write pointer and behind the read pointer. + */ +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); +/** + * The copying data writer. Copy at most `cnt' elements to `rb' from `src'. + * Returns the actual number of elements copied. + */ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); +/** Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); -size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); #endif /* RINGBUFFER_H */ -- cgit v1.2.3 From bd32a682f7476e7bdd8240e0244adff047d99f49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Mar 2018 18:38:59 -0800 Subject: Use atomic variables instead of volatile --- Alc/ALc.c | 90 ++++++++++++++++++++++------------------------- Alc/ALu.c | 4 +-- OpenAL32/Include/alMain.h | 4 +-- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8c743838..3cc50e8c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1222,7 +1222,8 @@ static void alc_cleanup(void) ALCuint num = 0; do { num++; - } while((dev=dev->next) != NULL); + dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); + } while(dev != NULL); ERR("%u device%s not closed\n", num, (num>1)?"s":""); } } @@ -2343,7 +2344,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateAllSourceProps(context); WriteUnlock(&context->PropLock); - context = context->next; + context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); } END_MIXER_MODE(); if(update_failed) @@ -2415,6 +2416,8 @@ static void InitDevice(ALCdevice *device) almtx_init(&device->BackendLock, almtx_plain); device->Backend = NULL; + + ATOMIC_INIT(&device->next, NULL); } /* FreeDevice @@ -2533,7 +2536,7 @@ static ALCboolean VerifyDevice(ALCdevice **device) UnlockLists(); return ALC_TRUE; } - tmpDevice = tmpDevice->next; + tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); } UnlockLists(); @@ -2787,19 +2790,17 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) V0(device->Backend,lock)(); origctx = context; - newhead = context->next; + newhead = ATOMIC_LOAD(&context->next, almemory_order_relaxed); if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&device->ContextList, &origctx, newhead)) { - ALCcontext *volatile*list = &origctx->next; - while(*list) - { - if(*list == context) - { - *list = (*list)->next; - break; - } - list = &(*list)->next; - } + ALCcontext *list; + do { + /* origctx is what the desired context failed to match. Try + * swapping out the next one in the list. + */ + list = origctx; + origctx = context; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origctx, newhead)); } else ret = !!newhead; @@ -2851,9 +2852,9 @@ static ALCboolean VerifyContext(ALCcontext **context) UnlockLists(); return ALC_TRUE; } - ctx = ctx->next; + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); } - dev = dev->next; + dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); } UnlockLists(); @@ -3794,6 +3795,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALContext->MaxVoices = 0; ATOMIC_INIT(&ALContext->ActiveAuxSlots, NULL); ALContext->Device = device; + ATOMIC_INIT(&ALContext->next, NULL); if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { @@ -3847,7 +3849,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin { ALCcontext *head = ATOMIC_LOAD_SEQ(&device->ContextList); do { - ALContext->next = head; + ATOMIC_STORE(&ALContext->next, head, almemory_order_relaxed); } while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&device->ContextList, &head, ALContext) == 0); } @@ -4185,7 +4187,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { - device->next = head; + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } @@ -4199,7 +4201,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) */ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) { - ALCdevice *iter, *origdev; + ALCdevice *iter, *origdev, *nextdev; ALCcontext *ctx; LockLists(); @@ -4207,7 +4209,8 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) do { if(iter == device) break; - } while((iter=iter->next) != NULL); + iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + } while(iter != NULL); if(!iter || iter->Type == Capture) { alcSetError(iter, ALC_INVALID_DEVICE); @@ -4217,25 +4220,21 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) almtx_lock(&device->BackendLock); origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, device->next)) + nextdev = ATOMIC_LOAD(&device->next, almemory_order_relaxed); + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) { - ALCdevice *volatile*list = &origdev->next; - while(*list) - { - if(*list == device) - { - *list = (*list)->next; - break; - } - list = &(*list)->next; - } + ALCdevice *list; + do { + list = origdev; + origdev = device; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } UnlockLists(); ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx != NULL) { - ALCcontext *next = ctx->next; + ALCcontext *next = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); WARN("Releasing context %p\n", ctx); ReleaseContext(ctx, device); ctx = next; @@ -4332,7 +4331,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { - device->next = head; + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } @@ -4342,14 +4341,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { - ALCdevice *iter, *origdev; + ALCdevice *iter, *origdev, *nextdev; LockLists(); iter = ATOMIC_LOAD_SEQ(&DeviceList); do { if(iter == device) break; - } while((iter=iter->next) != NULL); + iter = ATOMIC_LOAD(&iter->next, almemory_order_relaxed); + } while(iter != NULL); if(!iter || iter->Type != Capture) { alcSetError(iter, ALC_INVALID_DEVICE); @@ -4358,18 +4358,14 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } origdev = device; - if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, device->next)) + nextdev = ATOMIC_LOAD(&device->next, almemory_order_relaxed); + if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) { - ALCdevice *volatile*list = &origdev->next; - while(*list) - { - if(*list == device) - { - *list = (*list)->next; - break; - } - list = &(*list)->next; - } + ALCdevice *list; + do { + list = origdev; + origdev = device; + } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } UnlockLists(); @@ -4522,7 +4518,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { - device->next = head; + ATOMIC_STORE(&device->next, head, almemory_order_relaxed); } while(!ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(&DeviceList, &head, device)); } diff --git a/Alc/ALu.c b/Alc/ALu.c index 3fd561ae..57f4188b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1827,7 +1827,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) state->OutChannels); } - ctx = ctx->next; + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); } /* Increment the clock time. Every second's worth of samples is @@ -1965,6 +1965,6 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ATOMIC_STORE(&voice->Playing, false, almemory_order_release); } - ctx = ctx->next; + ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1726cb37..b21b76a3 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -581,7 +581,7 @@ struct ALCdevice_struct { almtx_t BackendLock; struct ALCbackend *Backend; - ALCdevice *volatile next; + ATOMIC(ALCdevice*) next; }; // Frequency was requested by the app or config file @@ -692,7 +692,7 @@ struct ALCcontext_struct { ALCdevice *Device; const ALCchar *ExtensionList; - ALCcontext *volatile next; + ATOMIC(ALCcontext*) next; /* Memory space used by the listener (and possibly default effect slot) */ alignas(16) ALCbyte _listener_mem[]; -- cgit v1.2.3 From 4bd02eada65a9c9140c0c62524692038165e9a31 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Mar 2018 09:00:14 -0800 Subject: Init more stuff in InitDevice --- Alc/ALc.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3cc50e8c..3fd3ab8f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2361,10 +2361,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } -static void InitDevice(ALCdevice *device) +static void InitDevice(ALCdevice *device, enum DeviceType type) { ALsizei i; + InitRef(&device->ref, 1); + ATOMIC_INIT(&device->Connected, ALC_TRUE); + device->Type = type; + ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); + device->Flags = 0; device->Render_Mode = NormalRender; device->AvgSpeakerDist = 0.0f; @@ -4031,12 +4036,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } //Validate device - InitRef(&device->ref, 1); - ATOMIC_INIT(&device->Connected, ALC_TRUE); - device->Type = Playback; - ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - - InitDevice(device); + InitDevice(device, Playback); //Set output format device->FmtChans = DevFmtChannelsDefault; @@ -4284,11 +4284,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, } //Validate device - InitRef(&device->ref, 1); - ATOMIC_INIT(&device->Connected, ALC_TRUE); - device->Type = Capture; - - InitDevice(device); + InitDevice(device, Capture); device->Frequency = frequency; device->Flags |= DEVICE_FREQUENCY_REQUEST; @@ -4465,12 +4461,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN } //Validate device - InitRef(&device->ref, 1); - ATOMIC_INIT(&device->Connected, ALC_TRUE); - device->Type = Loopback; - ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); - - InitDevice(device); + InitDevice(device, Loopback); device->SourcesMax = 256; device->AuxiliaryEffectSlotMax = 64; -- cgit v1.2.3 From 4e6c758daf1849741712eaf451f392264fd49244 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Mar 2018 13:42:37 -0800 Subject: Use a plain mutex for the property lock --- Alc/ALc.c | 12 ++++---- OpenAL32/Include/alMain.h | 3 +- OpenAL32/alAuxEffectSlot.c | 8 +++--- OpenAL32/alListener.c | 48 +++++++++++++++---------------- OpenAL32/alSource.c | 72 ++++++++++++++++------------------------------ OpenAL32/alState.c | 24 ++++++++-------- 6 files changed, 72 insertions(+), 95 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 3fd3ab8f..ab21c356 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1629,7 +1629,7 @@ void ALCcontext_DeferUpdates(ALCcontext *context) */ void ALCcontext_ProcessUpdates(ALCcontext *context) { - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(ATOMIC_EXCHANGE_SEQ(&context->DeferUpdates, AL_FALSE)) { /* Tell the mixer to stop applying updates, then wait for any active @@ -1651,7 +1651,7 @@ void ALCcontext_ProcessUpdates(ALCcontext *context) */ ATOMIC_STORE_SEQ(&context->HoldUpdates, AL_FALSE); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); } @@ -2244,7 +2244,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) UpdateEffectSlotProps(slot, context); } - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); almtx_lock(&context->EffectSlotLock); for(pos = 0;pos < (ALsizei)VECTOR_SIZE(context->EffectSlotList);pos++) { @@ -2342,7 +2342,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) ATOMIC_FLAG_TEST_AND_SET(&context->Listener->PropsClean, almemory_order_release); UpdateListenerProps(context); UpdateAllSourceProps(context); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); context = ATOMIC_LOAD(&context->next, almemory_order_relaxed); } @@ -2581,7 +2581,7 @@ static ALvoid InitContext(ALCcontext *Context) InitRef(&Context->UpdateCount, 0); ATOMIC_INIT(&Context->HoldUpdates, AL_FALSE); Context->GainBoost = 1.0f; - RWLockInit(&Context->PropLock); + almtx_init(&Context->PropLock, almtx_plain); ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); VECTOR_INIT(Context->SourceList); Context->NumSources = 0; @@ -2763,6 +2763,8 @@ static void FreeContext(ALCcontext *context) ll_ringbuffer_free(context->AsyncEvents); context->AsyncEvents = NULL; + almtx_destroy(&context->PropLock); + ALCdevice_DecRef(context->Device); context->Device = NULL; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b21b76a3..6d6d661f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -26,7 +26,6 @@ #include "static_assert.h" #include "align.h" #include "atomic.h" -#include "uintmap.h" #include "vector.h" #include "alstring.h" #include "almalloc.h" @@ -651,7 +650,7 @@ struct ALCcontext_struct { ATOMIC_FLAG PropsClean; ATOMIC(ALenum) DeferUpdates; - RWLock PropLock; + almtx_t PropLock; /* Counter for the pre-mixing updates, in 31.1 fixed point (lowest bit * indicates if updates are currently happening). diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 04edcc09..6eb6187b 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -244,7 +244,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); @@ -282,7 +282,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param done: UnlockEffectSlotList(context); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -324,7 +324,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); LockEffectSlotList(context); if((slot=LookupEffectSlot(context, effectslot)) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot); @@ -344,7 +344,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param done: UnlockEffectSlotList(context); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c index 290ae8ca..f1ac3ff4 100644 --- a/OpenAL32/alListener.c +++ b/OpenAL32/alListener.c @@ -43,7 +43,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) if(!context) return; listener = context->Listener; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(param) { case AL_GAIN: @@ -68,7 +68,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value) } done: - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -82,7 +82,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val if(!context) return; listener = context->Listener; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(param) { case AL_POSITION: @@ -108,7 +108,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val } done: - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -138,7 +138,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) if(!context) return; listener = context->Listener; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer"); switch(param) { @@ -161,7 +161,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) } done: - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -173,13 +173,13 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value)) context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); } - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -200,13 +200,13 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(param) { default: alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); } - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -241,7 +241,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!values) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -249,7 +249,7 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) default: alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); } - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -262,7 +262,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!value) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -278,7 +278,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) default: alSetError(context, AL_INVALID_ENUM, "Invalid listener float property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -291,7 +291,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!value1 || !value2 || !value3) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -311,7 +311,7 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat default: alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -337,7 +337,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!values) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -355,7 +355,7 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) default: alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -368,7 +368,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!value) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -376,7 +376,7 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) default: alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -389,7 +389,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!value1 || !value2 || !value3) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -409,7 +409,7 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu default: alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -430,7 +430,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) context = GetContextRef(); if(!context) return; - ReadLock(&context->PropLock); + almtx_lock(&context->PropLock); if(!values) alSetError(context, AL_INVALID_VALUE, "NULL pointer"); else switch(param) @@ -448,7 +448,7 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) default: alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property"); } - ReadUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index b3cf9e3e..02511382 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1757,7 +1757,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1766,7 +1766,7 @@ AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) else SetSourcefv(Source, Context, param, &value); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1779,7 +1779,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1791,7 +1791,7 @@ AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1 SetSourcefv(Source, Context, param, fvals); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1804,7 +1804,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1815,7 +1815,7 @@ AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat else SetSourcefv(Source, Context, param, values); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1829,7 +1829,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1841,7 +1841,7 @@ AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble va SetSourcefv(Source, Context, param, &fval); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1854,7 +1854,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1866,7 +1866,7 @@ AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble v SetSourcefv(Source, Context, param, fvals); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1880,7 +1880,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1898,7 +1898,7 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo SetSourcefv(Source, Context, param, fvals); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1912,7 +1912,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1921,7 +1921,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) else SetSourceiv(Source, Context, param, &value); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1934,7 +1934,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1946,7 +1946,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, AL SetSourceiv(Source, Context, param, ivals); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1959,7 +1959,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1970,7 +1970,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *val else SetSourceiv(Source, Context, param, values); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -1984,7 +1984,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -1993,7 +1993,7 @@ AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SO else SetSourcei64v(Source, Context, param, &value); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2006,7 +2006,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2018,7 +2018,7 @@ AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOF SetSourcei64v(Source, Context, param, i64vals); } UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2031,7 +2031,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin Context = GetContextRef(); if(!Context) return; - WriteLock(&Context->PropLock); + almtx_lock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2042,7 +2042,7 @@ AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALin else SetSourcei64v(Source, Context, param, values); UnlockSourceList(Context); - WriteUnlock(&Context->PropLock); + almtx_unlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2056,7 +2056,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2071,7 +2070,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *val *value = (ALfloat)dval; } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2085,7 +2083,6 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2104,7 +2101,6 @@ AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *va } } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2119,7 +2115,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2138,7 +2133,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va } } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2152,7 +2146,6 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2163,7 +2156,6 @@ AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble * else GetSourcedv(Source, Context, param, value); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2176,7 +2168,6 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2195,7 +2186,6 @@ AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble } } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2208,7 +2198,6 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2219,7 +2208,6 @@ AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble else GetSourcedv(Source, Context, param, values); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2233,7 +2221,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2244,7 +2231,6 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value else GetSourceiv(Source, Context, param, value); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2258,7 +2244,6 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2277,7 +2262,6 @@ AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1 } } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2291,7 +2275,6 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2302,7 +2285,6 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values else GetSourceiv(Source, Context, param, values); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2316,7 +2298,6 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2327,7 +2308,6 @@ AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64S else GetSourcei64v(Source, Context, param, value); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2340,7 +2320,6 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2359,7 +2338,6 @@ AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64 } } UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } @@ -2372,7 +2350,6 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 Context = GetContextRef(); if(!Context) return; - ReadLock(&Context->PropLock); LockSourceList(Context); if((Source=LookupSource(Context, source)) == NULL) alSetError(Context, AL_INVALID_NAME, "Invalid source ID %u", source); @@ -2383,7 +2360,6 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 else GetSourcei64v(Source, Context, param, values); UnlockSourceList(Context); - ReadUnlock(&Context->PropLock); ALCcontext_DecRef(Context); } diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 8448e548..460c93e0 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -79,7 +79,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -90,7 +90,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability) default: alSetError(context, AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability); } - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -102,7 +102,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) context = GetContextRef(); if(!context) return; - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -113,7 +113,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) default: alSetError(context, AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability); } - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } @@ -700,10 +700,10 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) alSetError(context, AL_INVALID_VALUE, "Doppler factor %f out of range", value); else { - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); context->DopplerFactor = value; DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); } ALCcontext_DecRef(context); @@ -734,10 +734,10 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) alSetError(context, AL_INVALID_VALUE, "Doppler velocity %f out of range", value); else { - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); context->DopplerVelocity = value; DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); } ALCcontext_DecRef(context); @@ -754,10 +754,10 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) alSetError(context, AL_INVALID_VALUE, "Speed of sound %f out of range", value); else { - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); context->SpeedOfSound = value; DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); } ALCcontext_DecRef(context); @@ -777,11 +777,11 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) alSetError(context, AL_INVALID_VALUE, "Distance model 0x%04x out of range", value); else { - WriteLock(&context->PropLock); + almtx_lock(&context->PropLock); context->DistanceModel = value; if(!context->SourceDistanceModel) DO_UPDATEPROPS(); - WriteUnlock(&context->PropLock); + almtx_unlock(&context->PropLock); } ALCcontext_DecRef(context); -- cgit v1.2.3 From b8636a3dbff0a9003aa00d871fa20302cb82e36d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Mar 2018 13:53:41 -0800 Subject: Add some missing locks to protect reading state --- OpenAL32/alState.c | 14 ++++++++++++++ OpenAL32/event.c | 2 ++ 2 files changed, 16 insertions(+) diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c index 460c93e0..ce93e143 100644 --- a/OpenAL32/alState.c +++ b/OpenAL32/alState.c @@ -126,6 +126,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) context = GetContextRef(); if(!context) return AL_FALSE; + almtx_lock(&context->PropLock); switch(capability) { case AL_SOURCE_DISTANCE_MODEL: @@ -135,6 +136,7 @@ AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) default: alSetError(context, AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -148,6 +150,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) context = GetContextRef(); if(!context) return AL_FALSE; + almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -192,6 +195,7 @@ AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -205,6 +209,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) context = GetContextRef(); if(!context) return 0.0; + almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -243,6 +248,7 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid double property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -256,6 +262,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) context = GetContextRef(); if(!context) return 0.0f; + almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -294,6 +301,7 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid float property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -307,6 +315,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) context = GetContextRef(); if(!context) return 0; + almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -345,6 +354,7 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -358,6 +368,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) context = GetContextRef(); if(!context) return 0; + almtx_lock(&context->PropLock); switch(pname) { case AL_DOPPLER_FACTOR: @@ -396,6 +407,7 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; @@ -409,6 +421,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) context = GetContextRef(); if(!context) return NULL; + almtx_lock(&context->PropLock); switch(pname) { case AL_EVENT_CALLBACK_FUNCTION_SOFT: @@ -422,6 +435,7 @@ AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname) default: alSetError(context, AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname); } + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); return value; diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 333b7613..6fd2e96f 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -134,10 +134,12 @@ AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *user context = GetContextRef(); if(!context) return; + almtx_lock(&context->PropLock); almtx_lock(&context->EventCbLock); context->EventCb = callback; context->EventParam = userParam; almtx_unlock(&context->EventCbLock); + almtx_unlock(&context->PropLock); ALCcontext_DecRef(context); } -- cgit v1.2.3 From 945d74cbc9dfa41c325efc029f2a4069dfcf9317 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Mar 2018 14:04:10 -0800 Subject: Avoid some code duplication --- OpenAL32/event.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 6fd2e96f..1189e889 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -20,16 +20,16 @@ static int EventThread(void *arg) while(1) { - AsyncEvent evt; ALbitfieldSOFT enabledevts; + AsyncEvent evt; - if(ll_ringbuffer_read_space(context->AsyncEvents) == 0) + if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0) { alsem_wait(&context->EventSem); continue; } - ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1); - if(!evt.EnumType) break; + if(!evt.EnumType) + break; almtx_lock(&context->EventCbLock); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); @@ -44,7 +44,9 @@ static int EventThread(void *arg) AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) { ALCcontext *context; + ALbitfieldSOFT enabledevts; ALbitfieldSOFT flags = 0; + bool isrunning; ALsizei i; context = GetContextRef(); @@ -72,11 +74,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); } + almtx_lock(&context->EventThrdLock); if(enable) { - ALbitfieldSOFT enabledevts; - bool isrunning; - almtx_lock(&context->EventThrdLock); if(!context->AsyncEvents) context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); @@ -90,13 +90,9 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A } if(!isrunning && flags) althrd_create(&context->EventThread, EventThread, context); - almtx_unlock(&context->EventThrdLock); } else { - ALbitfieldSOFT enabledevts; - bool isrunning; - almtx_lock(&context->EventThrdLock); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, @@ -120,8 +116,8 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A almtx_lock(&context->EventCbLock); almtx_unlock(&context->EventCbLock); } - almtx_unlock(&context->EventThrdLock); } + almtx_unlock(&context->EventThrdLock); done: ALCcontext_DecRef(context); -- cgit v1.2.3 From 179e1c4dbc143c9df50676ce538f628690799cd3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 3 Mar 2018 21:57:42 -0800 Subject: Don't check for space in the ringbuffer before trying to write The write method already checks and returns how much it managed to fit in. --- Alc/ALc.c | 3 +-- Alc/ALu.c | 11 ++++------- Alc/mixer.c | 7 ++----- OpenAL32/alSource.c | 5 ++--- OpenAL32/event.c | 3 +-- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ab21c356..0cde449e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2749,9 +2749,8 @@ static void FreeContext(ALCcontext *context) if(ATOMIC_EXCHANGE(&context->EnabledEvts, 0, almemory_order_acq_rel)) { static const AsyncEvent kill_evt = { 0 }; - while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) althrd_yield(); - ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); alsem_post(&context->EventSem); althrd_join(context->EventThread, NULL); } diff --git a/Alc/ALu.c b/Alc/ALu.c index 57f4188b..f1b958e5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -238,9 +238,8 @@ static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) } strcpy(evt.Message+strpos, " state changed to AL_STOPPED"); - if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) - ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); - alsem_post(&context->EventSem); + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); } @@ -1942,11 +1941,9 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) ALbitfieldSOFT enabledevt = ATOMIC_LOAD(&ctx->EnabledEvts, almemory_order_acquire); ALsizei i; - if((enabledevt&EventType_Disconnected) && ll_ringbuffer_write_space(ctx->AsyncEvents) > 0) - { - ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1); + if((enabledevt&EventType_Disconnected) && + ll_ringbuffer_write(ctx->AsyncEvents, (const char*)&evt, 1) == 1) alsem_post(&ctx->EventSem); - } for(i = 0;i < ctx->VoiceCount;i++) { diff --git a/Alc/mixer.c b/Alc/mixer.c index 96a5335b..7a7bbfe0 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -203,8 +203,8 @@ static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, evt.ObjectId = objid; evt.Param = param; strcpy(evt.Message, msg); - if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) - ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); } @@ -773,12 +773,9 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize /* Send any events now, after the position/buffer info was updated. */ enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - { SendAsyncEvent(Context, EventType_BufferCompleted, AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" ); - alsem_post(&Context->EventSem); - } return isplaying; } diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 02511382..40b2c494 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -248,9 +248,8 @@ static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) * and we don't want state change messages to occur out of order, so send * it through the async queue to ensure proper ordering. */ - if(ll_ringbuffer_write_space(context->AsyncEvents) > 0) - ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1); - alsem_post(&context->EventSem); + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); } diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 1189e889..12636489 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -102,9 +102,8 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A if(isrunning && !(enabledevts&~flags)) { static const AsyncEvent kill_evt = { 0 }; - while(ll_ringbuffer_write_space(context->AsyncEvents) == 0) + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) althrd_yield(); - ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1); alsem_post(&context->EventSem); althrd_join(context->EventThread, NULL); } -- cgit v1.2.3 From 86319127e3e377312f815d55693f7b46569cde62 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Wed, 7 Mar 2018 20:53:56 +0100 Subject: Add SDL2 backend for playback, fix #173 --- Alc/ALc.c | 3 + Alc/backends/base.h | 1 + Alc/backends/sdl2.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 22 ++++- config.h.in | 3 + 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 Alc/backends/sdl2.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 0cde449e..c72a1833 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -100,6 +100,9 @@ static struct BackendInfo BackendList[] = { #ifdef HAVE_OPENSL { "opensl", ALCopenslBackendFactory_getFactory }, #endif +#ifdef HAVE_SDL2 + { "sdl2", ALCsdl2BackendFactory_getFactory }, +#endif { "null", ALCnullBackendFactory_getFactory }, #ifdef HAVE_WAVE diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 177f6869..b05523b2 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -147,6 +147,7 @@ ALCbackendFactory *ALCportBackendFactory_getFactory(void); ALCbackendFactory *ALCopenslBackendFactory_getFactory(void); ALCbackendFactory *ALCnullBackendFactory_getFactory(void); ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); +ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c new file mode 100644 index 00000000..4b2d3acd --- /dev/null +++ b/Alc/backends/sdl2.c @@ -0,0 +1,265 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alu.h" +#include "threads.h" +#include "compat.h" + +#include "backends/base.h" + + +typedef struct ALCsdl2Backend { + DERIVE_FROM_TYPE(ALCbackend); + + SDL_AudioDeviceID deviceID; + ALvoid *mBuffer; + ALuint mSize; + ALCboolean quit; + ATOMIC(int) killNow; + althrd_t thread; +} ALCsdl2Backend; + +static int ALCsdl2Backend_mixerProc(void *ptr); + +static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, Destruct) +static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); +static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); +static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); +static void ALCsdl2Backend_stop(ALCsdl2Backend *self); +static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) + +DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); + +static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); + + self->mBuffer = NULL; + self->mSize = 0; + self->quit = ALC_FALSE; + if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? + { + SDL_Init(SDL_INIT_AUDIO); + self->quit = ALC_TRUE; + } + else if(!SDL_WasInit(SDL_INIT_AUDIO)) + SDL_InitSubSystem(SDL_INIT_AUDIO); + + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + + +static int ALCsdl2Backend_mixerProc(void *ptr) +{ + ALCsdl2Backend *self = (ALCsdl2Backend*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + struct timespec now, start; + ALuint64 avail, done; + const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / + device->Frequency / 2); + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + done = 0; + if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get starting time\n"); + return 1; + } + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) + { + ERR("Failed to get current time\n"); + return 1; + } + + avail = (now.tv_sec - start.tv_sec) * device->Frequency; + avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; + if(avail < done) + { + /* Oops, time skipped backwards. Reset the number of samples done + * with one update available since we (likely) just came back from + * sleeping. */ + done = avail - device->UpdateSize; + } + + if(avail-done < device->UpdateSize) + al_nssleep(restTime); + else while(avail-done >= device->UpdateSize) + { + ALCsdl2Backend_lock(self); + aluMixData(device, self->mBuffer, device->UpdateSize); + SDL_QueueAudio(self->deviceID, self->mBuffer, self->mSize); + ALCsdl2Backend_unlock(self); + done += device->UpdateSize; + } + } + + return 0; +} + +static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + SDL_AudioSpec want; + SDL_zero(want); + want.freq = device->Frequency; + want.format = AUDIO_F32; + want.channels = 2; + want.samples = device->UpdateSize; + + if(!name) + name = SDL_GetAudioDeviceName(0, 0); + self->deviceID = SDL_OpenAudioDevice(name, 0, &want, NULL, 0); + if(self->deviceID == 0) { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + alstr_copy_cstr(&STATIC_CAST(ALCbackend, self)->mDevice->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) +{ + SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + return ALC_TRUE; +} + +static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + self->mSize = device->UpdateSize * FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + self->mBuffer = malloc(self->mSize); + if(!self->mBuffer) + { + ERR("Buffer malloc failed\n"); + return ALC_FALSE; + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, ALCsdl2Backend_mixerProc, self) != althrd_success) + { + free(self->mBuffer); + self->mBuffer = NULL; + self->mSize = 0; + return ALC_FALSE; + } + SDL_PauseAudioDevice(self->deviceID, 0); + return ALC_TRUE; +} + +static void ALCsdl2Backend_stop(ALCsdl2Backend *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + free(self->mBuffer); + self->mBuffer = NULL; + if(self->quit) + SDL_Quit(); +} + + +typedef struct ALCsdl2BackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCsdl2BackendFactory; +#define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } } + +ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); + +static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); +static DECLARE_FORWARD(ALCsdl2BackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type); +static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); + + +ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void) +{ + static ALCsdl2BackendFactory factory = ALCsdl2BACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self)) +{ + return ALC_TRUE; +} + +static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type) +{ + if(type != ALL_DEVICE_PROBE) + return; + ALCboolean quit = ALC_FALSE; + if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? + { + SDL_Init(SDL_INIT_AUDIO); + quit = ALC_TRUE; + } + else if(!SDL_WasInit(SDL_INIT_AUDIO)) + SDL_InitSubSystem(SDL_INIT_AUDIO); + for(int i = 0; i < SDL_GetNumAudioDevices(0); ++i) + AppendAllDevicesList(SDL_GetAudioDeviceName(i, 0)); + if(quit) + SDL_Quit(); +} + +static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCsdl2Backend *backend; + NEW_OBJ(backend, ALCsdl2Backend)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index bd531128..0c6196f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -759,6 +759,7 @@ SET(HAVE_PULSEAUDIO 0) SET(HAVE_COREAUDIO 0) SET(HAVE_OPENSL 0) SET(HAVE_WAVE 0) +SET(HAVE_SDL2 0) # Check for SSE support OPTION(ALSOFT_REQUIRE_SSE "Require SSE support" OFF) @@ -1123,6 +1124,23 @@ IF(ALSOFT_REQUIRE_OPENSL AND NOT HAVE_OPENSL) MESSAGE(FATAL_ERROR "Failed to enabled required OpenSL backend") ENDIF() +# Check for SDL2 backend +OPTION(ALSOFT_REQUIRE_SDL2 "Require SDL2 backend" OFF) +FIND_PACKAGE(SDL2) +IF(SDL2_FOUND) + # Off by default, since it adds a runtime dependency + OPTION(ALSOFT_BACKEND_SDL2 "Enable SDL2 backend" OFF) + IF(ALSOFT_BACKEND_SDL2) + SET(HAVE_SDL2 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.c) + SET(BACKENDS "${BACKENDS} SDL2,") + SET(EXTRA_LIBS ${SDL2_LIBRARY} ${EXTRA_LIBS}) + ENDIF() +ENDIF() +IF(ALSOFT_REQUIRE_SDL2 AND NOT SDL2_FOUND) + MESSAGE(FATAL_ERROR "Failed to enabled required SDL2 backend") +ENDIF() + # Optionally enable the Wave Writer backend OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) IF(ALSOFT_BACKEND_WAVE) @@ -1206,7 +1224,9 @@ IF(ALSOFT_UTILS AND NOT ALSOFT_NO_CONFIG_UTIL) add_subdirectory(utils/alsoft-config) ENDIF() IF(ALSOFT_EXAMPLES) - FIND_PACKAGE(SDL2) + IF(NOT SDL2_FOUND) + FIND_PACKAGE(SDL2) + ENDIF() IF(SDL2_FOUND) FIND_PACKAGE(SDL_sound) FIND_PACKAGE(FFmpeg COMPONENTS AVFORMAT AVCODEC AVUTIL SWSCALE SWRESAMPLE) diff --git a/config.h.in b/config.h.in index 2abeedfd..345e8408 100644 --- a/config.h.in +++ b/config.h.in @@ -77,6 +77,9 @@ /* Define if we have the Wave Writer backend */ #cmakedefine HAVE_WAVE +/* Define if we have the SDL2 backend */ +#cmakedefine HAVE_SDL2 + /* Define if we have the stat function */ #cmakedefine HAVE_STAT -- cgit v1.2.3 From 767807cd2273eb9e760b25d792820b1c8f1946e1 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Thu, 8 Mar 2018 09:50:16 +0100 Subject: SDL2 backend: Use callback instead of a timing loop The system clock and audio clock aren't necessarily synchronized. --- Alc/backends/sdl2.c | 94 +++++++---------------------------------------------- 1 file changed, 11 insertions(+), 83 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 4b2d3acd..c191a528 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -35,15 +35,10 @@ typedef struct ALCsdl2Backend { DERIVE_FROM_TYPE(ALCbackend); SDL_AudioDeviceID deviceID; - ALvoid *mBuffer; - ALuint mSize; ALCboolean quit; - ATOMIC(int) killNow; althrd_t thread; } ALCsdl2Backend; -static int ALCsdl2Backend_mixerProc(void *ptr); - static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, Destruct) static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); @@ -64,8 +59,6 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); - self->mBuffer = NULL; - self->mSize = 0; self->quit = ALC_FALSE; if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? { @@ -74,61 +67,20 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) } else if(!SDL_WasInit(SDL_INIT_AUDIO)) SDL_InitSubSystem(SDL_INIT_AUDIO); - - ATOMIC_INIT(&self->killNow, AL_TRUE); } -static int ALCsdl2Backend_mixerProc(void *ptr) +static void ALCsdl2Backend_audioCallback(void *ptr, Uint8* stream, int len) { ALCsdl2Backend *self = (ALCsdl2Backend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - struct timespec now, start; - ALuint64 avail, done; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && - ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) - { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } - - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) - { - /* Oops, time skipped backwards. Reset the number of samples done - * with one update available since we (likely) just came back from - * sleeping. */ - done = avail - device->UpdateSize; - } - - if(avail-done < device->UpdateSize) - al_nssleep(restTime); - else while(avail-done >= device->UpdateSize) - { - ALCsdl2Backend_lock(self); - aluMixData(device, self->mBuffer, device->UpdateSize); - SDL_QueueAudio(self->deviceID, self->mBuffer, self->mSize); - ALCsdl2Backend_unlock(self); - done += device->UpdateSize; - } - } - - return 0; + ALsizei frameSize = FrameSizeFromDevFmt( + device->FmtChans, device->FmtType, device->AmbiOrder + ); + assert(len % frameSize == 0); + ALCsdl2Backend_lock(self); + aluMixData(device, stream, len / frameSize); + ALCsdl2Backend_unlock(self); } static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) @@ -140,6 +92,8 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) want.format = AUDIO_F32; want.channels = 2; want.samples = device->UpdateSize; + want.callback = ALCsdl2Backend_audioCallback; + want.userdata = self; if(!name) name = SDL_GetAudioDeviceName(0, 0); @@ -161,39 +115,13 @@ static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->mSize = device->UpdateSize * FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - self->mBuffer = malloc(self->mSize); - if(!self->mBuffer) - { - ERR("Buffer malloc failed\n"); - return ALC_FALSE; - } - - ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCsdl2Backend_mixerProc, self) != althrd_success) - { - free(self->mBuffer); - self->mBuffer = NULL; - self->mSize = 0; - return ALC_FALSE; - } SDL_PauseAudioDevice(self->deviceID, 0); return ALC_TRUE; } static void ALCsdl2Backend_stop(ALCsdl2Backend *self) { - int res; - - if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) - return; - althrd_join(self->thread, &res); - - free(self->mBuffer); - self->mBuffer = NULL; + SDL_PauseAudioDevice(self->deviceID, 1); if(self->quit) SDL_Quit(); } -- cgit v1.2.3 From a6f93a501a08ddf35f98473822a70258e70f613a Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Thu, 8 Mar 2018 10:07:22 +0100 Subject: Handle passing NULL to SDL_OpenAudioDevice as a special device https://discourse.libsdl.org/t/changing-audio-output-when-the-default-audio-playback-device-changes/22399/2 --- Alc/backends/sdl2.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index c191a528..9881594d 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -54,6 +54,8 @@ DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); +static const ALCchar defaultDeviceName[] = "Default device"; + static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -95,13 +97,16 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) want.callback = ALCsdl2Backend_audioCallback; want.userdata = self; - if(!name) - name = SDL_GetAudioDeviceName(0, 0); + if (name && strcmp(name, defaultDeviceName) == 0) + name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first + // device in the list. self->deviceID = SDL_OpenAudioDevice(name, 0, &want, NULL, 0); if(self->deviceID == 0) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; } + if(!name) + name = defaultDeviceName; alstr_copy_cstr(&STATIC_CAST(ALCbackend, self)->mDevice->DeviceName, name); return ALC_NO_ERROR; @@ -173,6 +178,7 @@ static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enu } else if(!SDL_WasInit(SDL_INIT_AUDIO)) SDL_InitSubSystem(SDL_INIT_AUDIO); + AppendAllDevicesList(defaultDeviceName); for(int i = 0; i < SDL_GetNumAudioDevices(0); ++i) AppendAllDevicesList(SDL_GetAudioDeviceName(i, 0)); if(quit) -- cgit v1.2.3 From ef2b813776a173425ff691749453f83265747768 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Thu, 8 Mar 2018 10:17:02 +0100 Subject: SDL2 backend: Allow frequency changes --- Alc/backends/sdl2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 9881594d..a52b22c8 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -88,7 +88,7 @@ static void ALCsdl2Backend_audioCallback(void *ptr, Uint8* stream, int len) static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - SDL_AudioSpec want; + SDL_AudioSpec want, have; SDL_zero(want); want.freq = device->Frequency; want.format = AUDIO_F32; @@ -100,7 +100,12 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) if (name && strcmp(name, defaultDeviceName) == 0) name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first // device in the list. - self->deviceID = SDL_OpenAudioDevice(name, 0, &want, NULL, 0); + self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); + if(want.freq != have.freq) + { + TRACE("Frequency changed by SDL2\n"); + device->Frequency = have.freq; + } if(self->deviceID == 0) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; -- cgit v1.2.3 From 0af075b5ffb98e9093cd174862d4289ef4d98252 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Thu, 8 Mar 2018 20:26:31 +0100 Subject: SDL2 backend: Allow changes to channels and format --- Alc/backends/sdl2.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index a52b22c8..414dbe19 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -100,12 +100,33 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) if (name && strcmp(name, defaultDeviceName) == 0) name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first // device in the list. - self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); + self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); if(want.freq != have.freq) { TRACE("Frequency changed by SDL2\n"); device->Frequency = have.freq; } + if(have.channels == 1) + device->FmtChans = DevFmtMono; + else if(have.channels == 2) + device->FmtChans = DevFmtStereo; + else + { + ERR("Invalid number of channels\n"); + return ALC_INVALID_VALUE; + } + switch(have.format) + { + case AUDIO_U8: device->FmtType = DevFmtUByte; break; + case AUDIO_S8: device->FmtType = DevFmtByte; break; + case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break; + case AUDIO_S16SYS: device->FmtType = DevFmtShort; break; + case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; + case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; + default: + ERR("Unsupported format\n"); + return ALC_INVALID_VALUE; + } if(self->deviceID == 0) { ERR("Could not open device\n"); return ALC_INVALID_VALUE; -- cgit v1.2.3 From 2eb29d538b0e90a48f45f55eaf110fa114b17f35 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Thu, 8 Mar 2018 20:39:15 +0100 Subject: SDL2 backend: Reset device parameters --- Alc/backends/sdl2.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 414dbe19..9bd42cdf 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -36,7 +36,9 @@ typedef struct ALCsdl2Backend { SDL_AudioDeviceID deviceID; ALCboolean quit; - althrd_t thread; + ALuint Frequency; + enum DevFmtChannels FmtChans; + enum DevFmtType FmtType; } ALCsdl2Backend; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); @@ -62,6 +64,9 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); self->quit = ALC_FALSE; + self->Frequency = device->Frequency; + self->FmtChans = device->FmtChans; + self->FmtType = device->FmtType; if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? { SDL_Init(SDL_INIT_AUDIO); @@ -92,7 +97,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) SDL_zero(want); want.freq = device->Frequency; want.format = AUDIO_F32; - want.channels = 2; + want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; want.samples = device->UpdateSize; want.callback = ALCsdl2Backend_audioCallback; want.userdata = self; @@ -101,6 +106,11 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first // device in the list. self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); + if(self->deviceID == 0) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } if(want.freq != have.freq) { TRACE("Frequency changed by SDL2\n"); @@ -127,10 +137,9 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) ERR("Unsupported format\n"); return ALC_INVALID_VALUE; } - if(self->deviceID == 0) { - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } + self->Frequency = device->Frequency; + self->FmtChans = device->FmtChans; + self->FmtType = device->FmtType; if(!name) name = defaultDeviceName; alstr_copy_cstr(&STATIC_CAST(ALCbackend, self)->mDevice->DeviceName, name); @@ -140,7 +149,11 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) { - SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice); + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + device->Frequency = self->Frequency; + device->FmtChans = self->FmtChans; + device->FmtType = self->FmtType; + SetDefaultWFXChannelOrder(device); return ALC_TRUE; } -- cgit v1.2.3 From 19281868dce20d47344bd059b5f3c4af5264baaa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 14:00:28 -0800 Subject: Properly limit the max number of effect slots to 2^31 - 1 --- Alc/ALc.c | 2 ++ OpenAL32/alAuxEffectSlot.c | 10 +--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index c72a1833..554a4951 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -4139,6 +4139,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; + else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); if(ConfigValueInt(deviceName, NULL, "sends", &device->NumAuxSends)) device->NumAuxSends = clampi( @@ -4487,6 +4488,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 64; + else device->AuxiliaryEffectSlotMax = minu(device->AuxiliaryEffectSlotMax, INT_MAX); if(ConfigValueInt(NULL, NULL, "sends", &device->NumAuxSends)) device->NumAuxSends = clampi( diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 6eb6187b..9ccfaa36 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -109,7 +109,6 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo ALCdevice *device; ALCcontext *context; ALsizei cur; - ALenum err; context = GetContextRef(); if(!context) return; @@ -131,6 +130,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList); ALeffectslot *slot = NULL; + ALenum err = AL_OUT_OF_MEMORY; for(;iter != end;iter++) { @@ -139,18 +139,10 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo } if(iter == end) { - if(VECTOR_SIZE(context->EffectSlotList) >= INT_MAX) - { - UnlockEffectSlotList(context); - - alDeleteAuxiliaryEffectSlots(cur, effectslots); - SETERR_GOTO(context, err, done, "Too many effect slot objects"); - } VECTOR_PUSH_BACK(context->EffectSlotList, NULL); iter = &VECTOR_BACK(context->EffectSlotList); } slot = al_calloc(16, sizeof(ALeffectslot)); - err = AL_OUT_OF_MEMORY; if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) { al_free(slot); -- cgit v1.2.3 From 9bd1678299433a1f569a0d7680a25fbf4de83450 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 15:11:17 -0800 Subject: Fix adding to and removing from the active effect slots It wasn't properly removing all duplicates on insertion, and didn't remove the first effect slot when removing them. --- OpenAL32/alAuxEffectSlot.c | 56 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 9ccfaa36..d4e6bf75 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -598,18 +598,29 @@ static void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontex { for(j = i;j != 0;) { - if(newarray->slot[i] == newarray->slot[--j]) + if(UNLIKELY(newarray->slot[i] == newarray->slot[--j])) + { + newcount--; + for(j = i;j < newcount;j++) + newarray->slot[j] = newarray->slot[j+1]; + i--; break; - } - if(j != 0) - { - newcount--; - for(j = i;j < newcount;j++) - newarray->slot[j] = newarray->slot[j+1]; - i--; + } } } - newarray->count = newcount; + + /* Reallocate newarray if the new size ended up smaller from duplicate + * removal. + */ + if(UNLIKELY(newcount < newarray->count)) + { + struct ALeffectslotArray *tmpnewarray = al_calloc(DEF_ALIGN, + FAM_SIZE(struct ALeffectslotArray, slot, newcount)); + memcpy(tmpnewarray, newarray, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); + al_free(newarray); + newarray = tmpnewarray; + newarray->count = newcount; + } curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) @@ -622,26 +633,29 @@ static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcon struct ALeffectslotArray *curarray = ATOMIC_LOAD(&context->ActiveAuxSlots, almemory_order_acquire); struct ALeffectslotArray *newarray = NULL; - ALsizei newcount = curarray->count - count; ALCdevice *device = context->Device; ALsizei i, j; - assert(newcount >= 0); - newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, newcount)); - newarray->count = newcount; - for(i = j = 0;i < newarray->count;) + /* Don't shrink the allocated array size since we don't know how many (if + * any) of the effect slots to remove are in the array. + */ + newarray = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, curarray->count)); + newarray->count = 0; + for(i = 0;i < curarray->count;i++) { - ALeffectslot *slot = curarray->slot[j++]; - ALsizei k = count; - while(k != 0) + /* Insert this slot into the new array only if it's not one to remove. */ + ALeffectslot *slot = curarray->slot[i]; + for(j = count;j != 0;) { - if(slot->id == slotids[--k]) - break; + if(slot->id == slotids[--j]) + goto skip_ins; } - if(k == 0) - newarray->slot[i++] = slot; + newarray->slot[newarray->count++] = slot; + skip_ins: ; } + /* TODO: Could reallocate newarray now that we know it's needed size. */ + curarray = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, newarray, almemory_order_acq_rel); while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1)) althrd_yield(); -- cgit v1.2.3 From 07c8857558ce4823b7e973aa1b998a62bdd83c3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 15:52:50 -0800 Subject: Fix struct forward declaration typo --- OpenAL32/Include/alAuxEffectSlot.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 060ab533..36f09782 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -59,7 +59,7 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \ } -struct EeffectStateFactoryVtable; +struct EffectStateFactoryVtable; typedef struct EffectStateFactory { const struct EffectStateFactoryVtable *vtab; -- cgit v1.2.3 From 4e613c5d4b83e40d22acdf816cd41d911e6052aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 18:09:34 -0800 Subject: Rename UpdateContextSources for clarity --- Alc/ALu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f1b958e5..7461dcbf 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1566,7 +1566,7 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) } -static void UpdateContextSources(ALCcontext *ctx, const struct ALeffectslotArray *slots) +static void ProcessParamUpdates(ALCcontext *ctx, const struct ALeffectslotArray *slots) { ALvoice **voice, **voice_end; ALsource *source; @@ -1791,7 +1791,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) const struct ALeffectslotArray *auxslots; auxslots = ATOMIC_LOAD(&ctx->ActiveAuxSlots, almemory_order_acquire); - UpdateContextSources(ctx, auxslots); + ProcessParamUpdates(ctx, auxslots); for(i = 0;i < auxslots->count;i++) { -- cgit v1.2.3 From 22d3e3b5639ac1de8e35a9be1dd82745ca3ddc23 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 22:26:30 -0800 Subject: Simplify modulator effect index updating --- Alc/effects/modulator.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 74a0d0c5..a7c4ce36 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -135,7 +135,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->step = fastf2i(props->Modulator.Frequency*WAVEFORM_FRACONE / device->Frequency); - if(state->step == 0) state->step = 1; + state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); /* Custom filter coeffs, which match the old version instead of a low-shelf. */ cw = cosf(F_TAU * props->Modulator.HighPassCutoff / device->Frequency); @@ -177,8 +177,7 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT state->Chans[i].TargetGains, SamplesToDo-base, base, td); } - for(i = 0;i < td;i++) - index += step; + index += (step*td) & WAVEFORM_FRACMASK; index &= WAVEFORM_FRACMASK; base += td; } -- cgit v1.2.3 From 52dee312702a80974b9a3d8a838faafe65f3e36b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 4 Mar 2018 22:44:20 -0800 Subject: Only calculate the modulation samples once for all 4 channels --- Alc/effects/modulator.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index a7c4ce36..9ec0d47e 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -30,14 +30,18 @@ #include "alu.h" +#define MAX_UPDATE_SAMPLES 128 + typedef struct ALmodulatorState { DERIVE_FROM_TYPE(ALeffectState); - void (*Process)(ALfloat*, const ALfloat*, ALsizei, const ALsizei, ALsizei); + void (*GetSamples)(ALfloat*, ALsizei, const ALsizei, ALsizei); ALsizei index; ALsizei step; + alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES]; + struct { ALfilterState Filter; @@ -75,15 +79,15 @@ static inline ALfloat Square(ALsizei index) } #define DECL_TEMPLATE(func) \ -static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\ - ALsizei index, const ALsizei step, ALsizei todo) \ +static void Modulate##func(ALfloat *restrict dst, ALsizei index, \ + const ALsizei step, ALsizei todo) \ { \ ALsizei i; \ for(i = 0;i < todo;i++) \ { \ index += step; \ index &= WAVEFORM_FRACMASK; \ - dst[i] = src[i] * func(index); \ + dst[i] = func(index); \ } \ } @@ -127,11 +131,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext ALsizei i; if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) - state->Process = ModulateSin; + state->GetSamples = ModulateSin; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) - state->Process = ModulateSaw; + state->GetSamples = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ - state->Process = ModulateSquare; + state->GetSamples = ModulateSquare; state->step = fastf2i(props->Modulator.Frequency*WAVEFORM_FRACONE / device->Frequency); @@ -158,30 +162,32 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { + ALfloat *restrict modsamples = ASSUME_ALIGNED(state->ModSamples, 16); const ALsizei step = state->step; - ALsizei index = state->index; ALsizei base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[2][128]; - ALsizei td = mini(128, SamplesToDo-base); - ALsizei i; + alignas(16) ALfloat temps[2][MAX_UPDATE_SAMPLES]; + ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); + ALsizei c, i; + + state->GetSamples(modsamples, state->index, step, td); + state->index += (step*td) & WAVEFORM_FRACMASK; + state->index &= WAVEFORM_FRACMASK; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - ALfilterState_process(&state->Chans[i].Filter, temps[0], &SamplesIn[i][base], td); - state->Process(temps[1], temps[0], index, step, td); + ALfilterState_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); + for(i = 0;i < td;i++) + temps[1][i] = temps[0][i] * modsamples[i]; - MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[i].CurrentGains, - state->Chans[i].TargetGains, SamplesToDo-base, base, td); + MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[c].CurrentGains, + state->Chans[c].TargetGains, SamplesToDo-base, base, td); } - index += (step*td) & WAVEFORM_FRACMASK; - index &= WAVEFORM_FRACMASK; base += td; } - state->index = index; } -- cgit v1.2.3 From 2187316bce826de1eaa6438f688d4713032be3da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 5 Mar 2018 11:29:03 -0800 Subject: Use function-like macros to call filter and effect vtable methods --- OpenAL32/Include/alEffect.h | 10 +++++++++- OpenAL32/Include/alFilter.h | 10 +++++++++- OpenAL32/alEffect.c | 38 +++++++++++++++++++------------------- OpenAL32/alFilter.c | 24 ++++++++++++------------ 4 files changed, 49 insertions(+), 33 deletions(-) diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 4469349c..95fa035e 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -160,11 +160,19 @@ typedef struct ALeffect { ALeffectProps Props; - const struct ALeffectVtable *vtbl; + const struct ALeffectVtable *vtab; /* Self ID */ ALuint id; } ALeffect; +#define ALeffect_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) +#define ALeffect_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) +#define ALeffect_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) +#define ALeffect_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) +#define ALeffect_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) +#define ALeffect_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) +#define ALeffect_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) +#define ALeffect_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) inline ALboolean IsReverbEffect(ALenum type) { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index e28b7b2b..4e506722 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -157,11 +157,19 @@ typedef struct ALfilter { ALfloat GainLF; ALfloat LFReference; - const struct ALfilterVtable *vtbl; + const struct ALfilterVtable *vtab; /* Self ID */ ALuint id; } ALfilter; +#define ALfilter_setParami(o, c, p, v) ((o)->vtab->setParami(o, c, p, v)) +#define ALfilter_setParamf(o, c, p, v) ((o)->vtab->setParamf(o, c, p, v)) +#define ALfilter_setParamiv(o, c, p, v) ((o)->vtab->setParamiv(o, c, p, v)) +#define ALfilter_setParamfv(o, c, p, v) ((o)->vtab->setParamfv(o, c, p, v)) +#define ALfilter_getParami(o, c, p, v) ((o)->vtab->getParami(o, c, p, v)) +#define ALfilter_getParamf(o, c, p, v) ((o)->vtab->getParamf(o, c, p, v)) +#define ALfilter_getParamiv(o, c, p, v) ((o)->vtab->getParamiv(o, c, p, v)) +#define ALfilter_getParamfv(o, c, p, v) ((o)->vtab->getParamfv(o, c, p, v)) void ReleaseALFilters(ALCdevice *device); diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index f4258e60..6b16fc56 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -176,7 +176,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) else { /* Call the appropriate handler */ - V(ALEffect,setParami)(Context, param, value); + ALeffect_setParami(ALEffect, Context, param, value); } } UnlockEffectList(Device); @@ -207,7 +207,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v else { /* Call the appropriate handler */ - V(ALEffect,setParamiv)(Context, param, values); + ALeffect_setParamiv(ALEffect, Context, param, values); } UnlockEffectList(Device); @@ -230,7 +230,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) else { /* Call the appropriate handler */ - V(ALEffect,setParamf)(Context, param, value); + ALeffect_setParamf(ALEffect, Context, param, value); } UnlockEffectList(Device); @@ -253,7 +253,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat else { /* Call the appropriate handler */ - V(ALEffect,setParamfv)(Context, param, values); + ALeffect_setParamfv(ALEffect, Context, param, values); } UnlockEffectList(Device); @@ -280,7 +280,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value else { /* Call the appropriate handler */ - V(ALEffect,getParami)(Context, param, value); + ALeffect_getParami(ALEffect, Context, param, value); } } UnlockEffectList(Device); @@ -311,7 +311,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu else { /* Call the appropriate handler */ - V(ALEffect,getParamiv)(Context, param, values); + ALeffect_getParamiv(ALEffect, Context, param, values); } UnlockEffectList(Device); @@ -334,7 +334,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val else { /* Call the appropriate handler */ - V(ALEffect,getParamf)(Context, param, value); + ALeffect_getParamf(ALEffect, Context, param, value); } UnlockEffectList(Device); @@ -357,7 +357,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va else { /* Call the appropriate handler */ - V(ALEffect,getParamfv)(Context, param, values); + ALeffect_getParamfv(ALEffect, Context, param, values); } UnlockEffectList(Device); @@ -500,7 +500,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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; - effect->vtbl = &ALeaxreverb_vtable; + effect->vtab = &ALeaxreverb_vtable; break; case AL_EFFECT_REVERB: effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY; @@ -530,7 +530,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Reverb.LFReference = 250.0f; effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; - effect->vtbl = &ALreverb_vtable; + effect->vtab = &ALreverb_vtable; break; case AL_EFFECT_CHORUS: effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; @@ -539,11 +539,11 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH; effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK; effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY; - effect->vtbl = &ALchorus_vtable; + effect->vtab = &ALchorus_vtable; break; case AL_EFFECT_COMPRESSOR: effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF; - effect->vtbl = &ALcompressor_vtable; + effect->vtab = &ALcompressor_vtable; break; case AL_EFFECT_DISTORTION: effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE; @@ -551,7 +551,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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; - effect->vtbl = &ALdistortion_vtable; + effect->vtab = &ALdistortion_vtable; break; case AL_EFFECT_ECHO: effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY; @@ -559,7 +559,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING; effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD; - effect->vtbl = &ALecho_vtable; + effect->vtab = &ALecho_vtable; break; case AL_EFFECT_EQUALIZER: effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF; @@ -572,7 +572,7 @@ static void InitEffectParams(ALeffect *effect, ALenum type) 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; - effect->vtbl = &ALequalizer_vtable; + effect->vtab = &ALequalizer_vtable; break; case AL_EFFECT_FLANGER: effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM; @@ -581,21 +581,21 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH; effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK; effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; - effect->vtbl = &ALflanger_vtable; + effect->vtab = &ALflanger_vtable; break; case AL_EFFECT_RING_MODULATOR: 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; - effect->vtbl = &ALmodulator_vtable; + effect->vtab = &ALmodulator_vtable; break; case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: case AL_EFFECT_DEDICATED_DIALOGUE: effect->Props.Dedicated.Gain = 1.0f; - effect->vtbl = &ALdedicated_vtable; + effect->vtab = &ALdedicated_vtable; break; default: - effect->vtbl = &ALnull_vtable; + effect->vtab = &ALnull_vtable; break; } effect->type = type; diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 70ae901c..08f66d26 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -154,7 +154,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) else { /* Call the appropriate handler */ - V(ALFilter,setParami)(Context, param, value); + ALfilter_setParami(ALFilter, Context, param, value); } } UnlockFilterList(Device); @@ -185,7 +185,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v else { /* Call the appropriate handler */ - V(ALFilter,setParamiv)(Context, param, values); + ALfilter_setParamiv(ALFilter, Context, param, values); } UnlockFilterList(Device); @@ -208,7 +208,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) else { /* Call the appropriate handler */ - V(ALFilter,setParamf)(Context, param, value); + ALfilter_setParamf(ALFilter, Context, param, value); } UnlockFilterList(Device); @@ -231,7 +231,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat else { /* Call the appropriate handler */ - V(ALFilter,setParamfv)(Context, param, values); + ALfilter_setParamfv(ALFilter, Context, param, values); } UnlockFilterList(Device); @@ -258,7 +258,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value else { /* Call the appropriate handler */ - V(ALFilter,getParami)(Context, param, value); + ALfilter_getParami(ALFilter, Context, param, value); } } UnlockFilterList(Device); @@ -289,7 +289,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu else { /* Call the appropriate handler */ - V(ALFilter,getParamiv)(Context, param, values); + ALfilter_getParamiv(ALFilter, Context, param, values); } UnlockFilterList(Device); @@ -312,7 +312,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val else { /* Call the appropriate handler */ - V(ALFilter,getParamf)(Context, param, value); + ALfilter_getParamf(ALFilter, Context, param, value); } UnlockFilterList(Device); @@ -335,7 +335,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va else { /* Call the appropriate handler */ - V(ALFilter,getParamfv)(Context, param, values); + ALfilter_getParamfv(ALFilter, Context, param, values); } UnlockFilterList(Device); @@ -720,7 +720,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = 1.0f; filter->LFReference = HIGHPASSFREQREF; - filter->vtbl = &ALlowpass_vtable; + filter->vtab = &ALlowpass_vtable; } else if(type == AL_FILTER_HIGHPASS) { @@ -729,7 +729,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF; filter->LFReference = HIGHPASSFREQREF; - filter->vtbl = &ALhighpass_vtable; + filter->vtab = &ALhighpass_vtable; } else if(type == AL_FILTER_BANDPASS) { @@ -738,7 +738,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF; filter->LFReference = HIGHPASSFREQREF; - filter->vtbl = &ALbandpass_vtable; + filter->vtab = &ALbandpass_vtable; } else { @@ -747,7 +747,7 @@ static void InitFilterParams(ALfilter *filter, ALenum type) filter->HFReference = LOWPASSFREQREF; filter->GainLF = 1.0f; filter->LFReference = HIGHPASSFREQREF; - filter->vtbl = &ALnullfilter_vtable; + filter->vtab = &ALnullfilter_vtable; } filter->type = type; } -- cgit v1.2.3 From d4fc87fc9c2cacb09d9538c410a701a8dd12aa6b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:07:49 -0800 Subject: Avoid calling SDL_GetNumAudioDevices multiple times --- Alc/backends/sdl2.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 9bd42cdf..416e745d 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -207,9 +207,12 @@ static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUS static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type) { + ALCboolean quit = ALC_FALSE; + int num_devices, i; + if(type != ALL_DEVICE_PROBE) return; - ALCboolean quit = ALC_FALSE; + if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? { SDL_Init(SDL_INIT_AUDIO); @@ -217,9 +220,13 @@ static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enu } else if(!SDL_WasInit(SDL_INIT_AUDIO)) SDL_InitSubSystem(SDL_INIT_AUDIO); + + num_devices = SDL_GetNumAudioDevices(SDL_FALSE); + AppendAllDevicesList(defaultDeviceName); - for(int i = 0; i < SDL_GetNumAudioDevices(0); ++i) - AppendAllDevicesList(SDL_GetAudioDeviceName(i, 0)); + for(i = 0; i < num_devices; ++i) + AppendAllDevicesList(SDL_GetAudioDeviceName(i, SDL_FALSE)); + if(quit) SDL_Quit(); } -- cgit v1.2.3 From 52ca70d98e164cb925dcc28fa97ade6fea1bd6ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:12:14 -0800 Subject: Properly close the SDL2 audio device --- Alc/backends/sdl2.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 416e745d..df4324ad 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -42,7 +42,7 @@ typedef struct ALCsdl2Backend { } ALCsdl2Backend; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, Destruct) +static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self); static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name); static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self); static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self); @@ -63,6 +63,7 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); + self->deviceID = 0; self->quit = ALC_FALSE; self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; @@ -76,6 +77,18 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SDL_InitSubSystem(SDL_INIT_AUDIO); } +static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) +{ + if(self->deviceID) + SDL_CloseAudioDevice(self->deviceID); + self->deviceID = 0; + + if(self->quit) + SDL_Quit(); + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + static void ALCsdl2Backend_audioCallback(void *ptr, Uint8* stream, int len) { @@ -166,8 +179,6 @@ static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self) static void ALCsdl2Backend_stop(ALCsdl2Backend *self) { SDL_PauseAudioDevice(self->deviceID, 1); - if(self->quit) - SDL_Quit(); } @@ -224,7 +235,7 @@ static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enu num_devices = SDL_GetNumAudioDevices(SDL_FALSE); AppendAllDevicesList(defaultDeviceName); - for(i = 0; i < num_devices; ++i) + for(i = 0;i < num_devices;++i) AppendAllDevicesList(SDL_GetAudioDeviceName(i, SDL_FALSE)); if(quit) -- cgit v1.2.3 From 58760e6184118e34fe2f8fde28fb7b51d449e8cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:16:10 -0800 Subject: Use the audio device lock for the SDL2 backend --- Alc/backends/sdl2.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index df4324ad..b54fcc4b 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -50,8 +50,8 @@ static void ALCsdl2Backend_stop(ALCsdl2Backend *self); static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples) static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, void, unlock) +static void ALCsdl2Backend_lock(ALCsdl2Backend *self); +static void ALCsdl2Backend_unlock(ALCsdl2Backend *self); DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); @@ -97,10 +97,9 @@ static void ALCsdl2Backend_audioCallback(void *ptr, Uint8* stream, int len) ALsizei frameSize = FrameSizeFromDevFmt( device->FmtChans, device->FmtType, device->AmbiOrder ); + assert(len % frameSize == 0); - ALCsdl2Backend_lock(self); aluMixData(device, stream, len / frameSize); - ALCsdl2Backend_unlock(self); } static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) @@ -181,6 +180,16 @@ static void ALCsdl2Backend_stop(ALCsdl2Backend *self) SDL_PauseAudioDevice(self->deviceID, 1); } +static void ALCsdl2Backend_lock(ALCsdl2Backend *self) +{ + SDL_LockAudioDevice(self->deviceID); +} + +static void ALCsdl2Backend_unlock(ALCsdl2Backend *self) +{ + SDL_UnlockAudioDevice(self->deviceID); +} + typedef struct ALCsdl2BackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); -- cgit v1.2.3 From aa7df8183f5acd81ca2d26b057eb89eccbf85492 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:22:03 -0800 Subject: Also save the update size with SDL2 --- Alc/backends/sdl2.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index b54fcc4b..391b110d 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -36,9 +36,11 @@ typedef struct ALCsdl2Backend { SDL_AudioDeviceID deviceID; ALCboolean quit; + ALuint Frequency; enum DevFmtChannels FmtChans; enum DevFmtType FmtType; + ALuint UpdateSize; } ALCsdl2Backend; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device); @@ -123,11 +125,8 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) ERR("Could not open device\n"); return ALC_INVALID_VALUE; } - if(want.freq != have.freq) - { - TRACE("Frequency changed by SDL2\n"); - device->Frequency = have.freq; - } + + device->Frequency = have.freq; if(have.channels == 1) device->FmtChans = DevFmtMono; else if(have.channels == 2) @@ -149,12 +148,15 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) ERR("Unsupported format\n"); return ALC_INVALID_VALUE; } + device->UpdateSize = have.samples; + device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ + self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; - if(!name) - name = defaultDeviceName; - alstr_copy_cstr(&STATIC_CAST(ALCbackend, self)->mDevice->DeviceName, name); + self->UpdateSize = device->UpdateSize; + + alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName); return ALC_NO_ERROR; } @@ -165,6 +167,8 @@ static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self) device->Frequency = self->Frequency; device->FmtChans = self->FmtChans; device->FmtType = self->FmtType; + device->UpdateSize = self->UpdateSize; + device->NumUpdates = 2; SetDefaultWFXChannelOrder(device); return ALC_TRUE; } -- cgit v1.2.3 From 0c7fa1b955d441a4dc3e87aba8148ed8ade91e2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:53:49 -0800 Subject: Avoid deinitializing backends that never initialized --- Alc/ALc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 554a4951..00c6b6fa 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1075,27 +1075,33 @@ static void alc_initconfig(void) BackendListSize = i; } - for(i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) + for(n = i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++) { - ALCbackendFactory *factory = BackendList[i].getFactory(); + ALCbackendFactory *factory; + BackendList[n] = BackendList[i]; + + factory = BackendList[n].getFactory(); if(!V0(factory,init)()) { - WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name); + WARN("Failed to initialize backend \"%s\"\n", BackendList[n].name); continue; } - TRACE("Initialized backend \"%s\"\n", BackendList[i].name); + TRACE("Initialized backend \"%s\"\n", BackendList[n].name); if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback)) { - PlaybackBackend = BackendList[i]; + PlaybackBackend = BackendList[n]; TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); } if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture)) { - CaptureBackend = BackendList[i]; + CaptureBackend = BackendList[n]; TRACE("Added \"%s\" for capture\n", CaptureBackend.name); } + n++; } + BackendListSize = n; + { ALCbackendFactory *factory = ALCloopbackFactory_getFactory(); V0(factory,init)(); -- cgit v1.2.3 From 2866c6cf280dec63336d2733bc300db9d7bbcce6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 18:59:22 -0800 Subject: Init and quit the SDL2 audio subsystem with the factory --- Alc/backends/sdl2.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 391b110d..27f42129 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -35,7 +35,6 @@ typedef struct ALCsdl2Backend { DERIVE_FROM_TYPE(ALCbackend); SDL_AudioDeviceID deviceID; - ALCboolean quit; ALuint Frequency; enum DevFmtChannels FmtChans; @@ -66,17 +65,10 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); self->deviceID = 0; - self->quit = ALC_FALSE; self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; - if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? - { - SDL_Init(SDL_INIT_AUDIO); - self->quit = ALC_TRUE; - } - else if(!SDL_WasInit(SDL_INIT_AUDIO)) - SDL_InitSubSystem(SDL_INIT_AUDIO); + self->UpdateSize = device->UpdateSize; } static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) @@ -85,9 +77,6 @@ static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) SDL_CloseAudioDevice(self->deviceID); self->deviceID = 0; - if(self->quit) - SDL_Quit(); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -203,7 +192,7 @@ typedef struct ALCsdl2BackendFactory { ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); -static DECLARE_FORWARD(ALCsdl2BackendFactory, ALCbackendFactory, void, deinit) +static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type); static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); @@ -219,7 +208,14 @@ ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void) static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self)) { - return ALC_TRUE; + if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) + return AL_TRUE; + return ALC_FALSE; +} + +static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self)) +{ + SDL_QuitSubSystem(SDL_INIT_AUDIO); } static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type) @@ -231,28 +227,16 @@ static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUS static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type) { - ALCboolean quit = ALC_FALSE; int num_devices, i; if(type != ALL_DEVICE_PROBE) return; - if(SDL_WasInit(0) == 0) // Is SDL2 initialized at all? - { - SDL_Init(SDL_INIT_AUDIO); - quit = ALC_TRUE; - } - else if(!SDL_WasInit(SDL_INIT_AUDIO)) - SDL_InitSubSystem(SDL_INIT_AUDIO); - num_devices = SDL_GetNumAudioDevices(SDL_FALSE); AppendAllDevicesList(defaultDeviceName); for(i = 0;i < num_devices;++i) AppendAllDevicesList(SDL_GetAudioDeviceName(i, SDL_FALSE)); - - if(quit) - SDL_Quit(); } static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -- cgit v1.2.3 From 41cc82e84beff737afbdf2b56ba8f53d8fb04559 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 22:09:30 -0800 Subject: Print the unsupported values from SDL2 --- Alc/backends/sdl2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 27f42129..61076789 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -110,10 +110,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) // device in the list. self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); if(self->deviceID == 0) - { - ERR("Could not open device\n"); return ALC_INVALID_VALUE; - } device->Frequency = have.freq; if(have.channels == 1) @@ -122,7 +119,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) device->FmtChans = DevFmtStereo; else { - ERR("Invalid number of channels\n"); + ERR("Got unhandled SDL channel count: %d\n", (int)have.channels); return ALC_INVALID_VALUE; } switch(have.format) @@ -134,7 +131,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) case AUDIO_S32SYS: device->FmtType = DevFmtInt; break; case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break; default: - ERR("Unsupported format\n"); + ERR("Got unsupported SDL format: 0x%04x\n", have.format); return ALC_INVALID_VALUE; } device->UpdateSize = have.samples; -- cgit v1.2.3 From 46e7e96eb3407405df9999cbb3134a5392c98a08 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 8 Mar 2018 22:23:36 -0800 Subject: Store the frame size for the SDL2 backend --- Alc/backends/sdl2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 61076789..f301cf48 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -35,6 +35,7 @@ typedef struct ALCsdl2Backend { DERIVE_FROM_TYPE(ALCbackend); SDL_AudioDeviceID deviceID; + ALsizei frameSize; ALuint Frequency; enum DevFmtChannels FmtChans; @@ -65,6 +66,7 @@ static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) SET_VTABLE2(ALCsdl2Backend, ALCbackend, self); self->deviceID = 0; + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; @@ -81,16 +83,13 @@ static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self) } -static void ALCsdl2Backend_audioCallback(void *ptr, Uint8* stream, int len) +static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len) { ALCsdl2Backend *self = (ALCsdl2Backend*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALsizei frameSize = FrameSizeFromDevFmt( - device->FmtChans, device->FmtType, device->AmbiOrder - ); - assert(len % frameSize == 0); - aluMixData(device, stream, len / frameSize); + assert((len % self->frameSize) == 0); + aluMixData(device, stream, len / self->frameSize); } static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) @@ -137,6 +136,7 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) device->UpdateSize = have.samples; device->NumUpdates = 2; /* SDL always (tries to) use two periods. */ + self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); self->Frequency = device->Frequency; self->FmtChans = device->FmtChans; self->FmtType = device->FmtType; -- cgit v1.2.3 From 8b242555570b9afe260026721737ae4ba2eef563 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Mar 2018 10:53:03 -0800 Subject: Request the device's sample type for SDL2 --- Alc/backends/sdl2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index f301cf48..2955fb25 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -96,9 +96,21 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; SDL_AudioSpec want, have; + SDL_zero(want); + SDL_zero(have); + want.freq = device->Frequency; - want.format = AUDIO_F32; + switch(device->FmtType) + { + case DevFmtUByte: want.format = AUDIO_U8; break; + case DevFmtByte: want.format = AUDIO_S8; break; + case DevFmtUShort: want.format = AUDIO_U16SYS; break; + case DevFmtShort: want.format = AUDIO_S16SYS; break; + case DevFmtUInt: /* fall-through */ + case DevFmtInt: want.format = AUDIO_S32SYS; break; + case DevFmtFloat: want.format = AUDIO_F32; break; + } want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2; want.samples = device->UpdateSize; want.callback = ALCsdl2Backend_audioCallback; -- cgit v1.2.3 From c0e7a5b8b07132f39e7bf60371586d5d56984e14 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Mar 2018 11:41:28 -0800 Subject: Prefix SDL2 device names on Windows --- Alc/backends/sdl2.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index 2955fb25..cf005024 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -31,6 +31,12 @@ #include "backends/base.h" +#ifdef _WIN32 +#define DEVNAME_PREFIX "OpenAL Soft on " +#else +#define DEVNAME_PREFIX "" +#endif + typedef struct ALCsdl2Backend { DERIVE_FROM_TYPE(ALCbackend); @@ -58,7 +64,7 @@ DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend) DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend); -static const ALCchar defaultDeviceName[] = "Default device"; +static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device"; static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device) { @@ -116,10 +122,22 @@ static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name) want.callback = ALCsdl2Backend_audioCallback; want.userdata = self; - if (name && strcmp(name, defaultDeviceName) == 0) - name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first - // device in the list. - self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE); + /* Passing NULL to SDL_OpenAudioDevice opens a default, which isn't + * necessarily the first in the list. + */ + if(!name || strcmp(name, defaultDeviceName) == 0) + self->deviceID = SDL_OpenAudioDevice(NULL, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + { + const size_t prefix_len = strlen(DEVNAME_PREFIX); + if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0) + self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + else + self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have, + SDL_AUDIO_ALLOW_ANY_CHANGE); + } if(self->deviceID == 0) return ALC_INVALID_VALUE; @@ -237,15 +255,22 @@ static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUS static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type) { int num_devices, i; + al_string name; if(type != ALL_DEVICE_PROBE) return; + AL_STRING_INIT(name); num_devices = SDL_GetNumAudioDevices(SDL_FALSE); AppendAllDevicesList(defaultDeviceName); for(i = 0;i < num_devices;++i) - AppendAllDevicesList(SDL_GetAudioDeviceName(i, SDL_FALSE)); + { + alstr_copy_cstr(&name, DEVNAME_PREFIX); + alstr_append_cstr(&name, SDL_GetAudioDeviceName(i, SDL_FALSE)); + AppendAllDevicesList(alstr_get_cstr(name)); + } + alstr_reset(&name); } static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -- cgit v1.2.3 From 30821e978b69fa017cbcd76e5ff25c62f16b1d2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Mar 2018 17:24:03 -0800 Subject: Add extern "C" to some headers --- Alc/alstring.h | 8 ++++++++ Alc/backends/base.h | 8 ++++++++ Alc/compat.h | 8 ++++++++ Alc/logging.h | 8 ++++++++ Alc/ringbuffer.h | 8 ++++++++ OpenAL32/Include/alMain.h | 34 +++++++++++++++++----------------- 6 files changed, 57 insertions(+), 17 deletions(-) diff --git a/Alc/alstring.h b/Alc/alstring.h index e10811da..923a5ea2 100644 --- a/Alc/alstring.h +++ b/Alc/alstring.h @@ -6,6 +6,10 @@ #include "vector.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef char al_string_char_type; TYPEDEF_VECTOR(al_string_char_type, al_string) TYPEDEF_VECTOR(al_string, vector_al_string) @@ -47,4 +51,8 @@ void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to); void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); #endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* ALSTRING_H */ diff --git a/Alc/backends/base.h b/Alc/backends/base.h index b05523b2..6940a2a2 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -5,6 +5,10 @@ #include "threads.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct ClockLatency { ALint64 ClockTime; ALint64 Latency; @@ -157,4 +161,8 @@ inline void ALCdevice_Lock(ALCdevice *device) inline void ALCdevice_Unlock(ALCdevice *device) { V0(device->Backend,unlock)(); } +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* AL_BACKENDS_BASE_H */ diff --git a/Alc/compat.h b/Alc/compat.h index 6cf2d0d2..093184c8 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -3,6 +3,10 @@ #include "alstring.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -54,4 +58,8 @@ void *GetSymbol(void *handle, const char *name); void *Android_GetJNIEnv(void); #endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* AL_COMPAT_H */ diff --git a/Alc/logging.h b/Alc/logging.h index 18093b75..785771c8 100644 --- a/Alc/logging.h +++ b/Alc/logging.h @@ -10,6 +10,10 @@ #define DECL_FORMAT(x, y, z) #endif +#ifdef __cplusplus +extern "C" { +#endif + extern FILE *LogFile; #if defined(__GNUC__) && !defined(_WIN32) @@ -58,4 +62,8 @@ extern enum LogLevel LogLevel; LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__); \ } while(0) +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* LOGGING_H */ diff --git a/Alc/ringbuffer.h b/Alc/ringbuffer.h index bcf67374..0d05ec84 100644 --- a/Alc/ringbuffer.h +++ b/Alc/ringbuffer.h @@ -4,6 +4,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + typedef struct ll_ringbuffer ll_ringbuffer_t; typedef struct ll_ringbuffer_data { char *buf; @@ -66,4 +70,8 @@ size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); /** Advance the write pointer `cnt' places. */ void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* RINGBUFFER_H */ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 6d6d661f..783a90de 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -49,19 +49,6 @@ #define UNLIKELY(x) (!!(x)) #endif -typedef ALint64SOFT ALint64; -typedef ALuint64SOFT ALuint64; - -#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 @@ -85,6 +72,23 @@ typedef ALuint64SOFT ALuint64; #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N)) +#ifdef __cplusplus +extern "C" { +#endif + +typedef ALint64SOFT ALint64; +typedef ALuint64SOFT ALuint64; + +#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 + /* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result * is *UNDEFINED* if the value is 0. */ @@ -153,10 +157,6 @@ static const union { #define COUNTOF(x) (sizeof(x) / sizeof(0[x])) -#ifdef __cplusplus -extern "C" { -#endif - struct ll_ringbuffer; struct Hrtf; struct HrtfEntry; -- cgit v1.2.3 From a6ddeaf5f190a3640f816a4767ffa8b10fbd1b5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 9 Mar 2018 18:56:24 -0800 Subject: Rename the mmdevapi backend to wasapi --- Alc/ALc.c | 14 +- Alc/backends/base.h | 2 +- Alc/backends/mmdevapi.c | 2054 ------------------------------------ Alc/backends/wasapi.c | 2049 +++++++++++++++++++++++++++++++++++ Alc/helpers.c | 2 +- CMakeLists.txt | 20 +- alsoftrc.sample | 4 +- appveyor.yml | 2 +- config.h.in | 4 +- utils/alsoft-config/mainwindow.cpp | 13 +- 10 files changed, 2089 insertions(+), 2075 deletions(-) delete mode 100644 Alc/backends/mmdevapi.c create mode 100644 Alc/backends/wasapi.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 00c6b6fa..8a2f67aa 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -85,8 +85,8 @@ static struct BackendInfo BackendList[] = { #ifdef HAVE_QSA { "qsa", ALCqsaBackendFactory_getFactory }, #endif -#ifdef HAVE_MMDEVAPI - { "mmdevapi", ALCmmdevBackendFactory_getFactory }, +#ifdef HAVE_WASAPI + { "wasapi", ALCwasapiBackendFactory_getFactory }, #endif #ifdef HAVE_DSOUND { "dsound", ALCdsoundBackendFactory_getFactory }, @@ -1046,6 +1046,16 @@ static void alc_initconfig(void) len = (next ? ((size_t)(next-devs)) : strlen(devs)); while(len > 0 && isspace(devs[len-1])) len--; +#ifdef HAVE_WASAPI + /* HACK: For backwards compatibility, convert backend references of + * mmdevapi to wasapi. This should eventually be removed. + */ + if(len == 8 && strncmp(devs, "mmdevapi", len) == 0) + { + devs = "wasapi"; + len = 6; + } +#endif for(n = i;n < BackendListSize;n++) { if(len == strlen(BackendList[n].name) && diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 6940a2a2..ba92b4ac 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -144,7 +144,7 @@ ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); ALCbackendFactory *ALCqsaBackendFactory_getFactory(void); -ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); +ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); ALCbackendFactory *ALCportBackendFactory_getFactory(void); diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c deleted file mode 100644 index 961cba52..00000000 --- a/Alc/backends/mmdevapi.c +++ /dev/null @@ -1,2054 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#define COBJMACROS -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef _WAVEFORMATEXTENSIBLE_ -#include -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "ringbuffer.h" -#include "threads.h" -#include "compat.h" -#include "alstring.h" -#include "converter.h" - -#include "backends/base.h" - - -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); - -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); -DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); - -#define MONO SPEAKER_FRONT_CENTER -#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) -#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) -#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) - -#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) - -#define DEVNAME_HEAD "OpenAL Soft on " - - -/* Scales the given value using 64-bit integer math, ceiling the result. */ -static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) -{ - return (val*new_scale + old_scale-1) / old_scale; -} - - -typedef struct { - al_string name; - al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. - WCHAR *devid; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) - -static void clear_devlist(vector_DevMap *list) -{ -#define CLEAR_DEVMAP(i) do { \ - AL_STRING_DEINIT((i)->name); \ - AL_STRING_DEINIT((i)->endpoint_guid); \ - free((i)->devid); \ - (i)->devid = NULL; \ -} while(0) - VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); - VECTOR_RESIZE(*list, 0, 0); -#undef CLEAR_DEVMAP -} - -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; - - -static HANDLE ThreadHdl; -static DWORD ThreadID; - -typedef struct { - HANDLE FinishedEvt; - HRESULT result; -} ThreadRequest; - -#define WM_USER_First (WM_USER+0) -#define WM_USER_OpenDevice (WM_USER+0) -#define WM_USER_ResetDevice (WM_USER+1) -#define WM_USER_StartDevice (WM_USER+2) -#define WM_USER_StopDevice (WM_USER+3) -#define WM_USER_CloseDevice (WM_USER+4) -#define WM_USER_Enumerate (WM_USER+5) -#define WM_USER_Last (WM_USER+5) - -static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { - "Open Device", - "Reset Device", - "Start Device", - "Stop Device", - "Close Device", - "Enumerate Devices", -}; - -static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res) -{ - req->result = res; - SetEvent(req->FinishedEvt); -} - -static HRESULT WaitForResponse(ThreadRequest *req) -{ - if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0) - return req->result; - ERR("Message response error: %lu\n", GetLastError()); - return E_FAIL; -} - - -static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) -{ - IPropertyStore *ps; - PROPVARIANT pvname; - PROPVARIANT pvguid; - HRESULT hr; - - alstr_copy_cstr(name, DEVNAME_HEAD); - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); - if(guid!=NULL)alstr_copy_cstr(guid, "Unknown Device GUID"); - return; - } - - PropVariantInit(&pvname); - - hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); - if(FAILED(hr)) - { - WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); - alstr_append_cstr(name, "Unknown Device Name"); - } - else if(pvname.vt == VT_LPWSTR) - alstr_append_wcstr(name, pvname.pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); - alstr_append_cstr(name, "Unknown Device Name"); - } - PropVariantClear(&pvname); - - if(guid!=NULL){ - PropVariantInit(&pvguid); - - hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pvguid); - if(FAILED(hr)) - { - WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } - else if(pvguid.vt == VT_LPWSTR) - alstr_copy_wcstr(guid, pvguid.pwszVal); - else - { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); - alstr_copy_cstr(guid, "Unknown Device GUID"); - } - - PropVariantClear(&pvguid); - } - - IPropertyStore_Release(ps); -} - -static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) -{ - IPropertyStore *ps; - PROPVARIANT pvform; - HRESULT hr; - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); - if(FAILED(hr)) - { - WARN("OpenPropertyStore failed: 0x%08lx\n", hr); - return; - } - - PropVariantInit(&pvform); - - hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform); - if(FAILED(hr)) - WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); - else if(pvform.vt == VT_UI4) - *formfactor = pvform.ulVal; - else if(pvform.vt == VT_EMPTY) - *formfactor = UnknownFormFactor; - else - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); - - PropVariantClear(&pvform); - IPropertyStore_Release(ps); -} - - -static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) -{ - int count = 0; - al_string tmpname; - DevMap entry; - - AL_STRING_INIT(tmpname); - AL_STRING_INIT(entry.name); - AL_STRING_INIT(entry.endpoint_guid); - - entry.devid = strdupW(devid); - get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); - - while(1) - { - const DevMap *iter; - - alstr_copy(&entry.name, tmpname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); - alstr_append_cstr(&entry.name, str); - } - -#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) - VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); - if(iter == VECTOR_END(*list)) break; -#undef MATCH_ENTRY - count++; - } - - TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); - VECTOR_PUSH_BACK(*list, entry); - - AL_STRING_DEINIT(tmpname); -} - -static WCHAR *get_device_id(IMMDevice *device) -{ - WCHAR *devid; - HRESULT hr; - - hr = IMMDevice_GetId(device, &devid); - if(FAILED(hr)) - { - ERR("Failed to get device id: %lx\n", hr); - return NULL; - } - - return devid; -} - -static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) -{ - IMMDeviceCollection *coll; - IMMDevice *defdev = NULL; - WCHAR *defdevid = NULL; - HRESULT hr; - UINT count; - UINT i; - - hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll); - if(FAILED(hr)) - { - ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); - return hr; - } - - count = 0; - hr = IMMDeviceCollection_GetCount(coll, &count); - if(SUCCEEDED(hr) && count > 0) - { - clear_devlist(list); - VECTOR_RESIZE(*list, 0, count); - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, - eMultimedia, &defdev); - } - if(SUCCEEDED(hr) && defdev != NULL) - { - defdevid = get_device_id(defdev); - if(defdevid) - add_device(defdev, defdevid, list); - } - - for(i = 0;i < count;++i) - { - IMMDevice *device; - WCHAR *devid; - - hr = IMMDeviceCollection_Item(coll, i, &device); - if(FAILED(hr)) continue; - - devid = get_device_id(device); - if(devid) - { - if(wcscmp(devid, defdevid) != 0) - add_device(device, devid, list); - CoTaskMemFree(devid); - } - IMMDevice_Release(device); - } - - if(defdev) IMMDevice_Release(defdev); - if(defdevid) CoTaskMemFree(defdevid); - IMMDeviceCollection_Release(coll); - - return S_OK; -} - - -/* Proxy interface used by the message handler. */ -struct ALCmmdevProxyVtable; - -typedef struct ALCmmdevProxy { - const struct ALCmmdevProxyVtable *vtbl; -} ALCmmdevProxy; - -struct ALCmmdevProxyVtable { - HRESULT (*const openProxy)(ALCmmdevProxy*); - void (*const closeProxy)(ALCmmdevProxy*); - - HRESULT (*const resetProxy)(ALCmmdevProxy*); - HRESULT (*const startProxy)(ALCmmdevProxy*); - void (*const stopProxy)(ALCmmdevProxy*); -}; - -#define DEFINE_ALCMMDEVPROXY_VTABLE(T) \ -DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, openProxy) \ -DECLARE_THUNK(T, ALCmmdevProxy, void, closeProxy) \ -DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, resetProxy) \ -DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, startProxy) \ -DECLARE_THUNK(T, ALCmmdevProxy, void, stopProxy) \ - \ -static const struct ALCmmdevProxyVtable T##_ALCmmdevProxy_vtable = { \ - T##_ALCmmdevProxy_openProxy, \ - T##_ALCmmdevProxy_closeProxy, \ - T##_ALCmmdevProxy_resetProxy, \ - T##_ALCmmdevProxy_startProxy, \ - T##_ALCmmdevProxy_stopProxy, \ -} - -static void ALCmmdevProxy_Construct(ALCmmdevProxy* UNUSED(self)) { } -static void ALCmmdevProxy_Destruct(ALCmmdevProxy* UNUSED(self)) { } - -static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr) -{ - ThreadRequest *req = ptr; - IMMDeviceEnumerator *Enumerator; - ALuint deviceCount = 0; - ALCmmdevProxy *proxy; - HRESULT hr, cohr; - MSG msg; - - TRACE("Starting message thread\n"); - - cohr = CoInitialize(NULL); - if(FAILED(cohr)) - { - WARN("Failed to initialize COM: 0x%08lx\n", cohr); - ReturnMsgResponse(req, cohr); - return 0; - } - - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); - if(FAILED(hr)) - { - WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); - CoUninitialize(); - ReturnMsgResponse(req, hr); - return 0; - } - Enumerator = ptr; - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; - - CoUninitialize(); - - /* HACK: Force Windows to create a message queue for this thread before - * returning success, otherwise PostThreadMessage may fail if it gets - * called before GetMessage. - */ - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - - TRACE("Message thread initialization complete\n"); - ReturnMsgResponse(req, S_OK); - - TRACE("Starting message loop\n"); - while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last)) - { - TRACE("Got message \"%s\" (0x%04x, lparam=%p, wparam=%p)\n", - (msg.message >= WM_USER && msg.message <= WM_USER_Last) ? - MessageStr[msg.message-WM_USER] : "Unknown", - msg.message, (void*)msg.lParam, (void*)msg.wParam - ); - switch(msg.message) - { - case WM_USER_OpenDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCmmdevProxy*)msg.lParam; - - hr = cohr = S_OK; - if(++deviceCount == 1) - hr = cohr = CoInitialize(NULL); - if(SUCCEEDED(hr)) - hr = V0(proxy,openProxy)(); - if(FAILED(hr)) - { - if(--deviceCount == 0 && SUCCEEDED(cohr)) - CoUninitialize(); - } - - ReturnMsgResponse(req, hr); - continue; - - case WM_USER_ResetDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCmmdevProxy*)msg.lParam; - - hr = V0(proxy,resetProxy)(); - ReturnMsgResponse(req, hr); - continue; - - case WM_USER_StartDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCmmdevProxy*)msg.lParam; - - hr = V0(proxy,startProxy)(); - ReturnMsgResponse(req, hr); - continue; - - case WM_USER_StopDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCmmdevProxy*)msg.lParam; - - V0(proxy,stopProxy)(); - ReturnMsgResponse(req, S_OK); - continue; - - case WM_USER_CloseDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCmmdevProxy*)msg.lParam; - - V0(proxy,closeProxy)(); - if(--deviceCount == 0) - CoUninitialize(); - - ReturnMsgResponse(req, S_OK); - continue; - - case WM_USER_Enumerate: - req = (ThreadRequest*)msg.wParam; - - hr = cohr = S_OK; - if(++deviceCount == 1) - hr = cohr = CoInitialize(NULL); - if(SUCCEEDED(hr)) - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); - if(SUCCEEDED(hr)) - { - Enumerator = ptr; - - if(msg.lParam == ALL_DEVICE_PROBE) - hr = probe_devices(Enumerator, eRender, &PlaybackDevices); - else if(msg.lParam == CAPTURE_DEVICE_PROBE) - hr = probe_devices(Enumerator, eCapture, &CaptureDevices); - - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; - } - - if(--deviceCount == 0 && SUCCEEDED(cohr)) - CoUninitialize(); - - ReturnMsgResponse(req, hr); - continue; - - default: - ERR("Unexpected message: %u\n", msg.message); - continue; - } - } - TRACE("Message loop finished\n"); - - return 0; -} - - -typedef struct ALCmmdevPlayback { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCmmdevProxy); - - WCHAR *devid; - - IMMDevice *mmdev; - IAudioClient *client; - IAudioRenderClient *render; - HANDLE NotifyEvent; - - HANDLE MsgEvent; - - ATOMIC(UINT32) Padding; - - ATOMIC(int) killNow; - althrd_t thread; -} ALCmmdevPlayback; - -static int ALCmmdevPlayback_mixerProc(void *arg); - -static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device); -static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self); -static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *name); -static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self); -static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self); -static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self); -static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self); -static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self); -static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self); -static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self); -static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self); -static DECLARE_FORWARD2(ALCmmdevPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) -static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, ALCuint, availableSamples) -static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self); -static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCmmdevPlayback) - -DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevPlayback); -DEFINE_ALCBACKEND_VTABLE(ALCmmdevPlayback); - - -static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device) -{ - SET_VTABLE2(ALCmmdevPlayback, ALCbackend, self); - SET_VTABLE2(ALCmmdevPlayback, ALCmmdevProxy, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self)); - - self->devid = NULL; - - self->mmdev = NULL; - self->client = NULL; - self->render = NULL; - self->NotifyEvent = NULL; - - self->MsgEvent = NULL; - - ATOMIC_INIT(&self->Padding, 0); - - ATOMIC_INIT(&self->killNow, 0); -} - -static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self) -{ - if(self->MsgEvent) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - } - - if(self->NotifyEvent) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - free(self->devid); - self->devid = NULL; - - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - - free(self->devid); - self->devid = NULL; - - ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self)); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) -{ - ALCmmdevPlayback *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - UINT32 buffer_len, written; - ALuint update_size, len; - BYTE *buffer; - HRESULT hr; - - hr = CoInitialize(NULL); - if(FAILED(hr)) - { - ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); - return 1; - } - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - update_size = device->UpdateSize; - buffer_len = update_size * device->NumUpdates; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) - { - hr = IAudioClient_GetCurrentPadding(self->client, &written); - if(FAILED(hr)) - { - ERR("Failed to get padding: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); - - len = buffer_len - written; - if(len < update_size) - { - DWORD res; - res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - continue; - } - len -= len%update_size; - - hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer); - if(SUCCEEDED(hr)) - { - ALCmmdevPlayback_lock(self); - aluMixData(device, buffer, len); - ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); - ALCmmdevPlayback_unlock(self); - hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); - } - if(FAILED(hr)) - { - ERR("Failed to buffer data: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - } - ATOMIC_STORE(&self->Padding, 0, almemory_order_release); - - CoUninitialize(); - return 0; -} - - -static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) -{ - memset(out, 0, sizeof(*out)); - if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - *out = *(const WAVEFORMATEXTENSIBLE*)in; - else if(in->wFormatTag == WAVE_FORMAT_PCM) - { - out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - out->Format = *in; - out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - out->Format.cbSize = sizeof(*out) - sizeof(*in); - if(out->Format.nChannels == 1) - out->dwChannelMask = MONO; - else if(out->Format.nChannels == 2) - out->dwChannelMask = STEREO; - else - ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); - out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else - { - ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); - return ALC_FALSE; - } - return ALC_TRUE; -} - -static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName) -{ - HRESULT hr = S_OK; - - self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if(self->NotifyEvent == NULL || self->MsgEvent == NULL) - { - ERR("Failed to create message events: %lu\n", GetLastError()); - hr = E_FAIL; - } - - if(SUCCEEDED(hr)) - { - if(deviceName) - { - const DevMap *iter; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) - (void)WaitForResponse(&req); - } - - hr = E_FAIL; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(PlaybackDevices)) - { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) - { - WCHAR *wname = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) - VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); -#undef MATCH_NAME - free(wname); - } - } - if(iter == VECTOR_END(PlaybackDevices)) - WARN("Failed to find device name matching \"%s\"\n", deviceName); - else - { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - else - ERR("Failed to post thread message: %lu\n", GetLastError()); - } - - if(FAILED(hr)) - { - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - - free(self->devid); - self->devid = NULL; - - ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; - } - - return ALC_NO_ERROR; -} - -static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - void *ptr; - HRESULT hr; - - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); - if(SUCCEEDED(hr)) - { - IMMDeviceEnumerator *Enumerator = ptr; - if(!self->devid) - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &self->mmdev); - else - hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; - } - if(SUCCEEDED(hr)) - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); - if(SUCCEEDED(hr)) - { - self->client = ptr; - if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); - } - - if(FAILED(hr)) - { - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; - } - - return hr; -} - - -static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self) -{ - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; -} - - -static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - EndpointFormFactor formfactor = UnknownFormFactor; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = NULL; - REFERENCE_TIME min_per, buf_time; - UINT32 buffer_len, min_len; - void *ptr = NULL; - HRESULT hr; - - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); - if(FAILED(hr)) - { - ERR("Failed to reactivate audio client: 0x%08lx\n", hr); - return hr; - } - self->client = ptr; - - hr = IAudioClient_GetMixFormat(self->client, &wfx); - if(FAILED(hr)) - { - ERR("Failed to get mix format: 0x%08lx\n", hr); - return hr; - } - - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); - - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - device->Frequency = OutputType.Format.nSamplesPerSec; - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - { - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; - else - ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - } - - switch(device->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtAmbi3D: - device->FmtChans = DevFmtStereo; - /*fall-through*/ - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - } - switch(device->FmtType) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - /* fall-through */ - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.Samples.wValidBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.Samples.wValidBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - /* fall-through */ - case DevFmtInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.Samples.wValidBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Format.nSamplesPerSec = device->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - - hr = IAudioClient_IsFormatSupported(self->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); - if(FAILED(hr)) - { - ERR("Failed to check format support: 0x%08lx\n", hr); - hr = IAudioClient_GetMixFormat(self->client, &wfx); - } - if(FAILED(hr)) - { - ERR("Failed to find a supported format: 0x%08lx\n", hr); - return hr; - } - - if(wfx != NULL) - { - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - - device->Frequency = OutputType.Format.nSamplesPerSec; - if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) - device->FmtChans = DevFmtMono; - else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) - device->FmtChans = DevFmtStereo; - else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) - device->FmtChans = DevFmtQuad; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) - device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) - device->FmtChans = DevFmtX51Rear; - else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) - device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) - device->FmtChans = DevFmtX71; - else - { - ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); - device->FmtChans = DevFmtStereo; - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - } - - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - device->FmtType = DevFmtInt; - else - { - device->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; - } - } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - device->FmtType = DevFmtFloat; - OutputType.Format.wBitsPerSample = 32; - } - else - { - ERR("Unhandled format sub-type\n"); - device->FmtType = DevFmtShort; - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - } - get_device_formfactor(self->mmdev, &formfactor); - device->IsHeadphones = (device->FmtChans == DevFmtStereo && - (formfactor == Headphones || formfactor == Headset) - ); - - SetDefaultWFXChannelOrder(device); - - hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL); - if(SUCCEEDED(hr)) - { - min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); - /* Find the nearest multiple of the period size to the update size */ - if(min_len < device->UpdateSize) - min_len *= (device->UpdateSize + min_len/2)/min_len; - hr = IAudioClient_GetBufferSize(self->client, &buffer_len); - } - if(FAILED(hr)) - { - ERR("Failed to get audio buffer info: 0x%08lx\n", hr); - return hr; - } - - device->UpdateSize = min_len; - device->NumUpdates = buffer_len / device->UpdateSize; - if(device->NumUpdates <= 1) - { - ERR("Audio client returned buffer_len < period*2; expect break up\n"); - device->NumUpdates = 2; - device->UpdateSize = buffer_len / device->NumUpdates; - } - - hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); - if(FAILED(hr)) - { - ERR("Failed to set event handle: 0x%08lx\n", hr); - return hr; - } - - return hr; -} - - -static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self) -{ - HRESULT hr; - void *ptr; - - ResetEvent(self->NotifyEvent); - hr = IAudioClient_Start(self->client); - if(FAILED(hr)) - ERR("Failed to start audio client: 0x%08lx\n", hr); - - if(SUCCEEDED(hr)) - hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr); - if(SUCCEEDED(hr)) - { - self->render = ptr; - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCmmdevPlayback_mixerProc, self) != althrd_success) - { - if(self->render) - IAudioRenderClient_Release(self->render); - self->render = NULL; - IAudioClient_Stop(self->client); - ERR("Failed to start thread\n"); - hr = E_FAIL; - } - } - - return hr; -} - - -static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); -} - -static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self) -{ - int res; - - if(!self->render) - return; - - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); - - IAudioRenderClient_Release(self->render); - self->render = NULL; - IAudioClient_Stop(self->client); -} - - -static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ClockLatency ret; - - ALCmmdevPlayback_lock(self); - ret.ClockTime = GetDeviceClockTime(device); - ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / - device->Frequency; - ALCmmdevPlayback_unlock(self); - - return ret; -} - - -typedef struct ALCmmdevCapture { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCmmdevProxy); - - WCHAR *devid; - - IMMDevice *mmdev; - IAudioClient *client; - IAudioCaptureClient *capture; - HANDLE NotifyEvent; - - HANDLE MsgEvent; - - ChannelConverter *ChannelConv; - SampleConverter *SampleConv; - ll_ringbuffer_t *Ring; - - ATOMIC(int) killNow; - althrd_t thread; -} ALCmmdevCapture; - -static int ALCmmdevCapture_recordProc(void *arg); - -static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device); -static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self); -static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name); -static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self); -static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self); -static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALCboolean, reset) -static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self); -static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self); -static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self); -static void ALCmmdevCapture_stop(ALCmmdevCapture *self); -static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self); -static ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples); -static ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self); -static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture) - -DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture); -DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture); - - -static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) -{ - SET_VTABLE2(ALCmmdevCapture, ALCbackend, self); - SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self); - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self)); - - self->devid = NULL; - - self->mmdev = NULL; - self->client = NULL; - self->capture = NULL; - self->NotifyEvent = NULL; - - self->MsgEvent = NULL; - - self->ChannelConv = NULL; - self->SampleConv = NULL; - self->Ring = NULL; - - ATOMIC_INIT(&self->killNow, 0); -} - -static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) -{ - if(self->MsgEvent) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); - - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - } - - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; - - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); - - free(self->devid); - self->devid = NULL; - - ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self)); - ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); -} - - -FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) -{ - ALCmmdevCapture *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALfloat *samples = NULL; - size_t samplesmax = 0; - HRESULT hr; - - hr = CoInitialize(NULL); - if(FAILED(hr)) - { - ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); - V0(device->Backend,unlock)(); - return 1; - } - - althrd_setname(althrd_current(), RECORD_THREAD_NAME); - - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) - { - UINT32 avail; - DWORD res; - - hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); - if(FAILED(hr)) - ERR("Failed to get next packet size: 0x%08lx\n", hr); - else if(avail > 0) - { - UINT32 numsamples; - DWORD flags; - BYTE *rdata; - - hr = IAudioCaptureClient_GetBuffer(self->capture, - &rdata, &numsamples, &flags, NULL, NULL - ); - if(FAILED(hr)) - ERR("Failed to get capture buffer: 0x%08lx\n", hr); - else - { - ll_ringbuffer_data_t data[2]; - size_t dstframes = 0; - - if(self->ChannelConv) - { - if(samplesmax < numsamples) - { - size_t newmax = RoundUp(numsamples, 4096); - ALfloat *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); - al_free(samples); - samples = tmp; - samplesmax = newmax; - } - ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); - rdata = (BYTE*)samples; - } - - ll_ringbuffer_get_write_vector(self->Ring, data); - - if(self->SampleConv) - { - const ALvoid *srcdata = rdata; - ALsizei srcframes = numsamples; - - dstframes = SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) - ); - if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) - { - /* If some source samples remain, all of the first dest - * block was filled, and there's space in the second - * dest block, do another run for the second block. - */ - dstframes += SampleConverterInput(self->SampleConv, - &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) - ); - } - } - else - { - ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, - device->AmbiOrder); - size_t len1 = minz(data[0].len, numsamples); - size_t len2 = minz(data[1].len, numsamples-len1); - - memcpy(data[0].buf, rdata, len1*framesize); - if(len2 > 0) - memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); - dstframes = len1 + len2; - } - - ll_ringbuffer_write_advance(self->Ring, dstframes); - - hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); - if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); - } - } - - if(FAILED(hr)) - { - V0(device->Backend,lock)(); - aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); - V0(device->Backend,unlock)(); - break; - } - - res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); - if(res != WAIT_OBJECT_0) - ERR("WaitForSingleObjectEx error: 0x%lx\n", res); - } - - al_free(samples); - samples = NULL; - samplesmax = 0; - - CoUninitialize(); - return 0; -} - - -static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName) -{ - HRESULT hr = S_OK; - - self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if(self->NotifyEvent == NULL || self->MsgEvent == NULL) - { - ERR("Failed to create message events: %lu\n", GetLastError()); - hr = E_FAIL; - } - - if(SUCCEEDED(hr)) - { - if(deviceName) - { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) - { - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) - (void)WaitForResponse(&req); - } - - hr = E_FAIL; -#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ - alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - if(iter == VECTOR_END(CaptureDevices)) - { - int len; - if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) - { - WCHAR *wname = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); -#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) - VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); -#undef MATCH_NAME - free(wname); - } - } - if(iter == VECTOR_END(CaptureDevices)) - WARN("Failed to find device name matching \"%s\"\n", deviceName); - else - { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - self->devid = strdupW(iter->devid); - alstr_copy(&device->DeviceName, iter->name); - hr = S_OK; - } - } - } - - if(SUCCEEDED(hr)) - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - else - ERR("Failed to post thread message: %lu\n", GetLastError()); - } - - if(FAILED(hr)) - { - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; - - free(self->devid); - self->devid = NULL; - - ERR("Device init failed: 0x%08lx\n", hr); - return ALC_INVALID_VALUE; - } - else - { - ThreadRequest req = { self->MsgEvent, 0 }; - - hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - else - ERR("Failed to post thread message: %lu\n", GetLastError()); - - if(FAILED(hr)) - { - if(hr == E_OUTOFMEMORY) - return ALC_OUT_OF_MEMORY; - return ALC_INVALID_VALUE; - } - } - - return ALC_NO_ERROR; -} - -static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - void *ptr; - HRESULT hr; - - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); - if(SUCCEEDED(hr)) - { - IMMDeviceEnumerator *Enumerator = ptr; - if(!self->devid) - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev); - else - hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; - } - if(SUCCEEDED(hr)) - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); - if(SUCCEEDED(hr)) - { - self->client = ptr; - if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); - } - - if(FAILED(hr)) - { - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; - } - - return hr; -} - - -static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self) -{ - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; -} - - -static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - WAVEFORMATEXTENSIBLE OutputType; - WAVEFORMATEX *wfx = NULL; - enum DevFmtType srcType; - REFERENCE_TIME buf_time; - UINT32 buffer_len; - void *ptr = NULL; - HRESULT hr; - - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; - - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); - if(FAILED(hr)) - { - ERR("Failed to reactivate audio client: 0x%08lx\n", hr); - return hr; - } - self->client = ptr; - - buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, - device->Frequency); - // Make sure buffer is at least 100ms in size - buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); - device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / - device->NumUpdates; - - OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - switch(device->FmtChans) - { - case DevFmtMono: - OutputType.Format.nChannels = 1; - OutputType.dwChannelMask = MONO; - break; - case DevFmtStereo: - OutputType.Format.nChannels = 2; - OutputType.dwChannelMask = STEREO; - break; - case DevFmtQuad: - OutputType.Format.nChannels = 4; - OutputType.dwChannelMask = QUAD; - break; - case DevFmtX51: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1; - break; - case DevFmtX51Rear: - OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1REAR; - break; - case DevFmtX61: - OutputType.Format.nChannels = 7; - OutputType.dwChannelMask = X6DOT1; - break; - case DevFmtX71: - OutputType.Format.nChannels = 8; - OutputType.dwChannelMask = X7DOT1; - break; - - case DevFmtAmbi3D: - return E_FAIL; - } - switch(device->FmtType) - { - /* NOTE: Signedness doesn't matter, the converter will handle it. */ - case DevFmtByte: - case DevFmtUByte: - OutputType.Format.wBitsPerSample = 8; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtShort: - case DevFmtUShort: - OutputType.Format.wBitsPerSample = 16; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtInt: - case DevFmtUInt: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - break; - case DevFmtFloat: - OutputType.Format.wBitsPerSample = 32; - OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - break; - } - OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; - OutputType.Format.nSamplesPerSec = device->Frequency; - - OutputType.Format.nBlockAlign = OutputType.Format.nChannels * - OutputType.Format.wBitsPerSample / 8; - OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * - OutputType.Format.nBlockAlign; - OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); - - hr = IAudioClient_IsFormatSupported(self->client, - AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx - ); - if(FAILED(hr)) - { - ERR("Failed to check format support: 0x%08lx\n", hr); - return hr; - } - - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); - - if(wfx != NULL) - { - if(!(wfx->nChannels == OutputType.Format.nChannels || - (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || - (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) - { - ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, - wfx->nSamplesPerSec); - CoTaskMemFree(wfx); - return E_FAIL; - } - - if(!MakeExtensible(&OutputType, wfx)) - { - CoTaskMemFree(wfx); - return E_FAIL; - } - CoTaskMemFree(wfx); - wfx = NULL; - } - - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) - { - if(OutputType.Format.wBitsPerSample == 8) - srcType = DevFmtUByte; - else if(OutputType.Format.wBitsPerSample == 16) - srcType = DevFmtShort; - else if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtInt; - else - { - ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) - { - if(OutputType.Format.wBitsPerSample == 32) - srcType = DevFmtFloat; - else - { - ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); - return E_FAIL; - } - } - else - { - ERR("Unhandled format sub-type\n"); - return E_FAIL; - } - - if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) - { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, - device->FmtChans); - if(!self->ChannelConv) - { - ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); - /* The channel converter always outputs float, so change the input type - * for the resampler/type-converter. - */ - srcType = DevFmtFloat; - } - else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) - { - self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, - device->FmtChans); - if(!self->ChannelConv) - { - ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - return E_FAIL; - } - TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); - srcType = DevFmtFloat; - } - - if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) - { - self->SampleConv = CreateSampleConverter( - srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), - OutputType.Format.nSamplesPerSec, device->Frequency - ); - if(!self->SampleConv) - { - ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - return E_FAIL; - } - TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); - } - - hr = IAudioClient_Initialize(self->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL - ); - if(FAILED(hr)) - { - ERR("Failed to initialize audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetBufferSize(self->client, &buffer_len); - if(FAILED(hr)) - { - ERR("Failed to get buffer size: 0x%08lx\n", hr); - return hr; - } - - buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); - ll_ringbuffer_free(self->Ring); - self->Ring = ll_ringbuffer_create(buffer_len, - FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), - false - ); - if(!self->Ring) - { - ERR("Failed to allocate capture ring buffer\n"); - return E_OUTOFMEMORY; - } - - hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); - if(FAILED(hr)) - { - ERR("Failed to set event handle: 0x%08lx\n", hr); - return hr; - } - - return hr; -} - - -static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; - - if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - hr = WaitForResponse(&req); - - return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; -} - -static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self) -{ - HRESULT hr; - void *ptr; - - ResetEvent(self->NotifyEvent); - hr = IAudioClient_Start(self->client); - if(FAILED(hr)) - { - ERR("Failed to start audio client: 0x%08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr); - if(SUCCEEDED(hr)) - { - self->capture = ptr; - ATOMIC_STORE(&self->killNow, 0, almemory_order_release); - if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success) - { - ERR("Failed to start thread\n"); - IAudioCaptureClient_Release(self->capture); - self->capture = NULL; - hr = E_FAIL; - } - } - - if(FAILED(hr)) - { - IAudioClient_Stop(self->client); - IAudioClient_Reset(self->client); - } - - return hr; -} - - -static void ALCmmdevCapture_stop(ALCmmdevCapture *self) -{ - ThreadRequest req = { self->MsgEvent, 0 }; - if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) - (void)WaitForResponse(&req); -} - -static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self) -{ - int res; - - if(!self->capture) - return; - - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); - - IAudioCaptureClient_Release(self->capture); - self->capture = NULL; - IAudioClient_Stop(self->client); - IAudioClient_Reset(self->client); -} - - -ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self) -{ - return (ALuint)ll_ringbuffer_read_space(self->Ring); -} - -ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples) -{ - if(ALCmmdevCapture_availableSamples(self) < samples) - return ALC_INVALID_VALUE; - ll_ringbuffer_read(self->Ring, buffer, samples); - return ALC_NO_ERROR; -} - - -static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } -static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } - -typedef struct ALCmmdevBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCmmdevBackendFactory; -#define ALCMMDEVBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCmmdevBackendFactory, ALCbackendFactory) } } - -static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory *self); -static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory *self); -static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory *self, ALCbackend_Type type); -static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory *self, enum DevProbe type); -static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCmmdevBackendFactory); - - -static BOOL MMDevApiLoad(void) -{ - static HRESULT InitResult; - if(!ThreadHdl) - { - ThreadRequest req; - InitResult = E_FAIL; - - req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); - if(req.FinishedEvt == NULL) - ERR("Failed to create event: %lu\n", GetLastError()); - else - { - ThreadHdl = CreateThread(NULL, 0, ALCmmdevProxy_messageHandler, &req, 0, &ThreadID); - if(ThreadHdl != NULL) - InitResult = WaitForResponse(&req); - CloseHandle(req.FinishedEvt); - } - } - return SUCCEEDED(InitResult); -} - -static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory* UNUSED(self)) -{ - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - - if(!MMDevApiLoad()) - return ALC_FALSE; - return ALC_TRUE; -} - -static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self)) -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); - - if(ThreadHdl) - { - TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); - PostThreadMessage(ThreadID, WM_QUIT, 0, 0); - CloseHandle(ThreadHdl); - ThreadHdl = NULL; - } -} - -static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type) -{ - /* TODO: Disable capture with mmdevapi for now, since it doesn't do any - * rechanneling or resampling; if the device is configured for 48000hz - * stereo input, for example, and the app asks for 22050hz mono, - * initialization will fail. - */ - if(type == ALCbackend_Playback || type == ALCbackend_Capture) - return ALC_TRUE; - return ALC_FALSE; -} - -static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory* UNUSED(self), enum DevProbe type) -{ - ThreadRequest req = { NULL, 0 }; - - req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); - if(req.FinishedEvt == NULL) - ERR("Failed to create event: %lu\n", GetLastError()); - else - { - HRESULT hr = E_FAIL; - if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type)) - hr = WaitForResponse(&req); - if(SUCCEEDED(hr)) switch(type) - { - case ALL_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); - break; - - case CAPTURE_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); - break; - } - CloseHandle(req.FinishedEvt); - req.FinishedEvt = NULL; - } -} - -static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) -{ - if(type == ALCbackend_Playback) - { - ALCmmdevPlayback *backend; - NEW_OBJ(backend, ALCmmdevPlayback)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - if(type == ALCbackend_Capture) - { - ALCmmdevCapture *backend; - NEW_OBJ(backend, ALCmmdevCapture)(device); - if(!backend) return NULL; - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} - - -ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void) -{ - static ALCmmdevBackendFactory factory = ALCMMDEVBACKENDFACTORY_INITIALIZER; - return STATIC_CAST(ALCbackendFactory, &factory); -} diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c new file mode 100644 index 00000000..b64e260b --- /dev/null +++ b/Alc/backends/wasapi.c @@ -0,0 +1,2049 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#define COBJMACROS +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include "alMain.h" +#include "alu.h" +#include "ringbuffer.h" +#include "threads.h" +#include "compat.h" +#include "alstring.h" +#include "converter.h" + +#include "backends/base.h" + + +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); + +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23,0xe0, 0xc0,0xff,0xee,0x7f,0x0e, 4 ); + +#define MONO SPEAKER_FRONT_CENTER +#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) +#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) + +#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000) + +#define DEVNAME_HEAD "OpenAL Soft on " + + +/* Scales the given value using 64-bit integer math, ceiling the result. */ +static inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale) +{ + return (val*new_scale + old_scale-1) / old_scale; +} + + +typedef struct { + al_string name; + al_string endpoint_guid; // obtained from PKEY_AudioEndpoint_GUID , set to "Unknown device GUID" if absent. + WCHAR *devid; +} DevMap; +TYPEDEF_VECTOR(DevMap, vector_DevMap) + +static void clear_devlist(vector_DevMap *list) +{ +#define CLEAR_DEVMAP(i) do { \ + AL_STRING_DEINIT((i)->name); \ + AL_STRING_DEINIT((i)->endpoint_guid); \ + free((i)->devid); \ + (i)->devid = NULL; \ +} while(0) + VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); + VECTOR_RESIZE(*list, 0, 0); +#undef CLEAR_DEVMAP +} + +static vector_DevMap PlaybackDevices; +static vector_DevMap CaptureDevices; + + +static HANDLE ThreadHdl; +static DWORD ThreadID; + +typedef struct { + HANDLE FinishedEvt; + HRESULT result; +} ThreadRequest; + +#define WM_USER_First (WM_USER+0) +#define WM_USER_OpenDevice (WM_USER+0) +#define WM_USER_ResetDevice (WM_USER+1) +#define WM_USER_StartDevice (WM_USER+2) +#define WM_USER_StopDevice (WM_USER+3) +#define WM_USER_CloseDevice (WM_USER+4) +#define WM_USER_Enumerate (WM_USER+5) +#define WM_USER_Last (WM_USER+5) + +static const char MessageStr[WM_USER_Last+1-WM_USER][20] = { + "Open Device", + "Reset Device", + "Start Device", + "Stop Device", + "Close Device", + "Enumerate Devices", +}; + +static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res) +{ + req->result = res; + SetEvent(req->FinishedEvt); +} + +static HRESULT WaitForResponse(ThreadRequest *req) +{ + if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0) + return req->result; + ERR("Message response error: %lu\n", GetLastError()); + return E_FAIL; +} + + +static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) +{ + IPropertyStore *ps; + PROPVARIANT pvname; + PROPVARIANT pvguid; + HRESULT hr; + + alstr_copy_cstr(name, DEVNAME_HEAD); + + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + alstr_append_cstr(name, "Unknown Device Name"); + if(guid!=NULL)alstr_copy_cstr(guid, "Unknown Device GUID"); + return; + } + + PropVariantInit(&pvname); + + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); + if(FAILED(hr)) + { + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + alstr_append_cstr(name, "Unknown Device Name"); + } + else if(pvname.vt == VT_LPWSTR) + alstr_append_wcstr(name, pvname.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); + alstr_append_cstr(name, "Unknown Device Name"); + } + PropVariantClear(&pvname); + + if(guid!=NULL){ + PropVariantInit(&pvguid); + + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&PKEY_AudioEndpoint_GUID, &pvguid); + if(FAILED(hr)) + { + WARN("GetValue AudioEndpoint_GUID failed: 0x%08lx\n", hr); + alstr_copy_cstr(guid, "Unknown Device GUID"); + } + else if(pvguid.vt == VT_LPWSTR) + alstr_copy_wcstr(guid, pvguid.pwszVal); + else + { + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvguid.vt); + alstr_copy_cstr(guid, "Unknown Device GUID"); + } + + PropVariantClear(&pvguid); + } + + IPropertyStore_Release(ps); +} + +static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +{ + IPropertyStore *ps; + PROPVARIANT pvform; + HRESULT hr; + + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return; + } + + PropVariantInit(&pvform); + + hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform); + if(FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if(pvform.vt == VT_UI4) + *formfactor = pvform.ulVal; + else if(pvform.vt == VT_EMPTY) + *formfactor = UnknownFormFactor; + else + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); + + PropVariantClear(&pvform); + IPropertyStore_Release(ps); +} + + +static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) +{ + int count = 0; + al_string tmpname; + DevMap entry; + + AL_STRING_INIT(tmpname); + AL_STRING_INIT(entry.name); + AL_STRING_INIT(entry.endpoint_guid); + + entry.devid = strdupW(devid); + get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); + + while(1) + { + const DevMap *iter; + + alstr_copy(&entry.name, tmpname); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + alstr_append_cstr(&entry.name, str); + } + +#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); + if(iter == VECTOR_END(*list)) break; +#undef MATCH_ENTRY + count++; + } + + TRACE("Got device \"%s\", \"%s\", \"%ls\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.endpoint_guid), entry.devid); + VECTOR_PUSH_BACK(*list, entry); + + AL_STRING_DEINIT(tmpname); +} + +static WCHAR *get_device_id(IMMDevice *device) +{ + WCHAR *devid; + HRESULT hr; + + hr = IMMDevice_GetId(device, &devid); + if(FAILED(hr)) + { + ERR("Failed to get device id: %lx\n", hr); + return NULL; + } + + return devid; +} + +static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) +{ + IMMDeviceCollection *coll; + IMMDevice *defdev = NULL; + WCHAR *defdevid = NULL; + HRESULT hr; + UINT count; + UINT i; + + hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll); + if(FAILED(hr)) + { + ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); + return hr; + } + + count = 0; + hr = IMMDeviceCollection_GetCount(coll, &count); + if(SUCCEEDED(hr) && count > 0) + { + clear_devlist(list); + VECTOR_RESIZE(*list, 0, count); + + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, + eMultimedia, &defdev); + } + if(SUCCEEDED(hr) && defdev != NULL) + { + defdevid = get_device_id(defdev); + if(defdevid) + add_device(defdev, defdevid, list); + } + + for(i = 0;i < count;++i) + { + IMMDevice *device; + WCHAR *devid; + + hr = IMMDeviceCollection_Item(coll, i, &device); + if(FAILED(hr)) continue; + + devid = get_device_id(device); + if(devid) + { + if(wcscmp(devid, defdevid) != 0) + add_device(device, devid, list); + CoTaskMemFree(devid); + } + IMMDevice_Release(device); + } + + if(defdev) IMMDevice_Release(defdev); + if(defdevid) CoTaskMemFree(defdevid); + IMMDeviceCollection_Release(coll); + + return S_OK; +} + + +/* Proxy interface used by the message handler. */ +struct ALCwasapiProxyVtable; + +typedef struct ALCwasapiProxy { + const struct ALCwasapiProxyVtable *vtbl; +} ALCwasapiProxy; + +struct ALCwasapiProxyVtable { + HRESULT (*const openProxy)(ALCwasapiProxy*); + void (*const closeProxy)(ALCwasapiProxy*); + + HRESULT (*const resetProxy)(ALCwasapiProxy*); + HRESULT (*const startProxy)(ALCwasapiProxy*); + void (*const stopProxy)(ALCwasapiProxy*); +}; + +#define DEFINE_ALCWASAPIPROXY_VTABLE(T) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, openProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, void, closeProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, resetProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, HRESULT, startProxy) \ +DECLARE_THUNK(T, ALCwasapiProxy, void, stopProxy) \ + \ +static const struct ALCwasapiProxyVtable T##_ALCwasapiProxy_vtable = { \ + T##_ALCwasapiProxy_openProxy, \ + T##_ALCwasapiProxy_closeProxy, \ + T##_ALCwasapiProxy_resetProxy, \ + T##_ALCwasapiProxy_startProxy, \ + T##_ALCwasapiProxy_stopProxy, \ +} + +static void ALCwasapiProxy_Construct(ALCwasapiProxy* UNUSED(self)) { } +static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { } + +static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) +{ + ThreadRequest *req = ptr; + IMMDeviceEnumerator *Enumerator; + ALuint deviceCount = 0; + ALCwasapiProxy *proxy; + HRESULT hr, cohr; + MSG msg; + + TRACE("Starting message thread\n"); + + cohr = CoInitialize(NULL); + if(FAILED(cohr)) + { + WARN("Failed to initialize COM: 0x%08lx\n", cohr); + ReturnMsgResponse(req, cohr); + return 0; + } + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(FAILED(hr)) + { + WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); + CoUninitialize(); + ReturnMsgResponse(req, hr); + return 0; + } + Enumerator = ptr; + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + + CoUninitialize(); + + /* HACK: Force Windows to create a message queue for this thread before + * returning success, otherwise PostThreadMessage may fail if it gets + * called before GetMessage. + */ + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + TRACE("Message thread initialization complete\n"); + ReturnMsgResponse(req, S_OK); + + TRACE("Starting message loop\n"); + while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last)) + { + TRACE("Got message \"%s\" (0x%04x, lparam=%p, wparam=%p)\n", + (msg.message >= WM_USER && msg.message <= WM_USER_Last) ? + MessageStr[msg.message-WM_USER] : "Unknown", + msg.message, (void*)msg.lParam, (void*)msg.wParam + ); + switch(msg.message) + { + case WM_USER_OpenDevice: + req = (ThreadRequest*)msg.wParam; + proxy = (ALCwasapiProxy*)msg.lParam; + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitialize(NULL); + if(SUCCEEDED(hr)) + hr = V0(proxy,openProxy)(); + if(FAILED(hr)) + { + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + } + + ReturnMsgResponse(req, hr); + continue; + + case WM_USER_ResetDevice: + req = (ThreadRequest*)msg.wParam; + proxy = (ALCwasapiProxy*)msg.lParam; + + hr = V0(proxy,resetProxy)(); + ReturnMsgResponse(req, hr); + continue; + + case WM_USER_StartDevice: + req = (ThreadRequest*)msg.wParam; + proxy = (ALCwasapiProxy*)msg.lParam; + + hr = V0(proxy,startProxy)(); + ReturnMsgResponse(req, hr); + continue; + + case WM_USER_StopDevice: + req = (ThreadRequest*)msg.wParam; + proxy = (ALCwasapiProxy*)msg.lParam; + + V0(proxy,stopProxy)(); + ReturnMsgResponse(req, S_OK); + continue; + + case WM_USER_CloseDevice: + req = (ThreadRequest*)msg.wParam; + proxy = (ALCwasapiProxy*)msg.lParam; + + V0(proxy,closeProxy)(); + if(--deviceCount == 0) + CoUninitialize(); + + ReturnMsgResponse(req, S_OK); + continue; + + case WM_USER_Enumerate: + req = (ThreadRequest*)msg.wParam; + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitialize(NULL); + if(SUCCEEDED(hr)) + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + Enumerator = ptr; + + if(msg.lParam == ALL_DEVICE_PROBE) + hr = probe_devices(Enumerator, eRender, &PlaybackDevices); + else if(msg.lParam == CAPTURE_DEVICE_PROBE) + hr = probe_devices(Enumerator, eCapture, &CaptureDevices); + + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + + ReturnMsgResponse(req, hr); + continue; + + default: + ERR("Unexpected message: %u\n", msg.message); + continue; + } + } + TRACE("Message loop finished\n"); + + return 0; +} + + +typedef struct ALCwasapiPlayback { + DERIVE_FROM_TYPE(ALCbackend); + DERIVE_FROM_TYPE(ALCwasapiProxy); + + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioRenderClient *render; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + ATOMIC(UINT32) Padding; + + ATOMIC(int) killNow; + althrd_t thread; +} ALCwasapiPlayback; + +static int ALCwasapiPlayback_mixerProc(void *arg); + +static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device); +static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self); +static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *name); +static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self); +static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self); +static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self); +static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self); +static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self); +static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self); +static DECLARE_FORWARD2(ALCwasapiPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, ALCuint, availableSamples) +static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self); +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwasapiPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwasapiPlayback) + +DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiPlayback); +DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback); + + +static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device) +{ + SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self); + SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); + + self->devid = NULL; + + self->mmdev = NULL; + self->client = NULL; + self->render = NULL; + self->NotifyEvent = NULL; + + self->MsgEvent = NULL; + + ATOMIC_INIT(&self->Padding, 0); + + ATOMIC_INIT(&self->killNow, 0); +} + +static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self) +{ + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + } + + if(self->NotifyEvent) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + + free(self->devid); + self->devid = NULL; + + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + if(self->MsgEvent != NULL) + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + free(self->devid); + self->devid = NULL; + + ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) +{ + ALCwasapiPlayback *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + UINT32 buffer_len, written; + ALuint update_size, len; + BYTE *buffer; + HRESULT hr; + + hr = CoInitialize(NULL); + if(FAILED(hr)) + { + ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); + V0(device->Backend,unlock)(); + return 1; + } + + SetRTPriority(); + althrd_setname(althrd_current(), MIXER_THREAD_NAME); + + update_size = device->UpdateSize; + buffer_len = update_size * device->NumUpdates; + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + { + hr = IAudioClient_GetCurrentPadding(self->client, &written); + if(FAILED(hr)) + { + ERR("Failed to get padding: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to retrieve buffer padding: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); + + len = buffer_len - written; + if(len < update_size) + { + DWORD res; + res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + continue; + } + len -= len%update_size; + + hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer); + if(SUCCEEDED(hr)) + { + ALCwasapiPlayback_lock(self); + aluMixData(device, buffer, len); + ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed); + ALCwasapiPlayback_unlock(self); + hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); + } + if(FAILED(hr)) + { + ERR("Failed to buffer data: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to send playback samples: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + } + ATOMIC_STORE(&self->Padding, 0, almemory_order_release); + + CoUninitialize(); + return 0; +} + + +static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +{ + memset(out, 0, sizeof(*out)); + if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + *out = *(const WAVEFORMATEXTENSIBLE*)in; + else if(in->wFormatTag == WAVE_FORMAT_PCM) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else + { + ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); + return ALC_FALSE; + } + return ALC_TRUE; +} + +static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName) +{ + HRESULT hr = S_OK; + + self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if(self->NotifyEvent == NULL || self->MsgEvent == NULL) + { + ERR("Failed to create message events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + const DevMap *iter; + + if(VECTOR_SIZE(PlaybackDevices) == 0) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) + (void)WaitForResponse(&req); + } + + hr = E_FAIL; +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(PlaybackDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) + { + WCHAR *wname = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); +#undef MATCH_NAME + free(wname); + } + } + if(iter == VECTOR_END(PlaybackDevices)) + WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + alstr_copy(&device->DeviceName, iter->name); + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + } + + if(FAILED(hr)) + { + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + if(self->MsgEvent != NULL) + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + free(self->devid); + self->devid = NULL; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + void *ptr; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + IMMDeviceEnumerator *Enumerator = ptr; + if(!self->devid) + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &self->mmdev); + else + hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + if(SUCCEEDED(hr)) + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(SUCCEEDED(hr)) + { + self->client = ptr; + if(alstr_empty(device->DeviceName)) + get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); + } + + if(FAILED(hr)) + { + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; + } + + return hr; +} + + +static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) +{ + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; +} + + +static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + EndpointFormFactor formfactor = UnknownFormFactor; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = NULL; + REFERENCE_TIME min_per, buf_time; + UINT32 buffer_len, min_len; + void *ptr = NULL; + HRESULT hr; + + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + self->client = ptr; + + hr = IAudioClient_GetMixFormat(self->client, &wfx); + if(FAILED(hr)) + { + ERR("Failed to get mix format: 0x%08lx\n", hr); + return hr; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + + buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency); + + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + device->Frequency = OutputType.Format.nSamplesPerSec; + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + device->FmtChans = DevFmtX71; + else + ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + } + + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtAmbi3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + } + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.Samples.wValidBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.Samples.wValidBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + + hr = IAudioClient_IsFormatSupported(self->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + hr = IAudioClient_GetMixFormat(self->client, &wfx); + } + if(FAILED(hr)) + { + ERR("Failed to find a supported format: 0x%08lx\n", hr); + return hr; + } + + if(wfx != NULL) + { + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + + device->Frequency = OutputType.Format.nSamplesPerSec; + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) + device->FmtChans = DevFmtX71; + else + { + ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + device->FmtChans = DevFmtStereo; + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + } + + if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + device->FmtType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + device->FmtType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + device->FmtType = DevFmtInt; + else + { + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + } + } + else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + device->FmtType = DevFmtFloat; + OutputType.Format.wBitsPerSample = 32; + } + else + { + ERR("Unhandled format sub-type\n"); + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + } + get_device_formfactor(self->mmdev, &formfactor); + device->IsHeadphones = (device->FmtChans == DevFmtStereo && + (formfactor == Headphones || formfactor == Headset) + ); + + SetDefaultWFXChannelOrder(device); + + hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, NULL); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL); + if(SUCCEEDED(hr)) + { + min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC); + /* Find the nearest multiple of the period size to the update size */ + if(min_len < device->UpdateSize) + min_len *= (device->UpdateSize + min_len/2)/min_len; + hr = IAudioClient_GetBufferSize(self->client, &buffer_len); + } + if(FAILED(hr)) + { + ERR("Failed to get audio buffer info: 0x%08lx\n", hr); + return hr; + } + + device->UpdateSize = min_len; + device->NumUpdates = buffer_len / device->UpdateSize; + if(device->NumUpdates <= 1) + { + ERR("Audio client returned buffer_len < period*2; expect break up\n"); + device->NumUpdates = 2; + device->UpdateSize = buffer_len / device->NumUpdates; + } + + hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self) +{ + HRESULT hr; + void *ptr; + + ResetEvent(self->NotifyEvent); + hr = IAudioClient_Start(self->client); + if(FAILED(hr)) + ERR("Failed to start audio client: 0x%08lx\n", hr); + + if(SUCCEEDED(hr)) + hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + self->render = ptr; + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); + if(althrd_create(&self->thread, ALCwasapiPlayback_mixerProc, self) != althrd_success) + { + if(self->render) + IAudioRenderClient_Release(self->render); + self->render = NULL; + IAudioClient_Stop(self->client); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + return hr; +} + + +static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); +} + +static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) +{ + int res; + + if(!self->render) + return; + + ATOMIC_STORE_SEQ(&self->killNow, 1); + althrd_join(self->thread, &res); + + IAudioRenderClient_Release(self->render); + self->render = NULL; + IAudioClient_Stop(self->client); +} + + +static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ClockLatency ret; + + ALCwasapiPlayback_lock(self); + ret.ClockTime = GetDeviceClockTime(device); + ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / + device->Frequency; + ALCwasapiPlayback_unlock(self); + + return ret; +} + + +typedef struct ALCwasapiCapture { + DERIVE_FROM_TYPE(ALCbackend); + DERIVE_FROM_TYPE(ALCwasapiProxy); + + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioCaptureClient *capture; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + ChannelConverter *ChannelConv; + SampleConverter *SampleConv; + ll_ringbuffer_t *Ring; + + ATOMIC(int) killNow; + althrd_t thread; +} ALCwasapiCapture; + +static int ALCwasapiCapture_recordProc(void *arg); + +static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device); +static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self); +static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *name); +static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self); +static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self); +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ALCboolean, reset) +static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self); +static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self); +static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self); +static void ALCwasapiCapture_stop(ALCwasapiCapture *self); +static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self); +static ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples); +static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self); +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwasapiCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwasapiCapture) + +DEFINE_ALCWASAPIPROXY_VTABLE(ALCwasapiCapture); +DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture); + + +static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device) +{ + SET_VTABLE2(ALCwasapiCapture, ALCbackend, self); + SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self)); + + self->devid = NULL; + + self->mmdev = NULL; + self->client = NULL; + self->capture = NULL; + self->NotifyEvent = NULL; + + self->MsgEvent = NULL; + + self->ChannelConv = NULL; + self->SampleConv = NULL; + self->Ring = NULL; + + ATOMIC_INIT(&self->killNow, 0); +} + +static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self) +{ + if(self->MsgEvent) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); + + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + } + + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + + free(self->devid); + self->devid = NULL; + + ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self)); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) +{ + ALCwasapiCapture *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALfloat *samples = NULL; + size_t samplesmax = 0; + HRESULT hr; + + hr = CoInitialize(NULL); + if(FAILED(hr)) + { + ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); + V0(device->Backend,unlock)(); + return 1; + } + + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + { + UINT32 avail; + DWORD res; + + hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); + if(FAILED(hr)) + ERR("Failed to get next packet size: 0x%08lx\n", hr); + else if(avail > 0) + { + UINT32 numsamples; + DWORD flags; + BYTE *rdata; + + hr = IAudioCaptureClient_GetBuffer(self->capture, + &rdata, &numsamples, &flags, NULL, NULL + ); + if(FAILED(hr)) + ERR("Failed to get capture buffer: 0x%08lx\n", hr); + else + { + ll_ringbuffer_data_t data[2]; + size_t dstframes = 0; + + if(self->ChannelConv) + { + if(samplesmax < numsamples) + { + size_t newmax = RoundUp(numsamples, 4096); + ALfloat *tmp = al_calloc(DEF_ALIGN, newmax*2*sizeof(ALfloat)); + al_free(samples); + samples = tmp; + samplesmax = newmax; + } + ChannelConverterInput(self->ChannelConv, rdata, samples, numsamples); + rdata = (BYTE*)samples; + } + + ll_ringbuffer_get_write_vector(self->Ring, data); + + if(self->SampleConv) + { + const ALvoid *srcdata = rdata; + ALsizei srcframes = numsamples; + + dstframes = SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX) + ); + if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0) + { + /* If some source samples remain, all of the first dest + * block was filled, and there's space in the second + * dest block, do another run for the second block. + */ + dstframes += SampleConverterInput(self->SampleConv, + &srcdata, &srcframes, data[1].buf, (ALsizei)minz(data[1].len, INT_MAX) + ); + } + } + else + { + ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, + device->AmbiOrder); + size_t len1 = minz(data[0].len, numsamples); + size_t len2 = minz(data[1].len, numsamples-len1); + + memcpy(data[0].buf, rdata, len1*framesize); + if(len2 > 0) + memcpy(data[1].buf, rdata+len1*framesize, len2*framesize); + dstframes = len1 + len2; + } + + ll_ringbuffer_write_advance(self->Ring, dstframes); + + hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); + if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); + } + } + + if(FAILED(hr)) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr); + V0(device->Backend,unlock)(); + break; + } + + res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + } + + al_free(samples); + samples = NULL; + samplesmax = 0; + + CoUninitialize(); + return 0; +} + + +static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName) +{ + HRESULT hr = S_OK; + + self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if(self->NotifyEvent == NULL || self->MsgEvent == NULL) + { + ERR("Failed to create message events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + const DevMap *iter; + + if(VECTOR_SIZE(CaptureDevices) == 0) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) + (void)WaitForResponse(&req); + } + + hr = E_FAIL; +#define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0 || \ + alstr_cmp_cstr((i)->endpoint_guid, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + if(iter == VECTOR_END(CaptureDevices)) + { + int len; + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, NULL, 0)) > 0) + { + WCHAR *wname = calloc(sizeof(WCHAR), len); + MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, wname, len); +#define MATCH_NAME(i) (wcscmp((i)->devid, wname) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); +#undef MATCH_NAME + free(wname); + } + } + if(iter == VECTOR_END(CaptureDevices)) + WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + alstr_copy(&device->DeviceName, iter->name); + hr = S_OK; + } + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + } + + if(FAILED(hr)) + { + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + if(self->MsgEvent != NULL) + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + free(self->devid); + self->devid = NULL; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + else + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + + if(FAILED(hr)) + { + if(hr == E_OUTOFMEMORY) + return ALC_OUT_OF_MEMORY; + return ALC_INVALID_VALUE; + } + } + + return ALC_NO_ERROR; +} + +static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + void *ptr; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + IMMDeviceEnumerator *Enumerator = ptr; + if(!self->devid) + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev); + else + hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + if(SUCCEEDED(hr)) + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(SUCCEEDED(hr)) + { + self->client = ptr; + if(alstr_empty(device->DeviceName)) + get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); + } + + if(FAILED(hr)) + { + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; + } + + return hr; +} + + +static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) +{ + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; +} + + +static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = NULL; + enum DevFmtType srcType; + REFERENCE_TIME buf_time; + UINT32 buffer_len; + void *ptr = NULL; + HRESULT hr; + + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + self->client = ptr; + + buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC, + device->Frequency); + // Make sure buffer is at least 100ms in size + buf_time = maxu64(buf_time, REFTIME_PER_SEC/10); + device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) / + device->NumUpdates; + + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + + case DevFmtAmbi3D: + return E_FAIL; + } + switch(device->FmtType) + { + /* NOTE: Signedness doesn't matter, the converter will handle it. */ + case DevFmtByte: + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtShort: + case DevFmtUShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtInt: + case DevFmtUInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); + + hr = IAudioClient_IsFormatSupported(self->client, + AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx + ); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + return hr; + } + + DestroySampleConverter(&self->SampleConv); + DestroyChannelConverter(&self->ChannelConv); + + if(wfx != NULL) + { + if(!(wfx->nChannels == OutputType.Format.nChannels || + (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || + (wfx->nChannels == 2 && OutputType.Format.nChannels == 1))) + { + ERR("Failed to get matching format, wanted: %s %s %uhz, got: %d channel%s %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, wfx->nChannels, (wfx->nChannels==1)?"":"s", wfx->wBitsPerSample, + wfx->nSamplesPerSec); + CoTaskMemFree(wfx); + return E_FAIL; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + } + + if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + srcType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + srcType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtInt; + else + { + ERR("Unhandled integer bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if(OutputType.Format.wBitsPerSample == 32) + srcType = DevFmtFloat; + else + { + ERR("Unhandled float bit depth: %d\n", OutputType.Format.wBitsPerSample); + return E_FAIL; + } + } + else + { + ERR("Unhandled format sub-type\n"); + return E_FAIL; + } + + if(device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 2) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtStereo, + device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType)); + /* The channel converter always outputs float, so change the input type + * for the resampler/type-converter. + */ + srcType = DevFmtFloat; + } + else if(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 1) + { + self->ChannelConv = CreateChannelConverter(srcType, DevFmtMono, + device->FmtChans); + if(!self->ChannelConv) + { + ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + return E_FAIL; + } + TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType)); + srcType = DevFmtFloat; + } + + if(device->Frequency != OutputType.Format.nSamplesPerSec || device->FmtType != srcType) + { + self->SampleConv = CreateSampleConverter( + srcType, device->FmtType, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder), + OutputType.Format.nSamplesPerSec, device->Frequency + ); + if(!self->SampleConv) + { + ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + return E_FAIL; + } + TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); + } + + hr = IAudioClient_Initialize(self->client, + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, NULL + ); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetBufferSize(self->client, &buffer_len); + if(FAILED(hr)) + { + ERR("Failed to get buffer size: 0x%08lx\n", hr); + return hr; + } + + buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len); + ll_ringbuffer_free(self->Ring); + self->Ring = ll_ringbuffer_create(buffer_len, + FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder), + false + ); + if(!self->Ring) + { + ERR("Failed to allocate capture ring buffer\n"); + return E_OUTOFMEMORY; + } + + hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self) +{ + HRESULT hr; + void *ptr; + + ResetEvent(self->NotifyEvent); + hr = IAudioClient_Start(self->client); + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr); + if(SUCCEEDED(hr)) + { + self->capture = ptr; + ATOMIC_STORE(&self->killNow, 0, almemory_order_release); + if(althrd_create(&self->thread, ALCwasapiCapture_recordProc, self) != althrd_success) + { + ERR("Failed to start thread\n"); + IAudioCaptureClient_Release(self->capture); + self->capture = NULL; + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + IAudioClient_Stop(self->client); + IAudioClient_Reset(self->client); + } + + return hr; +} + + +static void ALCwasapiCapture_stop(ALCwasapiCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self))) + (void)WaitForResponse(&req); +} + +static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) +{ + int res; + + if(!self->capture) + return; + + ATOMIC_STORE_SEQ(&self->killNow, 1); + althrd_join(self->thread, &res); + + IAudioCaptureClient_Release(self->capture); + self->capture = NULL; + IAudioClient_Stop(self->client); + IAudioClient_Reset(self->client); +} + + +ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +{ + return (ALuint)ll_ringbuffer_read_space(self->Ring); +} + +ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples) +{ + if(ALCwasapiCapture_availableSamples(self) < samples) + return ALC_INVALID_VALUE; + ll_ringbuffer_read(self->Ring, buffer, samples); + return ALC_NO_ERROR; +} + + +static inline void AppendAllDevicesList2(const DevMap *entry) +{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } +static inline void AppendCaptureDeviceList2(const DevMap *entry) +{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } + +typedef struct ALCwasapiBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCwasapiBackendFactory; +#define ALCWASAPIBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); +static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); +static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); + + +static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self)) +{ + static HRESULT InitResult; + + VECTOR_INIT(PlaybackDevices); + VECTOR_INIT(CaptureDevices); + + if(!ThreadHdl) + { + ThreadRequest req; + InitResult = E_FAIL; + + req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); + if(req.FinishedEvt == NULL) + ERR("Failed to create event: %lu\n", GetLastError()); + else + { + ThreadHdl = CreateThread(NULL, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID); + if(ThreadHdl != NULL) + InitResult = WaitForResponse(&req); + CloseHandle(req.FinishedEvt); + } + } + + return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE; +} + +static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)) +{ + clear_devlist(&PlaybackDevices); + VECTOR_DEINIT(PlaybackDevices); + + clear_devlist(&CaptureDevices); + VECTOR_DEINIT(CaptureDevices); + + if(ThreadHdl) + { + TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); + PostThreadMessage(ThreadID, WM_QUIT, 0, 0); + CloseHandle(ThreadHdl); + ThreadHdl = NULL; + } +} + +static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + /* TODO: Disable capture with mmdevapi for now, since it doesn't do any + * rechanneling or resampling; if the device is configured for 48000hz + * stereo input, for example, and the app asks for 22050hz mono, + * initialization will fail. + */ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type) +{ + ThreadRequest req = { NULL, 0 }; + + req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); + if(req.FinishedEvt == NULL) + ERR("Failed to create event: %lu\n", GetLastError()); + else + { + HRESULT hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type)) + hr = WaitForResponse(&req); + if(SUCCEEDED(hr)) switch(type) + { + case ALL_DEVICE_PROBE: + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); + break; + + case CAPTURE_DEVICE_PROBE: + VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); + break; + } + CloseHandle(req.FinishedEvt); + req.FinishedEvt = NULL; + } +} + +static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwasapiPlayback *backend; + NEW_OBJ(backend, ALCwasapiPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCwasapiCapture *backend; + NEW_OBJ(backend, ALCwasapiCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + + +ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) +{ + static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/Alc/helpers.c b/Alc/helpers.c index 6de1fdc3..e5545492 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -66,7 +66,7 @@ DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); -#ifdef HAVE_MMDEVAPI +#ifdef HAVE_WASAPI #include #include #include diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c6196f1..4a6d8ae0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -752,7 +752,7 @@ SET(HAVE_SOLARIS 0) SET(HAVE_SNDIO 0) SET(HAVE_QSA 0) SET(HAVE_DSOUND 0) -SET(HAVE_MMDEVAPI 0) +SET(HAVE_WASAPI 0) SET(HAVE_WINMM 0) SET(HAVE_PORTAUDIO 0) SET(HAVE_PULSEAUDIO 0) @@ -970,7 +970,7 @@ ENDIF() # Check Windows-only backends OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) -OPTION(ALSOFT_REQUIRE_MMDEVAPI "Require MMDevApi backend" OFF) +OPTION(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" OFF) IF(HAVE_WINDOWS_H) # Check MMSystem backend CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0502) @@ -1000,14 +1000,14 @@ IF(HAVE_WINDOWS_H) ENDIF() ENDIF() - # Check for MMDevApi backend + # Check for WASAPI backend CHECK_INCLUDE_FILE(mmdeviceapi.h HAVE_MMDEVICEAPI_H) IF(HAVE_MMDEVICEAPI_H) - OPTION(ALSOFT_BACKEND_MMDEVAPI "Enable MMDevApi backend" ON) - IF(ALSOFT_BACKEND_MMDEVAPI) - SET(HAVE_MMDEVAPI 1) - SET(BACKENDS "${BACKENDS} MMDevApi,") - SET(ALC_OBJS ${ALC_OBJS} Alc/backends/mmdevapi.c) + OPTION(ALSOFT_BACKEND_WASAPI "Enable WASAPI backend" ON) + IF(ALSOFT_BACKEND_WASAPI) + SET(HAVE_WASAPI 1) + SET(BACKENDS "${BACKENDS} WASAPI,") + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.c) ENDIF() ENDIF() ENDIF() @@ -1017,8 +1017,8 @@ ENDIF() IF(ALSOFT_REQUIRE_DSOUND AND NOT HAVE_DSOUND) MESSAGE(FATAL_ERROR "Failed to enabled required DSound backend") ENDIF() -IF(ALSOFT_REQUIRE_MMDEVAPI AND NOT HAVE_MMDEVAPI) - MESSAGE(FATAL_ERROR "Failed to enabled required MMDevApi backend") +IF(ALSOFT_REQUIRE_WASAPI AND NOT HAVE_WASAPI) + MESSAGE(FATAL_ERROR "Failed to enabled required WASAPI backend") ENDIF() # Check PortAudio backend diff --git a/alsoftrc.sample b/alsoftrc.sample index 06ef57d5..b457a2db 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -444,9 +444,9 @@ surround71 = #buffer-size = 0 ## -## MMDevApi backend stuff +## WASAPI backend stuff ## -[mmdevapi] +[wasapi] ## ## DirectSound backend stuff diff --git a/appveyor.yml b/appveyor.yml index eab4f397..0e5b7ce4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,6 @@ install: build_script: - cd build - - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_MMDEVAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. + - cmake -G"%GEN%" -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON -DALSOFT_EMBED_HRTF_DATA=YES .. - cmake --build . --config %CFG% --clean-first diff --git a/config.h.in b/config.h.in index 345e8408..5768e345 100644 --- a/config.h.in +++ b/config.h.in @@ -50,8 +50,8 @@ /* Define if we have the QSA backend */ #cmakedefine HAVE_QSA -/* Define if we have the MMDevApi backend */ -#cmakedefine HAVE_MMDEVAPI +/* Define if we have the WASAPI backend */ +#cmakedefine HAVE_WASAPI /* Define if we have the DSound backend */ #cmakedefine HAVE_DSOUND diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index c5efbe38..a3b0c559 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -44,8 +44,8 @@ static const struct { #ifdef HAVE_QSA { "qsa", "QSA" }, #endif -#ifdef HAVE_MMDEVAPI - { "mmdevapi", "MMDevAPI" }, +#ifdef HAVE_WASAPI + { "wasapi", "WASAPI" }, #endif #ifdef HAVE_DSOUND { "dsound", "DirectSound" }, @@ -774,7 +774,16 @@ void MainWindow::loadConfig(const QString &fname) if(drivers.size() == 1) drivers = drivers[0].split(QChar(',')); for(QStringList::iterator iter = drivers.begin();iter != drivers.end();iter++) + { *iter = iter->trimmed(); + /* Convert "mmdevapi" references to "wasapi" for backwards + * compatibility. + */ + if(*iter == "-mmdevapi") + *iter = "-wasapi"; + else if(*iter == "mmdevapi") + *iter = "wasapi"; + } bool lastWasEmpty = false; foreach(const QString &backend, drivers) -- cgit v1.2.3 From dac93794491a9219ebdc6815244db76244f45b09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 10 Mar 2018 12:10:58 -0800 Subject: Add methods to clean up althrd and altss data --- Alc/ALc.c | 3 ++ common/threads.c | 97 +++++++++++++++++++++++--------------------------------- common/threads.h | 7 ++++ router/router.c | 4 +++ 4 files changed, 53 insertions(+), 58 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 8a2f67aa..eee17768 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -813,6 +813,7 @@ BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) break; case DLL_THREAD_DETACH: + althrd_thread_detach(); break; case DLL_PROCESS_DETACH: @@ -1260,6 +1261,8 @@ static void alc_deinit_safe(void) if(LogFile != stderr) fclose(LogFile); LogFile = NULL; + + althrd_deinit(); } static void alc_deinit(void) diff --git a/common/threads.c b/common/threads.c index 88052d7e..2655a244 100644 --- a/common/threads.c +++ b/common/threads.c @@ -64,6 +64,22 @@ extern inline int altss_set(altss_t tss_id, void *val); #include +/* An associative map of uint:void* pairs. The key is the unique Thread ID and + * the value is the thread HANDLE. The thread ID is passed around as the + * althrd_t since there is only one ID per thread, whereas a thread may be + * referenced by multiple different HANDLEs. This map allows retrieving the + * original handle which is needed to join the thread and get its return value. + */ +static UIntMap ThrdIdHandle = UINTMAP_STATIC_INITIALIZE; + +/* An associative map of uint:void* pairs. The key is the TLS index (given by + * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, + * we iterate over the TLS indices for their thread-local value and call the + * destructor function with it if they're both not NULL. + */ +static UIntMap TlsDestructors = UINTMAP_STATIC_INITIALIZE; + + void althrd_setname(althrd_t thr, const char *name) { #if defined(_MSC_VER) @@ -94,23 +110,6 @@ void althrd_setname(althrd_t thr, const char *name) } -static UIntMap ThrdIdHandle = UINTMAP_STATIC_INITIALIZE; - -static void NTAPI althrd_callback(void* UNUSED(handle), DWORD reason, void* UNUSED(reserved)) -{ - if(reason == DLL_PROCESS_DETACH) - ResetUIntMap(&ThrdIdHandle); -} -#ifdef _MSC_VER -#pragma section(".CRT$XLC",read) -__declspec(allocate(".CRT$XLC")) PIMAGE_TLS_CALLBACK althrd_callback_ = althrd_callback; -#elif defined(__GNUC__) -PIMAGE_TLS_CALLBACK althrd_callback_ __attribute__((section(".CRT$XLC"))) = althrd_callback; -#else -PIMAGE_TLS_CALLBACK althrd_callback_ = althrd_callback; -#endif - - typedef struct thread_cntr { althrd_start_t func; void *arg; @@ -363,47 +362,6 @@ int alsem_trywait(alsem_t *sem) } -/* An associative map of uint:void* pairs. The key is the TLS index (given by - * TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits, - * we iterate over the TLS indices for their thread-local value and call the - * destructor function with it if they're both not NULL. To avoid using - * DllMain, a PIMAGE_TLS_CALLBACK function pointer is placed in a ".CRT$XLx" - * section (where x is a character A to Z) which will be called by the CRT. - */ -static UIntMap TlsDestructors = UINTMAP_STATIC_INITIALIZE; - -static void NTAPI altss_callback(void* UNUSED(handle), DWORD reason, void* UNUSED(reserved)) -{ - ALsizei i; - - if(reason == DLL_PROCESS_DETACH) - { - ResetUIntMap(&TlsDestructors); - return; - } - if(reason != DLL_THREAD_DETACH) - return; - - LockUIntMapRead(&TlsDestructors); - for(i = 0;i < TlsDestructors.size;i++) - { - void *ptr = altss_get(TlsDestructors.keys[i]); - altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i]; - if(ptr && callback) - callback(ptr); - } - UnlockUIntMapRead(&TlsDestructors); -} -#ifdef _MSC_VER -#pragma section(".CRT$XLB",read) -__declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK altss_callback_ = altss_callback; -#elif defined(__GNUC__) -PIMAGE_TLS_CALLBACK altss_callback_ __attribute__((section(".CRT$XLB"))) = altss_callback; -#else -#warning "No TLS callback support, thread-local contexts may leak references on poorly written applications." -PIMAGE_TLS_CALLBACK altss_callback_ = altss_callback; -#endif - int altss_create(altss_t *tss_id, altss_dtor_t callback) { DWORD key = TlsAlloc(); @@ -454,6 +412,27 @@ void alcall_once(alonce_flag *once, void (*callback)(void)) InterlockedExchange(once, 2); } + +void althrd_deinit(void) +{ + ResetUIntMap(&ThrdIdHandle); + ResetUIntMap(&TlsDestructors); +} + +void althrd_thread_detach(void) +{ + ALsizei i; + + LockUIntMapRead(&TlsDestructors); + for(i = 0;i < TlsDestructors.size;i++) + { + void *ptr = altss_get(TlsDestructors.keys[i]); + altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i]; + if(ptr && callback) callback(ptr); + } + UnlockUIntMapRead(&TlsDestructors); +} + #else #include @@ -467,6 +446,8 @@ void alcall_once(alonce_flag *once, void (*callback)(void)) extern inline int althrd_sleep(const struct timespec *ts, struct timespec *rem); extern inline void alcall_once(alonce_flag *once, void (*callback)(void)); +extern inline void althrd_deinit(void); +extern inline void althrd_thread_detach(void); void althrd_setname(althrd_t thr, const char *name) { diff --git a/common/threads.h b/common/threads.h index 9a6fe1f7..b0bebd8d 100644 --- a/common/threads.h +++ b/common/threads.h @@ -65,6 +65,9 @@ typedef LONG alonce_flag; int althrd_sleep(const struct timespec *ts, struct timespec *rem); void alcall_once(alonce_flag *once, void (*callback)(void)); +void althrd_deinit(void); +void althrd_thread_detach(void); + inline althrd_t althrd_current(void) { @@ -216,6 +219,10 @@ inline void alcall_once(alonce_flag *once, void (*callback)(void)) pthread_once(once, callback); } + +inline void althrd_deinit(void) { } +inline void althrd_thread_detach(void) { } + #endif diff --git a/router/router.c b/router/router.c index 0497a1d2..a0b554f4 100644 --- a/router/router.c +++ b/router/router.c @@ -64,7 +64,9 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser break; case DLL_THREAD_ATTACH: + break; case DLL_THREAD_DETACH: + althrd_thread_detach(); break; case DLL_PROCESS_DETACH: @@ -84,6 +86,8 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser if(LogFile && LogFile != stderr) fclose(LogFile); LogFile = NULL; + + althrd_deinit(); break; } return TRUE; -- cgit v1.2.3 From 6b35a4534f1047c8e6ec630cbae89ea3e25e5d74 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Mar 2018 22:18:11 -0700 Subject: Comment and clarify some code --- Alc/ALu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 7461dcbf..12708cc5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1215,6 +1215,9 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop else if(SendSlots[i]->Params.AuxSendAuto) { RoomRolloff[i] = SendSlots[i]->Params.RoomRolloff + props->RoomRolloffFactor; + /* Calculate the distances to where this effect's decay reaches + * -60dB. + */ DecayDistance[i] = SendSlots[i]->Params.DecayTime * Listener->Params.ReverbSpeedOfSound; DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; @@ -1223,8 +1226,13 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat airAbsorption = SendSlots[i]->Params.AirAbsorptionGainHF; if(airAbsorption < 1.0f) { - ALfloat limitRatio = log10f(REVERB_DECAY_GAIN) / log10f(airAbsorption); - DecayHFDistance[i] = minf(limitRatio, DecayHFDistance[i]); + /* Calculate the distance to where this effect's air + * absorption reaches -60dB, and limit the effect's HF + * decay distance (so it doesn't take any longer to decay + * than the air would allow). + */ + ALfloat absorb_dist = log10f(REVERB_DECAY_GAIN) / log10f(airAbsorption); + DecayHFDistance[i] = minf(absorb_dist, DecayHFDistance[i]); } } } -- cgit v1.2.3 From 8eb7a94e1c07a8b3d74f84886c493d1a7dada7de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 11 Mar 2018 22:40:08 -0700 Subject: Apply a distance decay on the source send for the reverb's DecayLFRatio --- Alc/ALu.c | 12 ++++++++++-- OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/alAuxEffectSlot.c | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 12708cc5..1aa35cb7 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -457,6 +457,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f { slot->Params.RoomRolloff = props->Props.Reverb.RoomRolloffFactor; slot->Params.DecayTime = props->Props.Reverb.DecayTime; + slot->Params.DecayLFRatio = props->Props.Reverb.DecayLFRatio; slot->Params.DecayHFRatio = props->Props.Reverb.DecayHFRatio; slot->Params.DecayHFLimit = props->Props.Reverb.DecayHFLimit; slot->Params.AirAbsorptionGainHF = props->Props.Reverb.AirAbsorptionGainHF; @@ -465,6 +466,7 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f { slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; slot->Params.DecayHFRatio = 0.0f; slot->Params.DecayHFLimit = AL_FALSE; slot->Params.AirAbsorptionGainHF = 1.0f; @@ -1186,6 +1188,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALeffectslot *SendSlots[MAX_SENDS]; ALfloat RoomRolloff[MAX_SENDS]; ALfloat DecayDistance[MAX_SENDS]; + ALfloat DecayLFDistance[MAX_SENDS]; ALfloat DecayHFDistance[MAX_SENDS]; ALfloat DryGain, DryGainHF, DryGainLF; ALfloat WetGain[MAX_SENDS]; @@ -1210,6 +1213,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop SendSlots[i] = NULL; RoomRolloff[i] = 0.0f; DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; DecayHFDistance[i] = 0.0f; } else if(SendSlots[i]->Params.AuxSendAuto) @@ -1220,6 +1224,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop */ DecayDistance[i] = SendSlots[i]->Params.DecayTime * Listener->Params.ReverbSpeedOfSound; + DecayLFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayLFRatio; DecayHFDistance[i] = DecayDistance[i] * SendSlots[i]->Params.DecayHFRatio; if(SendSlots[i]->Params.DecayHFLimit) { @@ -1242,6 +1247,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop * effect slot is the same as the dry path, sans filter effects */ RoomRolloff[i] = props->RolloffFactor; DecayDistance[i] = 0.0f; + DecayLFDistance[i] = 0.0f; DecayHFDistance[i] = 0.0f; } @@ -1386,7 +1392,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop */ for(i = 0;i < NumSends;i++) { - ALfloat gain; + ALfloat gain, gainhf, gainlf; if(!(DecayDistance[i] > 0.0f)) continue; @@ -1398,8 +1404,10 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop */ if(gain > 0.0f) { - ALfloat gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); + gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); WetGainHF[i] *= minf(gainhf / gain, 1.0f); + gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); + WetGainLF[i] *= minf(gainlf / gain, 1.0f); } } } diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 36f09782..61c72153 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -127,6 +127,7 @@ typedef struct ALeffectslot { ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */ ALfloat DecayTime; + ALfloat DecayLFRatio; ALfloat DecayHFRatio; ALboolean DecayHFLimit; ALfloat AirAbsorptionGainHF; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index d4e6bf75..301244a0 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -686,6 +686,7 @@ ALenum InitEffectSlot(ALeffectslot *slot) slot->Params.EffectState = slot->Effect.State; slot->Params.RoomRolloff = 0.0f; slot->Params.DecayTime = 0.0f; + slot->Params.DecayLFRatio = 0.0f; slot->Params.DecayHFRatio = 0.0f; slot->Params.DecayHFLimit = AL_FALSE; slot->Params.AirAbsorptionGainHF = 1.0f; -- cgit v1.2.3 From 942abab8f9779c81b65b4c8c676b59482adadc78 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 13 Mar 2018 03:45:24 -0700 Subject: Move a loop into a function --- Alc/effects/reverb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f9650c8b..6861e967 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1301,9 +1301,12 @@ static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei o } #define UnfadedDelayLineOut(d, o0, o1, c, mu) DelayLineOut(d, o0, c) -static inline ALvoid DelayLineIn(DelayLineI *Delay, const ALsizei offset, const ALsizei c, const ALfloat in) +static inline ALvoid DelayLineIn(DelayLineI *Delay, ALsizei offset, const ALsizei c, + const ALfloat *restrict in, ALsizei count) { - Delay->Line[offset&Delay->Mask][c] = in; + ALsizei i; + for(i = 0;i < count;i++) + Delay->Line[(offset++)&Delay->Mask][c] = *(in++); } static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) @@ -1603,7 +1606,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; ALsizei fadeCount = State->FadeCount; ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; - ALsizei base, c, i; + ALsizei base, c; /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) @@ -1630,8 +1633,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ALfilterState_process(&State->Filter[c].Hp, early[1], early[0], todo); /* Feed the initial delay line. */ - for(i = 0;i < todo;i++) - DelayLineIn(&State->Delay, State->Offset+i, c, early[1][i]); + DelayLineIn(&State->Delay, State->Offset, c, early[1], todo); } if(UNLIKELY(fadeCount < FADE_SAMPLES)) -- cgit v1.2.3 From f65e83c3499ed26ee3dea4b0a1ca0282d47ae7cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Mar 2018 03:21:26 -0700 Subject: Avoid using pa_stream_begin_write with PulseAudio It seems to actually have a negative performance impact when the system is under load. Without having actual measurements for any potential benefits, simply go with the recommended (and previous fallback) method of allocating space for the write and passing the free method. Ideally some kind of ring buffer could be used, so rather than constantly allocating and freeing blocks of memory, it uses the same memory over again with the callback marking each one as reusable. Unfortunately the callback isn't given much information to work with, and the update size (minreq) can potentially change during playback, which complicates things. --- Alc/backends/pulseaudio.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 96794e20..be785707 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -833,6 +833,9 @@ static int ALCpulsePlayback_mixerProc(void *ptr) while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { + void *buf; + int ret; + len = pa_stream_writable_size(self->stream); if(len < 0) { @@ -863,33 +866,16 @@ static int ALCpulsePlayback_mixerProc(void *ptr) pa_threaded_mainloop_wait(self->loop); continue; } - len -= len%self->attr.minreq; - while(len > 0) - { - size_t newlen = len; - int ret; - void *buf; - pa_free_cb_t free_func = NULL; + len -= len%self->attr.minreq; + len -= len%frame_size; - if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0) - { - buf = pa_xmalloc(newlen); - free_func = pa_xfree; - } + buf = pa_xmalloc(len); - newlen /= frame_size; - aluMixData(device, buf, newlen); + aluMixData(device, buf, len/frame_size); - newlen *= frame_size; - ret = pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); - if(ret != PA_OK) - { - ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); - break; - } - len -= newlen; - } + ret = pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE); + if(ret != PA_OK) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret)); } pa_threaded_mainloop_unlock(self->loop); -- cgit v1.2.3 From 7c0e68a33e1d25dfe4676f600c072e0f3edc2853 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Mar 2018 17:21:19 -0700 Subject: Store the filter history in local variables Despite being marked as restrict (and const for src) to mark the pointers as being non-aliased, it seems the compiler optimizes better this way. --- Alc/mixer_c.c | 38 ++++++++++++++++++-------------------- Alc/uhjfilter.c | 24 ++++++++++++++++-------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c index f8c3c833..2346080a 100644 --- a/Alc/mixer_c.c +++ b/Alc/mixer_c.c @@ -97,26 +97,24 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALsizei i; if(LIKELY(numsamples > 1)) { - dst[0] = filter->b0 * src[0] + - filter->b1 * filter->x[0] + - filter->b2 * filter->x[1] - - filter->a1 * filter->y[0] - - filter->a2 * filter->y[1]; - dst[1] = filter->b0 * src[1] + - filter->b1 * src[0] + - filter->b2 * filter->x[0] - - filter->a1 * dst[0] - - filter->a2 * filter->y[0]; - for(i = 2;i < numsamples;i++) - dst[i] = filter->b0 * src[i] + - filter->b1 * src[i-1] + - filter->b2 * src[i-2] - - filter->a1 * dst[i-1] - - filter->a2 * dst[i-2]; - filter->x[0] = src[i-1]; - filter->x[1] = src[i-2]; - filter->y[0] = dst[i-1]; - filter->y[1] = dst[i-2]; + ALfloat x0 = filter->x[0]; + ALfloat x1 = filter->x[1]; + ALfloat y0 = filter->y[0]; + ALfloat y1 = filter->y[1]; + + for(i = 0;i < numsamples;i++) + { + dst[i] = filter->b0* src[i] + + filter->b1*x0 + filter->b2*x1 - + filter->a1*y0 - filter->a2*y1; + y1 = y0; y0 = dst[i]; + x1 = x0; x0 = src[i]; + } + + filter->x[0] = x0; + filter->x[1] = x1; + filter->y[0] = y0; + filter->y[1] = y1; } else if(numsamples == 1) { diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index 6f9fb37d..fd2d6567 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -22,14 +22,22 @@ static void allpass_process(AllPassState *state, ALfloat *restrict dst, const AL if(LIKELY(todo > 1)) { - dst[0] = aa*(src[0] + state->y[1]) - state->x[1]; - dst[1] = aa*(src[1] + state->y[0]) - state->x[0]; - for(i = 2;i < todo;i++) - dst[i] = aa*(src[i] + dst[i-2]) - src[i-2]; - state->x[1] = src[i-2]; - state->x[0] = src[i-1]; - state->y[1] = dst[i-2]; - state->y[0] = dst[i-1]; + ALfloat x0 = state->x[0]; + ALfloat x1 = state->x[1]; + ALfloat y0 = state->y[0]; + ALfloat y1 = state->y[1]; + + for(i = 0;i < todo;i++) + { + dst[i] = aa*(src[i] + y1) - x1; + y1 = y0; y0 = dst[i]; + x1 = x0; x0 = src[i]; + } + + state->x[0] = x0; + state->x[1] = x1; + state->y[0] = y0; + state->y[1] = y1; } else if(todo == 1) { -- cgit v1.2.3 From 2011421e18442d7dd31dbb84135786dd8bf6a478 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Mar 2018 23:48:46 -0700 Subject: Release the PulseAudio mainloop lock sooner --- Alc/backends/pulseaudio.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index be785707..74d1a149 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1164,13 +1164,16 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self) static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) { - pa_usec_t latency = 0; ClockLatency ret; + pa_usec_t latency; int neg, err; pa_threaded_mainloop_lock(self->loop); ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); - if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0) + err = pa_stream_get_latency(self->stream, &latency, &neg); + pa_threaded_mainloop_unlock(self->loop); + + if(UNLIKELY(err != 0)) { /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon * after starting the stream and no timing info has been received from @@ -1181,9 +1184,9 @@ static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) latency = 0; neg = 0; } - if(neg) latency = 0; - ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000; - pa_threaded_mainloop_unlock(self->loop); + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; return ret; } @@ -1715,21 +1718,24 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self) { - pa_usec_t latency = 0; ClockLatency ret; + pa_usec_t latency; int neg, err; pa_threaded_mainloop_lock(self->loop); ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice); - if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0) + err = pa_stream_get_latency(self->stream, &latency, &neg); + pa_threaded_mainloop_unlock(self->loop); + + if(UNLIKELY(err != 0)) { ERR("Failed to get stream latency: 0x%x\n", err); latency = 0; neg = 0; } - if(neg) latency = 0; - ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000; - pa_threaded_mainloop_unlock(self->loop); + else if(UNLIKELY(neg)) + latency = 0; + ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000; return ret; } -- cgit v1.2.3 From 603e3e23acf02d1bcb20f5ebb230bfb3c0fad9d8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Mar 2018 23:51:13 -0700 Subject: Remove an outdated comment --- Alc/backends/wasapi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c index b64e260b..8677afa9 100644 --- a/Alc/backends/wasapi.c +++ b/Alc/backends/wasapi.c @@ -1984,11 +1984,6 @@ static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self) static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type) { - /* TODO: Disable capture with mmdevapi for now, since it doesn't do any - * rechanneling or resampling; if the device is configured for 48000hz - * stereo input, for example, and the app asks for 22050hz mono, - * initialization will fail. - */ if(type == ALCbackend_Playback || type == ALCbackend_Capture) return ALC_TRUE; return ALC_FALSE; -- cgit v1.2.3 From 445f63f350195cf13429d7fc18e645c8ecf0919d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 14 Mar 2018 23:59:20 -0700 Subject: Remove an extraneous + --- Alc/effects/reverb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 6861e967..3efac090 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1379,7 +1379,7 @@ static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat out[0] = xCoeff*in[3] + yCoeff*(in[0] + -in[1] + in[2] ); out[1] = xCoeff*in[2] + yCoeff*(in[0] + in[1] + -in[3]); out[2] = xCoeff*in[1] + yCoeff*(in[0] + -in[2] + in[3]); - out[3] = xCoeff*in[0] + yCoeff*( + -in[1] + -in[2] + -in[3]); + out[3] = xCoeff*in[0] + yCoeff*( -in[1] + -in[2] + -in[3]); } /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass -- cgit v1.2.3 From 3fde27d89098f6f71f82c06f89a2acbaa5f20400 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Mar 2018 00:28:49 -0700 Subject: Use a macro template to define similar functions --- Alc/effects/reverb.c | 126 ++++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 78 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 3efac090..46129934 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1441,9 +1441,9 @@ DECL_TEMPLATE(Faded) * line processing and non-transitional processing. */ #define DECL_TEMPLATE(T) \ -static ALvoid EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ - ALfloat fade, \ - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES])\ +static void EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ + ALfloat fade, \ + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ { \ ALsizei offset = State->Offset; \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ @@ -1522,82 +1522,52 @@ static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -static ALvoid LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) -{ - const ALfloat apFeedCoeff = State->ApFeedCoeff; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei offset; - ALsizei i, j; - - offset = State->Offset; - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES], fr[NUM_LINES]; - - for(j = 0;j < NUM_LINES;j++) - f[j] = FadedDelayLineOut(&State->Delay, - offset - State->LateDelayTap[j][0], - offset - State->LateDelayTap[j][1], j, fade - ) * State->Late.DensityGain; - - for(j = 0;j < NUM_LINES;j++) - f[j] += FadedDelayLineOut(&State->Late.Delay, - offset - State->Late.Offset[j][0], - offset - State->Late.Offset[j][1], j, fade - ); - - LateT60Filter(fr, f, State->Late.T60); - VectorAllpass_Faded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, - &State->Late.VecAp); - - for(j = 0;j < NUM_LINES;j++) - out[j][i] = f[j]; - - VectorPartialScatterRev(fr, f, mixX, mixY); - - DelayLineIn4(&State->Late.Delay, offset, fr); - - offset++; - fade += FadeStep; - } -} -static ALvoid LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat fade, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) -{ - const ALfloat apFeedCoeff = State->ApFeedCoeff; - const ALfloat mixX = State->MixX; - const ALfloat mixY = State->MixY; - ALsizei offset; - ALsizei i, j; - - offset = State->Offset; - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES], fr[NUM_LINES]; - - for(j = 0;j < NUM_LINES;j++) - f[j] = DelayLineOut(&State->Delay, offset-State->LateDelayTap[j][0], j) * - State->Late.DensityGain; - - for(j = 0;j < NUM_LINES;j++) - f[j] += DelayLineOut(&State->Late.Delay, offset-State->Late.Offset[j][0], j); - - LateT60Filter(fr, f, State->Late.T60); - VectorAllpass_Unfaded(f, fr, offset, apFeedCoeff, mixX, mixY, fade, - &State->Late.VecAp); - - for(j = 0;j < NUM_LINES;j++) - out[j][i] = f[j]; - - VectorPartialScatterRev(fr, f, mixX, mixY); - - DelayLineIn4(&State->Late.Delay, offset, fr); - - offset++; - } +#define DECL_TEMPLATE(T) \ +static void LateReverb_##T(ALreverbState *State, const ALsizei todo, \ + ALfloat fade, \ + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ +{ \ + const ALfloat apFeedCoeff = State->ApFeedCoeff; \ + const ALfloat mixX = State->MixX; \ + const ALfloat mixY = State->MixY; \ + ALsizei offset; \ + ALsizei i, j; \ + \ + offset = State->Offset; \ + for(i = 0;i < todo;i++) \ + { \ + ALfloat f[NUM_LINES], fr[NUM_LINES]; \ + \ + for(j = 0;j < NUM_LINES;j++) \ + f[j] = T##DelayLineOut(&State->Delay, \ + offset - State->LateDelayTap[j][0], \ + offset - State->LateDelayTap[j][1], j, fade \ + ) * State->Late.DensityGain; \ + \ + for(j = 0;j < NUM_LINES;j++) \ + f[j] += T##DelayLineOut(&State->Late.Delay, \ + offset - State->Late.Offset[j][0], \ + offset - State->Late.Offset[j][1], j, fade \ + ); \ + \ + LateT60Filter(fr, f, State->Late.T60); \ + VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ + &State->Late.VecAp); \ + \ + for(j = 0;j < NUM_LINES;j++) \ + out[j][i] = f[j]; \ + \ + VectorPartialScatterRev(fr, f, mixX, mixY); \ + \ + DelayLineIn4(&State->Late.Delay, offset, fr); \ + \ + offset++; \ + fade += FadeStep; \ + } \ } +DECL_TEMPLATE(Unfaded) +DECL_TEMPLATE(Faded) +#undef DECL_TEMPLATE static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { -- cgit v1.2.3 From 325fca5215982da3267486f2605df47b6c6c826d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 16 Mar 2018 05:01:00 -0700 Subject: Change the presets for the multireverb example --- examples/almultireverb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 2f820914..47bc86e2 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -235,8 +235,8 @@ static ALfloat dot_product(const ALfloat vec0[3], const ALfloat vec1[3]) int main(int argc, char **argv) { static const int MaxTransitions = 8; - EFXEAXREVERBPROPERTIES reverb0 = EFX_REVERB_PRESET_CASTLE_LARGEROOM; - EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_CASTLE_LONGPASSAGE; + EFXEAXREVERBPROPERTIES reverb0 = EFX_REVERB_PRESET_CARPETEDHALLWAY; + EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_BATHROOM; struct timespec basetime; ALCdevice *device = NULL; ALCcontext *context = NULL; -- cgit v1.2.3 From 6fd23f09842b81788298e1840b8626252fdf5e18 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 18 Mar 2018 17:47:17 +0100 Subject: EFX:Pitch Shifter implementation Add pitch shifter effect using standard phase vocoder, based on work of Stephan Bernsee. Only mono signal processing by now. --- Alc/ALc.c | 5 +- Alc/effects/pshifter.c | 493 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/Include/alEffect.h | 9 +- OpenAL32/alAuxEffectSlot.c | 1 + OpenAL32/alEffect.c | 6 + 7 files changed, 514 insertions(+), 2 deletions(-) create mode 100644 Alc/effects/pshifter.c diff --git a/Alc/ALc.c b/Alc/ALc.c index eee17768..8cfc7d25 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -547,10 +547,10 @@ static const struct { DECL(AL_EFFECT_DISTORTION), DECL(AL_EFFECT_ECHO), DECL(AL_EFFECT_FLANGER), + DECL(AL_EFFECT_PITCH_SHIFTER), #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 @@ -634,6 +634,9 @@ static const struct { DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), + DECL(AL_PITCH_SHIFTER_COARSE_TUNE), + DECL(AL_PITCH_SHIFTER_FINE_TUNE), + DECL(AL_COMPRESSOR_ONOFF), DECL(AL_EQUALIZER_LOW_GAIN), diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c new file mode 100644 index 00000000..1a2ddef7 --- /dev/null +++ b/Alc/effects/pshifter.c @@ -0,0 +1,493 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALcomplex{ + + ALfloat Real; + ALfloat Imag; + +}ALcomplex; + +typedef struct ALphasor{ + + ALfloat Amplitude; + ALfloat Phase; + +}ALphasor; + +typedef struct ALFrequencyDomain{ + + ALfloat Amplitude; + ALfloat Frequency; + +}ALfrequencyDomain; + +typedef struct ALpshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MAX_OUTPUT_CHANNELS]; + + /* Effect parameters */ + ALsizei count; + ALsizei STFT_size; + ALsizei step; + ALsizei FIFOLatency; + ALsizei oversamp; + ALfloat PitchShift; + ALfloat Frequency; + + /*Effects buffers*/ + ALfloat InFIFO[BUFFERSIZE]; + ALfloat OutFIFO[BUFFERSIZE]; + ALfloat LastPhase[(BUFFERSIZE>>1) +1]; + ALfloat SumPhase[(BUFFERSIZE>>1) +1]; + ALfloat OutputAccum[BUFFERSIZE<<1]; + ALfloat window[BUFFERSIZE]; + + ALcomplex FFTbuffer[BUFFERSIZE]; + + ALfrequencyDomain Analysis_buffer[BUFFERSIZE]; + ALfrequencyDomain Syntesis_buffer[BUFFERSIZE]; + + +} ALpshifterState; + +static inline ALphasor rect2polar( ALcomplex number ); +static inline ALcomplex polar2rect( ALphasor number ); +static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign); + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state); +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + +static void ALpshifterState_Construct(ALpshifterState *state) +{ + ALsizei i; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALpshifterState, ALeffectState, state); + + /*Initializing parameters and set to zero the buffers */ + state->STFT_size = BUFFERSIZE>>1; + state->oversamp = 1<<2; + + state->step = state->STFT_size / state->oversamp ; + state->FIFOLatency = state->step * ( state->oversamp-1 ); + state->count = state->FIFOLatency; + + memset(state->InFIFO, 0, BUFFERSIZE*sizeof(ALfloat)); + memset(state->OutFIFO, 0, BUFFERSIZE*sizeof(ALfloat)); + memset(state->FFTbuffer, 0, BUFFERSIZE*sizeof(ALcomplex)); + memset(state->LastPhase, 0, ((BUFFERSIZE>>1) +1)*sizeof(ALfloat)); + memset(state->SumPhase, 0, ((BUFFERSIZE>>1) +1)*sizeof(ALfloat)); + memset(state->OutputAccum, 0, (BUFFERSIZE<<1)*sizeof(ALfloat)); + memset(state->Analysis_buffer, 0, BUFFERSIZE*sizeof(ALfrequencyDomain)); + + /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ + for ( i = 0; i < state->STFT_size>>1 ; i++ ) + { + state->window[i] = state->window[state->STFT_size-(i+1)] \ + = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(state->STFT_size-1))); + } +} + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *UNUSED(state), ALCdevice *UNUSED(device)) +{ + return AL_TRUE; +} + +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + const ALfloat adjust = 0.707945784384f; /*-3dB adjust*/ + + state->Frequency = (ALfloat)device->Frequency; + state->PitchShift = powf(2.0f,((ALfloat)props->Pshifter.CoarseTune + props->Pshifter.FineTune/100.0f)/12.0f); + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * adjust, state->Gain); +} + +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + /*Pitch shifter engine based on the work of Stephan Bernsee. + * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ **/ + + ALsizei i, j, k, STFT_half_size; + ALfloat freq_bin, expected, tmp; + ALfloat bufferOut[BUFFERSIZE]; + ALphasor component; + + + STFT_half_size = state->STFT_size >> 1; + freq_bin = state->Frequency / (ALfloat)state->STFT_size; + expected = F_TAU / (ALfloat)state->oversamp; + + + for (i = 0; i < SamplesToDo; i++) + { + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + bufferOut[i] = state->OutFIFO[state->count - state->FIFOLatency]; + + state->count++; + + /* Check whether FIFO buffer is filled */ + if ( state->count >= state->STFT_size ) + { + state->count = state->FIFOLatency; + + /* Real signal windowing and store in FFTbuffer */ + for ( k = 0; k < state->STFT_size; k++ ) + { + state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; + state->FFTbuffer[k].Imag = 0.0f; + } + + /* ANALYSIS */ + /* Apply FFT to FFTbuffer data */ + FFT( state->FFTbuffer, state->STFT_size, -1 ); + + /* Analyze the obtained data. Since the real FFT is symmetric, only STFT_half_size+1 samples are needed */ + for ( k = 0; k <= STFT_half_size; k++ ) + { + /* Compute amplitude and phase */ + component = rect2polar( state->FFTbuffer[k] ); + + /* Compute phase difference and subtract expected phase difference */ + tmp = ( component.Phase - state->LastPhase[k] ) - (ALfloat)k*expected; + + /* Map delta phase into +/- Pi interval */ + tmp -= F_PI*(ALfloat)( fastf2i(tmp/F_PI) + fastf2i(tmp/F_PI) % 2 ); + + /* Get deviation from bin frequency from the +/- Pi interval */ + tmp /= expected; + + /* Compute the k-th partials' true frequency, twice the amplitude for maintain the gain + (because half of bins are used) and store amplitude and true frequency in analysis buffer */ + state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; + state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; + + /* Store actual phase[k] for the calculations in the next frame*/ + state->LastPhase[k] = component.Phase; + + } + + /* PROCESSING */ + /* pitch shifting */ + memset(state->Syntesis_buffer, 0, state->STFT_size*sizeof(ALfrequencyDomain)); + + for (k = 0; k <= STFT_half_size; k++) + { + j = fastf2i( (ALfloat)k*state->PitchShift ); + + if ( j <= STFT_half_size ) + { + state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; + state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * state->PitchShift; + } + } + + /* SYNTHESIS */ + /* Synthesis the processing data */ + for ( k = 0; k <= STFT_half_size; k++ ) + { + /* Compute bin deviation from scaled freq */ + tmp = state->Syntesis_buffer[k].Frequency /freq_bin - (ALfloat)k; + + /* Calculate actual delta phase and accumulate it to get bin phase */ + state->SumPhase[k] += ((ALfloat)k + tmp) * expected; + + component.Amplitude = state->Syntesis_buffer[k].Amplitude; + component.Phase = state->SumPhase[k]; + + /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ + state->FFTbuffer[k] = polar2rect( component ); + } + + /* zero negative frequencies for recontruct a real signal */ + memset( &state->FFTbuffer[STFT_half_size+1], 0, (STFT_half_size-1) * sizeof(ALcomplex) ); + + /* Apply iFFT to buffer data */ + FFT( state->FFTbuffer, state->STFT_size, 1 ); + + /* Windowing and add to output */ + for( k=0; k < state->STFT_size; k++ ) + { + state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / (STFT_half_size * state->oversamp); + } + + /* Shift accumulator, input & output FIFO */ + memmove(state->OutFIFO , state->OutputAccum , state->step * sizeof(ALfloat)); + memmove(state->OutputAccum, state->OutputAccum + state->step, state->STFT_size * sizeof(ALfloat)); + memmove(state->InFIFO , state->InFIFO + state->step, state->FIFOLatency * sizeof(ALfloat)); + + } + } + + /* Now, mix the processed sound data to the output*/ + + for (j = 0; j < NumChannels; j++ ) + { + ALfloat gain = state->Gain[j]; + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < SamplesToDo;i++) + SamplesOut[j][i] += gain * bufferOut[i]; + + } + + +} + +typedef struct PshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} PshifterStateFactory; + +static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) +{ + ALpshifterState *state; + + NEW_OBJ0(state, ALpshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); + +EffectStateFactory *PshifterStateFactory_getFactory(void) +{ + static PshifterStateFactory PshifterFactory = { { GET_VTABLE2(PshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &PshifterFactory); +} + + +void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param ); +} + +void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param ); +} + +void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); + props->Pshifter.CoarseTune = val; + break; + + case AL_PITCH_SHIFTER_FINE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); + props->Pshifter.FineTune = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALpshifter_setParami(effect, context, param, vals[0]); +} + +void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + *val = (ALint)props->Pshifter.CoarseTune; + break; + case AL_PITCH_SHIFTER_FINE_TUNE: + *val = (ALint)props->Pshifter.FineTune; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALpshifter_getParami(effect, context, param, vals); +} + +void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); +} + +void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); +} + +DEFINE_ALEFFECT_VTABLE(ALpshifter); + + +/* Converts ALcomplex to ALphasor*/ +static inline ALphasor rect2polar( ALcomplex number ) +{ + ALphasor polar; + + polar.Amplitude = sqrtf ( number.Real*number.Real + number.Imag*number.Imag ); + polar.Phase = atan2f( number.Imag , number.Real ); + + return polar; +} + +/* Converts ALphasor to ALcomplex*/ +static inline ALcomplex polar2rect( ALphasor number ) +{ + ALcomplex cartesian; + + cartesian.Real = number.Amplitude * cosf( number.Phase ); + cartesian.Imag = number.Amplitude * sinf( number.Phase ); + + return cartesian; +} + +/* Addition of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_add( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real + b.Real ); + result.Imag = ( a.Imag + b.Imag ); + + return result; +} + +/* Substraction of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_subst( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real - b.Real ); + result.Imag = ( a.Imag - b.Imag ); + + return result; +} + +/* Multiplication of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_mult( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real * b.Real - a.Imag * b.Imag ); + result.Imag = ( a.Imag * b.Real + a.Real * b.Imag ); + + return result; +} + +/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is FFT and 1 is + iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the Discrete Fourier Transform (DFT) + of the time domain data stored in FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of + complex numbers (ALcomplex), FFTSize MUST BE power of two.*/ + +static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign) +{ + ALfloat arg; + ALsizei i, j, k, mask, step, step2; + ALcomplex temp, u, w; + + /*bit-reversal permutation applied to a sequence of FFTSize items*/ + for (i = 1; i < FFTSize-1; i++ ) + { + + for ( mask = 0x1, j = 0; mask < FFTSize; mask <<= 1 ) + { + if ( ( i & mask ) != 0 ) j++; + + j <<= 1; + } + + j >>= 1; + + if ( i < j ) + { + temp = FFTBuffer[i]; + FFTBuffer[i] = FFTBuffer[j]; + FFTBuffer[j] = temp; + } + } + + /* Iterative form of Danielson–Lanczos lemma */ + for ( i = 1, step = 2; i < FFTSize; i<<=1, step <<= 1 ) + { + + step2 = step >> 1; + arg = F_PI / step2; + + w.Real = cosf( arg ); + w.Imag = sinf( arg ) * Sign; + + u.Real = 1.0f; + u.Imag = 0.0f; + + for ( j = 0; j < step2; j++ ) + { + + for ( k = j; k < FFTSize; k += step ) + { + + temp = complex_mult( FFTBuffer[k+step2], u ); + FFTBuffer[k+step2] = complex_subst( FFTBuffer[k], temp ); + FFTBuffer[k] = complex_add( FFTBuffer[k], temp ); + } + + u = complex_mult(u,w); + } + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a6d8ae0..986a6c32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -726,6 +726,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/effects/equalizer.c Alc/effects/modulator.c Alc/effects/null.c + Alc/effects/pshifter.c Alc/effects/reverb.c Alc/helpers.c Alc/hrtf.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index 61c72153..bb9aef59 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -167,6 +167,7 @@ EffectStateFactory *EchoStateFactory_getFactory(void); EffectStateFactory *EqualizerStateFactory_getFactory(void); EffectStateFactory *FlangerStateFactory_getFactory(void); EffectStateFactory *ModulatorStateFactory_getFactory(void); +EffectStateFactory *PshifterStateFactory_getFactory(void); EffectStateFactory *DedicatedStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 95fa035e..50b64ee1 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -19,6 +19,7 @@ enum { EQUALIZER_EFFECT, FLANGER_EFFECT, MODULATOR_EFFECT, + PSHIFTER_EFFECT, DEDICATED_EFFECT, MAX_EFFECTS @@ -32,7 +33,7 @@ struct EffectList { int type; ALenum val; }; -#define EFFECTLIST_SIZE 11 +#define EFFECTLIST_SIZE 12 extern const struct EffectList EffectList[EFFECTLIST_SIZE]; @@ -66,6 +67,7 @@ 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 ALpshifter_vtable; extern const struct ALeffectVtable ALdedicated_vtable; @@ -149,6 +151,11 @@ typedef union ALeffectProps { ALint Waveform; } Modulator; + struct { + ALint CoarseTune; + ALint FineTune; + } Pshifter; + struct { ALfloat Gain; } Dedicated; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 301244a0..d04fc4a7 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -55,6 +55,7 @@ static const struct { { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, + { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory } }; diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index 6b16fc56..e7dc6ace 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -45,6 +45,7 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, + { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE }, }; @@ -589,6 +590,11 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; effect->vtab = &ALmodulator_vtable; break; + case AL_EFFECT_PITCH_SHIFTER: + effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE; + effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE; + effect->vtab = &ALpshifter_vtable; + break; case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: case AL_EFFECT_DEDICATED_DIALOGUE: effect->Props.Dedicated.Gain = 1.0f; -- cgit v1.2.3 From 56423b9ef160aa4313f1db81da7197eb6a25efa8 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 18 Mar 2018 17:53:07 +0100 Subject: Alsoft-config: Add pitch shifter effect --- alsoftrc.sample | 2 +- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 30 +++++++++++++++++++++++------- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index b457a2db..cac9fd93 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -220,7 +220,7 @@ # 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,chorus,compressor, -# distortion,echo,equalizer,flanger,modulator,dedicated +# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter #excludefx = ## default-reverb: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index a3b0c559..94aa0750 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -380,6 +380,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enablePitchShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -845,6 +846,7 @@ void MainWindow::loadConfig(const QString &fname) ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); + ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool()); ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); @@ -1058,6 +1060,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("modulator"); if(!ui->enableDedicatedCheck->isChecked()) strlist.append("dedicated"); + if(!ui->enablePitchShifterCheck->isChecked()) + strlist.append("pshifter"); settings.setValue("excludefx", strlist.join(QChar(','))); settings.setValue("pulse/spawn-server", diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index b91c1c4d..b4766d5a 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ - 0 + 5 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 93 - 29 + 80 + 20 @@ -1933,7 +1933,7 @@ be useful for preventing those extensions from being used. 10 100 511 - 191 + 231 @@ -2108,6 +2108,22 @@ added by the ALC_EXT_DEDICATED extension. true + + + + 70 + 180 + 131 + 21 + + + + Pitch Shifter + + + true + + @@ -2130,8 +2146,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 125 - 29 + 108 + 20 @@ -2300,7 +2316,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 27 + 21 -- cgit v1.2.3 From df6e4617e435e7e9a3fcf1647fafcb8df6c0ef4d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 19 Mar 2018 06:41:38 -0700 Subject: Fix the reverb panning behavior to better fit the spec Previously it would attenuate the response from direction opposite to the vector, whereas the property descriptions say it should simply move all reflections toward the given direction. --- Alc/effects/reverb.c | 121 ++++++++++++++++----------------------------------- 1 file changed, 38 insertions(+), 83 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 46129934..bd5553ad 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1060,97 +1060,52 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co } } -/* Creates a transform matrix given a reverb vector. This works by first - * creating an inverse rotation around Y then X, applying a Z-focus transform, - * then non-inverse rotations back around X then Y, to place the focal point in - * the direction of the vector, using the vector length as a focus strength. - * - * This convoluted construction ultimately results in a B-Format transformation - * matrix that retains its original orientation, but spatially focuses the - * signal in the desired direction. There is probably a more efficient way to - * do this, but let's see how good the optimizer is. +/* Creates a transform matrix given a reverb vector. The vector pans the reverb + * reflections toward the given direction, using its magnitude (up to 1) as a + * focal strength. This function results in a B-Format transformation matrix + * that spatially focuses the signal in the desired direction. */ static aluMatrixf GetTransformFromVector(const ALfloat *vec) { const ALfloat sqrt_3 = 1.732050808f; - aluMatrixf zfocus, xrot, yrot; - aluMatrixf tmp1, tmp2; - ALfloat length; - ALfloat sa, a; - - length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - - /* Define a Z-focus (X in Ambisonics) transform, given the panning vector - * length. + aluMatrixf focus; + ALfloat norm[3]; + ALfloat mag; + + /* Normalize the panning vector according to the N3D scale, which has an + * extra sqrt(3) term on the directional components. Converting from OpenAL + * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however + * that the reverb panning vectors use right-handed coordinates, unlike the + * rest of OpenAL which use left-handed. This is fixed by negating Z, which + * cancels out with the B-Format Z negation. */ - sa = sinf(minf(length, 1.0f) * (F_PI/2.0f)); - aluMatrixfSet(&zfocus, - 1.0f/(1.0f+sa), 0.0f, 0.0f, sa/(1.0f+sa)/sqrt_3, - 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, 0.0f, - 0.0f, 0.0f, sqrtf((1.0f-sa)/(1.0f+sa)), 0.0f, - sa/(1.0f+sa)*sqrt_3, 0.0f, 0.0f, 1.0f/(1.0f+sa) - ); - - /* Define rotation around X (Y in Ambisonics) */ - a = atan2f(vec[1], sqrtf(vec[0]*vec[0] + vec[2]*vec[2])); - aluMatrixfSet(&xrot, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, cosf(a), sinf(a), - 0.0f, 0.0f, -sinf(a), cosf(a) - ); + mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(mag > 1.0f) + { + norm[0] = vec[0] / mag * -sqrt_3; + norm[1] = vec[1] / mag * sqrt_3; + norm[2] = vec[2] / mag * sqrt_3; + mag = 1.0f; + } + else + { + /* If the magnitude is less than or equal to 1, just apply the sqrt(3) + * term. There's no need to renormalize the magnitude since it would + * just be reapplied in the matrix. + */ + norm[0] = vec[0] * -sqrt_3; + norm[1] = vec[1] * sqrt_3; + norm[2] = vec[2] * sqrt_3; + } - /* Define rotation around Y (Z in Ambisonics). NOTE: EFX's reverb vectors - * use a right-handled coordinate system, compared to the rest of OpenAL - * which uses left-handed. This is fixed by negating Z, however it would - * need to also be negated to get a proper Ambisonics angle, thus - * cancelling it out. - */ - a = atan2f(-vec[0], vec[2]); - aluMatrixfSet(&yrot, - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, cosf(a), 0.0f, sinf(a), - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, -sinf(a), 0.0f, cosf(a) + aluMatrixfSet(&focus, + 1.0f, 0.0f, 0.0f, 0.0f, + norm[0], 1.0f-mag, 0.0f, 0.0f, + norm[1], 0.0f, 1.0f-mag, 0.0f, + norm[2], 0.0f, 0.0f, 1.0f-mag ); - /* First, define a matrix that applies the inverse of the Y- then X- - * rotation matrices, so that the desired direction lands on Z. - */ -#define MATRIX_INVMULT(_res, _m1, _m2) do { \ - int row, col; \ - for(col = 0;col < 4;col++) \ - { \ - for(row = 0;row < 4;row++) \ - _res.m[row][col] = _m1.m[0][row]*_m2.m[col][0] + \ - _m1.m[1][row]*_m2.m[col][1] + \ - _m1.m[2][row]*_m2.m[col][2] + \ - _m1.m[3][row]*_m2.m[col][3]; \ - } \ -} while(0) - MATRIX_INVMULT(tmp1, xrot, yrot); -#undef MATRIX_INVMULT - -#define MATRIX_MULT(_res, _m1, _m2) do { \ - int row, col; \ - for(col = 0;col < 4;col++) \ - { \ - for(row = 0;row < 4;row++) \ - _res.m[row][col] = _m1.m[row][0]*_m2.m[0][col] + \ - _m1.m[row][1]*_m2.m[1][col] + \ - _m1.m[row][2]*_m2.m[2][col] + \ - _m1.m[row][3]*_m2.m[3][col]; \ - } \ -} while(0) - /* Now apply matrices to focus on Z, then rotate back around X then Y, to - * result in a focus in the direction of the vector. - */ - MATRIX_MULT(tmp2, zfocus, tmp1); - MATRIX_MULT(tmp1, xrot, tmp2); - MATRIX_MULT(tmp2, yrot, tmp1); -#undef MATRIX_MULT - - return tmp2; + return focus; } /* Update the early and late 3D panning gains. */ -- cgit v1.2.3 From c38854fe3d83034237c244f1b8564d7834db3ff8 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Mon, 19 Mar 2018 16:48:00 +0100 Subject: EFX:Own size for pitch shifter buffers --- Alc/effects/pshifter.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 1a2ddef7..2bf911f8 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -29,6 +29,7 @@ #include "alError.h" #include "alu.h" +#define MAX_SIZE 2048 typedef struct ALcomplex{ @@ -67,17 +68,17 @@ typedef struct ALpshifterState { ALfloat Frequency; /*Effects buffers*/ - ALfloat InFIFO[BUFFERSIZE]; - ALfloat OutFIFO[BUFFERSIZE]; - ALfloat LastPhase[(BUFFERSIZE>>1) +1]; - ALfloat SumPhase[(BUFFERSIZE>>1) +1]; - ALfloat OutputAccum[BUFFERSIZE<<1]; - ALfloat window[BUFFERSIZE]; + ALfloat InFIFO[MAX_SIZE]; + ALfloat OutFIFO[MAX_SIZE]; + ALfloat LastPhase[(MAX_SIZE>>1) +1]; + ALfloat SumPhase[(MAX_SIZE>>1) +1]; + ALfloat OutputAccum[MAX_SIZE<<1]; + ALfloat window[MAX_SIZE]; - ALcomplex FFTbuffer[BUFFERSIZE]; + ALcomplex FFTbuffer[MAX_SIZE]; - ALfrequencyDomain Analysis_buffer[BUFFERSIZE]; - ALfrequencyDomain Syntesis_buffer[BUFFERSIZE]; + ALfrequencyDomain Analysis_buffer[MAX_SIZE]; + ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; } ALpshifterState; @@ -102,20 +103,20 @@ static void ALpshifterState_Construct(ALpshifterState *state) SET_VTABLE2(ALpshifterState, ALeffectState, state); /*Initializing parameters and set to zero the buffers */ - state->STFT_size = BUFFERSIZE>>1; + state->STFT_size = MAX_SIZE>>1; state->oversamp = 1<<2; state->step = state->STFT_size / state->oversamp ; state->FIFOLatency = state->step * ( state->oversamp-1 ); state->count = state->FIFOLatency; - memset(state->InFIFO, 0, BUFFERSIZE*sizeof(ALfloat)); - memset(state->OutFIFO, 0, BUFFERSIZE*sizeof(ALfloat)); - memset(state->FFTbuffer, 0, BUFFERSIZE*sizeof(ALcomplex)); - memset(state->LastPhase, 0, ((BUFFERSIZE>>1) +1)*sizeof(ALfloat)); - memset(state->SumPhase, 0, ((BUFFERSIZE>>1) +1)*sizeof(ALfloat)); - memset(state->OutputAccum, 0, (BUFFERSIZE<<1)*sizeof(ALfloat)); - memset(state->Analysis_buffer, 0, BUFFERSIZE*sizeof(ALfrequencyDomain)); + memset(state->InFIFO, 0, MAX_SIZE*sizeof(ALfloat)); + memset(state->OutFIFO, 0, MAX_SIZE*sizeof(ALfloat)); + memset(state->FFTbuffer, 0, MAX_SIZE*sizeof(ALcomplex)); + memset(state->LastPhase, 0, ((MAX_SIZE>>1) +1)*sizeof(ALfloat)); + memset(state->SumPhase, 0, ((MAX_SIZE>>1) +1)*sizeof(ALfloat)); + memset(state->OutputAccum, 0, (MAX_SIZE<<1)*sizeof(ALfloat)); + memset(state->Analysis_buffer, 0, MAX_SIZE*sizeof(ALfrequencyDomain)); /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ for ( i = 0; i < state->STFT_size>>1 ; i++ ) -- cgit v1.2.3 From 47260fc70b7f884c2e97e422c5bda4ed668335b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 20 Mar 2018 23:11:27 -0700 Subject: Update the multi-reverb example with improved transitions This better calculates the environment coverage by correctly calculating the portal's extents, improves the panning direction when close to the portal, and applies attenuation based on contribution. Movement has changed to make the listener move back and forth between environments with a stationary source, rather than continually looping environments with a position-relative source. --- examples/almultireverb.c | 379 +++++++++++++++++++++++++++++------------------ 1 file changed, 236 insertions(+), 143 deletions(-) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 47bc86e2..44398db3 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -231,12 +231,227 @@ static ALfloat dot_product(const ALfloat vec0[3], const ALfloat vec1[3]) return vec0[0]*vec1[0] + vec0[1]*vec1[1] + vec0[2]*vec1[2]; } +/* Helper to normalize a given vector. */ +static void normalize(ALfloat vec[3]) +{ + ALfloat mag = sqrtf(dot_product(vec, vec)); + if(mag > 0.00001f) + { + vec[0] /= mag; + vec[1] /= mag; + vec[2] /= mag; + } + else + { + vec[0] = 0.0f; + vec[1] = 0.0f; + vec[2] = 0.0f; + } +} + + +/* The main update function to update the listener and environment effects. */ +static void UpdateListenerAndEffects(float timediff, const ALuint slots[2], const ALuint effects[2], const EFXEAXREVERBPROPERTIES reverbs[2]) +{ + static const ALfloat listener_move_scale = 10.0f; + /* Individual reverb zones are connected via "portals". Each portal has a + * position (center point of the connecting area), a normal (facing + * direction), and a radius (approximate size of the connecting area). + */ + const ALfloat portal_pos[3] = { 0.0f, 0.0f, 0.0f }; + const ALfloat portal_norm[3] = { sqrtf(0.5f), 0.0f, -sqrtf(0.5f) }; + const ALfloat portal_radius = 2.5f; + ALfloat other_dir[3], this_dir[3]; + ALfloat listener_pos[3]; + ALfloat local_norm[3]; + ALfloat local_dir[3]; + ALfloat near_edge[3]; + ALfloat far_edge[3]; + ALfloat dist, edist; + + /* Update the listener position for the amount of time passed. This uses a + * simple triangular LFO to offset the position (moves along the X axis + * between -listener_move_scale and +listener_move_scale for each + * transition). + */ + listener_pos[0] = (fabsf(2.0f - timediff/2.0f) - 1.0f) * listener_move_scale; + listener_pos[1] = 0.0f; + listener_pos[2] = 0.0f; + alListenerfv(AL_POSITION, listener_pos); + + /* Calculate local_dir, which represents the listener-relative point to the + * adjacent zone (should also include orientation). Because EAX Reverb uses + * right-handed coordinates instead of left-handed like the rest of OpenAL, + * negate Z for the local values. + */ + local_dir[0] = portal_pos[0] - listener_pos[0]; + local_dir[1] = portal_pos[1] - listener_pos[1]; + local_dir[2] = -(portal_pos[2] - listener_pos[2]); + /* A normal application would also rotate the portal's normal given the + * listener orientation, to get the listener-relative normal. + */ + local_norm[0] = portal_norm[0]; + local_norm[1] = portal_norm[1]; + local_norm[2] = -portal_norm[2]; + + /* Calculate the distance from the listener to the portal, and ensure it's + * far enough away to not suffer severe floating-point precision issues. + */ + dist = sqrtf(dot_product(local_dir, local_dir)); + if(dist > 0.00001f) + { + const EFXEAXREVERBPROPERTIES *other_reverb, *this_reverb; + ALuint other_effect, this_effect; + ALfloat magnitude, dir_dot_norm; + + /* Normalize the direction to the portal. */ + local_dir[0] /= dist; + local_dir[1] /= dist; + local_dir[2] /= dist; + + /* Calculate the dot product of the portal's local direction and local + * normal, which is used for angular and side checks later on. + */ + dir_dot_norm = dot_product(local_dir, local_norm); + + /* Figure out which zone we're in. */ + if(dir_dot_norm <= 0.0f) + { + /* We're in front of the portal, so we're in Zone 0. */ + this_effect = effects[0]; + other_effect = effects[1]; + this_reverb = &reverbs[0]; + other_reverb = &reverbs[1]; + } + else + { + /* We're behind the portal, so we're in Zone 1. */ + this_effect = effects[1]; + other_effect = effects[0]; + this_reverb = &reverbs[1]; + other_reverb = &reverbs[0]; + } + + /* Calculate the listener-relative extents of the portal. */ + /* First, project the listener-to-portal vector onto the portal's plane + * to get the portal-relative direction along the plane that goes away + * from the listener (toward the farthest edge of the portal). + */ + far_edge[0] = local_dir[0] - local_norm[0]*dir_dot_norm; + far_edge[1] = local_dir[1] - local_norm[1]*dir_dot_norm; + far_edge[2] = local_dir[2] - local_norm[2]*dir_dot_norm; + + edist = sqrtf(dot_product(far_edge, far_edge)); + if(edist > 0.0001f) + { + /* Rescale the portal-relative vector to be at the radius edge. */ + ALfloat mag = portal_radius / edist; + far_edge[0] *= mag; + far_edge[1] *= mag; + far_edge[2] *= mag; + + /* Calculate the closest edge of the portal by negating the + * farthest, and add an offset to make them both relative to the + * listener. + */ + near_edge[0] = local_dir[0]*dist - far_edge[0]; + near_edge[1] = local_dir[1]*dist - far_edge[1]; + near_edge[2] = local_dir[2]*dist - far_edge[2]; + far_edge[0] += local_dir[0]*dist; + far_edge[1] += local_dir[1]*dist; + far_edge[2] += local_dir[2]*dist; + + /* Normalize the listener-relative extents of the portal, then + * calculate the panning magnitude for the other zone given the + * apparent size of the opening. The panning magnitude affects the + * envelopment of the environment, with 1 being a point, 0.5 being + * half coverage around the listener, and 0 being full coverage. + */ + normalize(far_edge); + normalize(near_edge); + magnitude = 1.0f - acosf(dot_product(far_edge, near_edge))/(float)(M_PI*2.0); + + /* Recalculate the panning direction, to be directly between the + * direction of the two extents. + */ + local_dir[0] = far_edge[0] + near_edge[0]; + local_dir[1] = far_edge[1] + near_edge[1]; + local_dir[2] = far_edge[2] + near_edge[2]; + normalize(local_dir); + } + else + { + /* If we get here, the listener is directly in front of or behind + * the center of the portal, making all aperture edges effectively + * equidistant. Calculating the panning magnitude is simplified, + * using the arctangent of the radius and distance. + */ + magnitude = 1.0f - (atan2f(portal_radius, dist) / (float)M_PI); + } + + /* Scale the other zone's panning vector. */ + other_dir[0] = local_dir[0] * magnitude; + other_dir[1] = local_dir[1] * magnitude; + other_dir[2] = local_dir[2] * magnitude; + /* Pan the current zone to the opposite direction of the portal, and + * take the remaining percentage of the portal's magnitude. + */ + this_dir[0] = local_dir[0] * (magnitude-1.0f); + this_dir[1] = local_dir[1] * (magnitude-1.0f); + this_dir[2] = local_dir[2] * (magnitude-1.0f); + + /* Now set the effects' panning vectors and gain. Energy is shared + * between environments, so attenuate according to each zone's + * contribution (note: gain^2 = energy). + */ + alEffectf(this_effect, AL_EAXREVERB_REFLECTIONS_GAIN, this_reverb->flReflectionsGain * sqrtf(magnitude)); + alEffectf(this_effect, AL_EAXREVERB_LATE_REVERB_GAIN, this_reverb->flLateReverbGain * sqrtf(magnitude)); + alEffectfv(this_effect, AL_EAXREVERB_REFLECTIONS_PAN, this_dir); + alEffectfv(this_effect, AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + + alEffectf(other_effect, AL_EAXREVERB_REFLECTIONS_GAIN, other_reverb->flReflectionsGain * sqrtf(1.0f-magnitude)); + alEffectf(other_effect, AL_EAXREVERB_LATE_REVERB_GAIN, other_reverb->flLateReverbGain * sqrtf(1.0f-magnitude)); + alEffectfv(other_effect, AL_EAXREVERB_REFLECTIONS_PAN, other_dir); + alEffectfv(other_effect, AL_EAXREVERB_LATE_REVERB_PAN, other_dir); + } + else + { + /* We're practically in the center of the portal. Give the panning + * vectors a 50/50 split, with Zone 0 covering the half in front of + * the normal, and Zone 1 covering the half behind. + */ + this_dir[0] = local_norm[0] / 2.0f; + this_dir[1] = local_norm[1] / 2.0f; + this_dir[2] = local_norm[2] / 2.0f; + + other_dir[0] = local_norm[0] / -2.0f; + other_dir[1] = local_norm[1] / -2.0f; + other_dir[2] = local_norm[2] / -2.0f; + + alEffectf(effects[0], AL_EAXREVERB_REFLECTIONS_GAIN, reverbs[0].flReflectionsGain * sqrtf(0.5f)); + alEffectf(effects[0], AL_EAXREVERB_LATE_REVERB_GAIN, reverbs[0].flLateReverbGain * sqrtf(0.5f)); + alEffectfv(effects[0], AL_EAXREVERB_REFLECTIONS_PAN, this_dir); + alEffectfv(effects[0], AL_EAXREVERB_LATE_REVERB_PAN, this_dir); + + alEffectf(effects[1], AL_EAXREVERB_REFLECTIONS_GAIN, reverbs[1].flReflectionsGain * sqrtf(0.5f)); + alEffectf(effects[1], AL_EAXREVERB_LATE_REVERB_GAIN, reverbs[1].flLateReverbGain * sqrtf(0.5f)); + alEffectfv(effects[1], AL_EAXREVERB_REFLECTIONS_PAN, other_dir); + alEffectfv(effects[1], AL_EAXREVERB_LATE_REVERB_PAN, other_dir); + } + + /* Finally, update the effect slots with the updated effect parameters. */ + alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); + alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); +} + int main(int argc, char **argv) { static const int MaxTransitions = 8; - EFXEAXREVERBPROPERTIES reverb0 = EFX_REVERB_PRESET_CARPETEDHALLWAY; - EFXEAXREVERBPROPERTIES reverb1 = EFX_REVERB_PRESET_BATHROOM; + EFXEAXREVERBPROPERTIES reverbs[2] = { + EFX_REVERB_PRESET_CARPETEDHALLWAY, + EFX_REVERB_PRESET_BATHROOM + }; struct timespec basetime; ALCdevice *device = NULL; ALCcontext *context = NULL; @@ -363,7 +578,7 @@ int main(int argc, char **argv) * relative to the listener. */ alGenEffects(2, effects); - if(!LoadEffect(effects[0], &reverb0) || !LoadEffect(effects[1], &reverb1)) + if(!LoadEffect(effects[0], &reverbs[0]) || !LoadEffect(effects[1], &reverbs[1])) { alDeleteEffects(2, effects); alDeleteBuffers(1, &buffer); @@ -396,10 +611,13 @@ int main(int argc, char **argv) alFilterf(direct_filter, AL_LOWPASS_GAIN, direct_gain); assert(alGetError()==AL_NO_ERROR && "Failed to set direct filter"); - /* Create the source to play the sound with. */ + /* Create the source to play the sound with, place it in front of the + * listener's path in the left zone. + */ source = 0; alGenSources(1, &source); alSourcei(source, AL_LOOPING, AL_TRUE); + alSource3f(source, AL_POSITION, -5.0f, 0.0f, -2.0f); alSourcei(source, AL_DIRECT_FILTER, direct_filter); alSourcei(source, AL_BUFFER, buffer); @@ -407,7 +625,8 @@ int main(int argc, char **argv) * to Zone 0's slot, and send 1 to Zone 1's slot. Filters can be specified * to occlude the source from each zone by varying amounts; for example, a * source within a particular zone would be unfiltered, while a source that - * can only see a zone through a window may be attenuated for that zone. + * can only see a zone through a window or thin wall may be attenuated for + * that zone. */ alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[0], 0, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, slots[1], 1, AL_FILTER_NULL); @@ -421,23 +640,8 @@ int main(int argc, char **argv) /* Play the sound for a while. */ alSourcePlay(source); do { - /* Individual reverb zones are connected via "portals". Each portal has - * a position (center point of the connecting area), a normal (facing - * direction), and a radius (approximate size of the connecting area). - * For this example it also has movement velocity, although normally it - * would be the listener that moves relative to the portal instead of - * the portal itself. - */ - const ALfloat portal_pos[3] = { -10.0f, 0.0f, 0.0f }; - const ALfloat portal_norm[3] = { 1.0f, 0.0f, 0.0f }; - const ALfloat portal_vel[3] = { 5.0f, 0.0f, 0.0f }; - const ALfloat portal_radius = 2.5f; - ALfloat other_dir[3], this_dir[3]; - ALfloat local_norm[3]; - ALfloat local_dir[3]; - ALfloat local_radius; - ALfloat dist, timediff; struct timespec curtime; + ALfloat timediff; /* Start a batch update, to ensure all changes apply simultaneously. */ alcSuspendContext(context); @@ -452,136 +656,25 @@ int main(int argc, char **argv) /* Avoid negative time deltas, in case of non-monotonic clocks. */ if(timediff < 0.0f) timediff = 0.0f; - else while(timediff >= 4.0f) + else while(timediff >= 4.0f*((loops&1)+1)) { - /* For this example, each transition occurs over 4 seconds. - * Decrease the delta and increase the base time to start a new - * transition. + /* For this example, each transition occurs over 4 seconds, and + * there's 2 transitions per cycle. */ - timediff -= 4.0f; - basetime.tv_sec += 4; if(++loops < MaxTransitions) printf("Transition %d of %d...\n", loops+1, MaxTransitions); - } - - /* Move the portal according to the amount of time passed. local_dir - * represents the listener-relative point to the adjacent zone. - */ - local_dir[0] = portal_pos[0] + portal_vel[0]*timediff; - local_dir[1] = portal_pos[1] + portal_vel[1]*timediff; - local_dir[2] = portal_pos[2] + portal_vel[2]*timediff; - /* A normal application would also rotate the portal's normal given the - * listener orientation, to get the listener-relative normal. - * - * For this example, the portal is always head-on but every other - * transition negates the normal. This effectively simulates a - * different portal moving in closer than the last one that faces the - * other way, switching the old adjacent zone to a new one. - */ - local_norm[0] = portal_norm[0] * ((loops&1) ? -1.0f : 1.0f); - local_norm[1] = portal_norm[1] * ((loops&1) ? -1.0f : 1.0f); - local_norm[2] = portal_norm[2] * ((loops&1) ? -1.0f : 1.0f); - - /* Calculate the distance from the listener to the portal. */ - dist = sqrtf(dot_product(local_dir, local_dir)); - if(!(dist > 0.00001f)) - { - /* We're practically in the center of the portal. Give the panning - * vectors a 50/50 split, with Zone 0 covering the half in front of - * the normal, and Zone 1 covering the half behind. - */ - this_dir[0] = local_norm[0] / 2.0f; - this_dir[1] = local_norm[1] / 2.0f; - this_dir[2] = local_norm[2] / 2.0f; - - other_dir[0] = local_norm[0] / -2.0f; - other_dir[1] = local_norm[1] / -2.0f; - other_dir[2] = local_norm[2] / -2.0f; - - alEffectf(effects[0], AL_EAXREVERB_GAIN, reverb0.flGain); - alEffectfv(effects[0], AL_EAXREVERB_REFLECTIONS_PAN, this_dir); - alEffectfv(effects[0], AL_EAXREVERB_LATE_REVERB_PAN, this_dir); - - alEffectf(effects[1], AL_EAXREVERB_GAIN, reverb1.flGain); - alEffectfv(effects[1], AL_EAXREVERB_REFLECTIONS_PAN, other_dir); - alEffectfv(effects[1], AL_EAXREVERB_LATE_REVERB_PAN, other_dir); - } - else - { - const EFXEAXREVERBPROPERTIES *other_reverb; - const EFXEAXREVERBPROPERTIES *this_reverb; - ALuint other_effect, this_effect; - ALfloat spread, attn; - - /* Normalize the direction to the portal. */ - local_dir[0] /= dist; - local_dir[1] /= dist; - local_dir[2] /= dist; - - /* Scale the radius according to its local angle. The visibility to - * the other zone reduces as the portal becomes perpendicular. - */ - local_radius = portal_radius * fabsf(dot_product(local_dir, local_norm)); - - /* Calculate distance attenuation for the other zone, using the - * standard inverse distance model with the radius as a reference. - */ - attn = local_radius / dist; - if(attn > 1.0f) attn = 1.0f; - - /* Calculate the 'spread' of the portal, which is the amount of - * coverage the other zone has around the listener. - */ - spread = atan2f(local_radius, dist) / (ALfloat)M_PI; - - /* Figure out which zone we're in, given the direction to the - * portal and its normal. - */ - if(dot_product(local_dir, local_norm) <= 0.0f) - { - /* We're in front of the portal, so we're in Zone 0. */ - this_effect = effects[0]; - other_effect = effects[1]; - this_reverb = &reverb0; - other_reverb = &reverb1; - } - else + if(!(loops&1)) { - /* We're behind the portal, so we're in Zone 1. */ - this_effect = effects[1]; - other_effect = effects[0]; - this_reverb = &reverb1; - other_reverb = &reverb0; + /* Cycle completed. Decrease the delta and increase the base + * time to start a new cycle. + */ + timediff -= 8.0f; + basetime.tv_sec += 8; } - - /* Scale the other zone's panning vector down as the portal's - * spread increases, so that it envelops the listener more. - */ - other_dir[0] = local_dir[0] * (1.0f-spread); - other_dir[1] = local_dir[1] * (1.0f-spread); - other_dir[2] = local_dir[2] * (1.0f-spread); - /* Pan the current zone to the opposite direction of the portal, - * and take the remaining percentage of the portal's spread. - */ - this_dir[0] = local_dir[0] * -spread; - this_dir[1] = local_dir[1] * -spread; - this_dir[2] = local_dir[2] * -spread; - - /* Now set the effects' panning vectors and distance attenuation. */ - alEffectf(this_effect, AL_EAXREVERB_GAIN, this_reverb->flGain); - alEffectfv(this_effect, AL_EAXREVERB_REFLECTIONS_PAN, this_dir); - alEffectfv(this_effect, AL_EAXREVERB_LATE_REVERB_PAN, this_dir); - - alEffectf(other_effect, AL_EAXREVERB_GAIN, other_reverb->flGain * attn); - alEffectfv(other_effect, AL_EAXREVERB_REFLECTIONS_PAN, other_dir); - alEffectfv(other_effect, AL_EAXREVERB_LATE_REVERB_PAN, other_dir); } - /* Finally, update the effect slots with the updated effect parameters, - * and finish the update batch. - */ - alAuxiliaryEffectSloti(slots[0], AL_EFFECTSLOT_EFFECT, effects[0]); - alAuxiliaryEffectSloti(slots[1], AL_EFFECTSLOT_EFFECT, effects[1]); + /* Update the listener and effects, and finish the batch. */ + UpdateListenerAndEffects(timediff, slots, effects, reverbs); alcProcessContext(context); al_nssleep(10000000); -- cgit v1.2.3 From 55a73b8df94ce3abc4d6c6a654e2516acf8ef631 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 01:56:42 -0700 Subject: Fix for older MSVC lacking strtof --- examples/alrecord.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/alrecord.c b/examples/alrecord.c index c21ba30b..43b26d35 100644 --- a/examples/alrecord.c +++ b/examples/alrecord.c @@ -45,6 +45,13 @@ #endif +#if defined(_MSC_VER) && (_MSC_VER < 1900) +static float msvc_strtof(const char *str, char **end) +{ return (float)strtod(str, end); } +#define strtof msvc_strtof +#endif + + static void fwrite16le(ALushort val, FILE *f) { ALubyte data[2] = { val&0xff, (val>>8)&0xff }; -- cgit v1.2.3 From ecc51c8c55f01e961bd2e82f8c408ce3c5a525d4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 08:56:26 -0700 Subject: Clean up some code formatting in the pitch shifter source Clean up excessive newlines and extra-long comments, move static inline definitions to their declarations. --- Alc/effects/pshifter.c | 972 ++++++++++++++++++++++++------------------------- 1 file changed, 478 insertions(+), 494 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 2bf911f8..a9921028 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -1,494 +1,478 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" - -#define MAX_SIZE 2048 - -typedef struct ALcomplex{ - - ALfloat Real; - ALfloat Imag; - -}ALcomplex; - -typedef struct ALphasor{ - - ALfloat Amplitude; - ALfloat Phase; - -}ALphasor; - -typedef struct ALFrequencyDomain{ - - ALfloat Amplitude; - ALfloat Frequency; - -}ALfrequencyDomain; - -typedef struct ALpshifterState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; - - /* Effect parameters */ - ALsizei count; - ALsizei STFT_size; - ALsizei step; - ALsizei FIFOLatency; - ALsizei oversamp; - ALfloat PitchShift; - ALfloat Frequency; - - /*Effects buffers*/ - ALfloat InFIFO[MAX_SIZE]; - ALfloat OutFIFO[MAX_SIZE]; - ALfloat LastPhase[(MAX_SIZE>>1) +1]; - ALfloat SumPhase[(MAX_SIZE>>1) +1]; - ALfloat OutputAccum[MAX_SIZE<<1]; - ALfloat window[MAX_SIZE]; - - ALcomplex FFTbuffer[MAX_SIZE]; - - ALfrequencyDomain Analysis_buffer[MAX_SIZE]; - ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; - - -} ALpshifterState; - -static inline ALphasor rect2polar( ALcomplex number ); -static inline ALcomplex polar2rect( ALphasor number ); -static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign); - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state); -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); - -static void ALpshifterState_Construct(ALpshifterState *state) -{ - ALsizei i; - - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALpshifterState, ALeffectState, state); - - /*Initializing parameters and set to zero the buffers */ - state->STFT_size = MAX_SIZE>>1; - state->oversamp = 1<<2; - - state->step = state->STFT_size / state->oversamp ; - state->FIFOLatency = state->step * ( state->oversamp-1 ); - state->count = state->FIFOLatency; - - memset(state->InFIFO, 0, MAX_SIZE*sizeof(ALfloat)); - memset(state->OutFIFO, 0, MAX_SIZE*sizeof(ALfloat)); - memset(state->FFTbuffer, 0, MAX_SIZE*sizeof(ALcomplex)); - memset(state->LastPhase, 0, ((MAX_SIZE>>1) +1)*sizeof(ALfloat)); - memset(state->SumPhase, 0, ((MAX_SIZE>>1) +1)*sizeof(ALfloat)); - memset(state->OutputAccum, 0, (MAX_SIZE<<1)*sizeof(ALfloat)); - memset(state->Analysis_buffer, 0, MAX_SIZE*sizeof(ALfrequencyDomain)); - - /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ - for ( i = 0; i < state->STFT_size>>1 ; i++ ) - { - state->window[i] = state->window[state->STFT_size-(i+1)] \ - = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(state->STFT_size-1))); - } -} - -static ALvoid ALpshifterState_Destruct(ALpshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *UNUSED(state), ALCdevice *UNUSED(device)) -{ - return AL_TRUE; -} - -static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - const ALfloat adjust = 0.707945784384f; /*-3dB adjust*/ - - state->Frequency = (ALfloat)device->Frequency; - state->PitchShift = powf(2.0f,((ALfloat)props->Pshifter.CoarseTune + props->Pshifter.FineTune/100.0f)/12.0f); - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * adjust, state->Gain); -} - -static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - /*Pitch shifter engine based on the work of Stephan Bernsee. - * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ **/ - - ALsizei i, j, k, STFT_half_size; - ALfloat freq_bin, expected, tmp; - ALfloat bufferOut[BUFFERSIZE]; - ALphasor component; - - - STFT_half_size = state->STFT_size >> 1; - freq_bin = state->Frequency / (ALfloat)state->STFT_size; - expected = F_TAU / (ALfloat)state->oversamp; - - - for (i = 0; i < SamplesToDo; i++) - { - /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[state->count - state->FIFOLatency]; - - state->count++; - - /* Check whether FIFO buffer is filled */ - if ( state->count >= state->STFT_size ) - { - state->count = state->FIFOLatency; - - /* Real signal windowing and store in FFTbuffer */ - for ( k = 0; k < state->STFT_size; k++ ) - { - state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; - state->FFTbuffer[k].Imag = 0.0f; - } - - /* ANALYSIS */ - /* Apply FFT to FFTbuffer data */ - FFT( state->FFTbuffer, state->STFT_size, -1 ); - - /* Analyze the obtained data. Since the real FFT is symmetric, only STFT_half_size+1 samples are needed */ - for ( k = 0; k <= STFT_half_size; k++ ) - { - /* Compute amplitude and phase */ - component = rect2polar( state->FFTbuffer[k] ); - - /* Compute phase difference and subtract expected phase difference */ - tmp = ( component.Phase - state->LastPhase[k] ) - (ALfloat)k*expected; - - /* Map delta phase into +/- Pi interval */ - tmp -= F_PI*(ALfloat)( fastf2i(tmp/F_PI) + fastf2i(tmp/F_PI) % 2 ); - - /* Get deviation from bin frequency from the +/- Pi interval */ - tmp /= expected; - - /* Compute the k-th partials' true frequency, twice the amplitude for maintain the gain - (because half of bins are used) and store amplitude and true frequency in analysis buffer */ - state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; - state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; - - /* Store actual phase[k] for the calculations in the next frame*/ - state->LastPhase[k] = component.Phase; - - } - - /* PROCESSING */ - /* pitch shifting */ - memset(state->Syntesis_buffer, 0, state->STFT_size*sizeof(ALfrequencyDomain)); - - for (k = 0; k <= STFT_half_size; k++) - { - j = fastf2i( (ALfloat)k*state->PitchShift ); - - if ( j <= STFT_half_size ) - { - state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; - state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * state->PitchShift; - } - } - - /* SYNTHESIS */ - /* Synthesis the processing data */ - for ( k = 0; k <= STFT_half_size; k++ ) - { - /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency /freq_bin - (ALfloat)k; - - /* Calculate actual delta phase and accumulate it to get bin phase */ - state->SumPhase[k] += ((ALfloat)k + tmp) * expected; - - component.Amplitude = state->Syntesis_buffer[k].Amplitude; - component.Phase = state->SumPhase[k]; - - /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - state->FFTbuffer[k] = polar2rect( component ); - } - - /* zero negative frequencies for recontruct a real signal */ - memset( &state->FFTbuffer[STFT_half_size+1], 0, (STFT_half_size-1) * sizeof(ALcomplex) ); - - /* Apply iFFT to buffer data */ - FFT( state->FFTbuffer, state->STFT_size, 1 ); - - /* Windowing and add to output */ - for( k=0; k < state->STFT_size; k++ ) - { - state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / (STFT_half_size * state->oversamp); - } - - /* Shift accumulator, input & output FIFO */ - memmove(state->OutFIFO , state->OutputAccum , state->step * sizeof(ALfloat)); - memmove(state->OutputAccum, state->OutputAccum + state->step, state->STFT_size * sizeof(ALfloat)); - memmove(state->InFIFO , state->InFIFO + state->step, state->FIFOLatency * sizeof(ALfloat)); - - } - } - - /* Now, mix the processed sound data to the output*/ - - for (j = 0; j < NumChannels; j++ ) - { - ALfloat gain = state->Gain[j]; - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < SamplesToDo;i++) - SamplesOut[j][i] += gain * bufferOut[i]; - - } - - -} - -typedef struct PshifterStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} PshifterStateFactory; - -static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) -{ - ALpshifterState *state; - - NEW_OBJ0(state, ALpshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); - -EffectStateFactory *PshifterStateFactory_getFactory(void) -{ - static PshifterStateFactory PshifterFactory = { { GET_VTABLE2(PshifterStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &PshifterFactory); -} - - -void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) -{ - alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param ); -} - -void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) -{ - alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param ); -} - -void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); - props->Pshifter.CoarseTune = val; - break; - - case AL_PITCH_SHIFTER_FINE_TUNE: - if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); - props->Pshifter.FineTune = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALpshifter_setParami(effect, context, param, vals[0]); -} - -void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_PITCH_SHIFTER_COARSE_TUNE: - *val = (ALint)props->Pshifter.CoarseTune; - break; - case AL_PITCH_SHIFTER_FINE_TUNE: - *val = (ALint)props->Pshifter.FineTune; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); - } -} -void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALpshifter_getParami(effect, context, param, vals); -} - -void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); -} - -void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) -{ - alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); -} - -DEFINE_ALEFFECT_VTABLE(ALpshifter); - - -/* Converts ALcomplex to ALphasor*/ -static inline ALphasor rect2polar( ALcomplex number ) -{ - ALphasor polar; - - polar.Amplitude = sqrtf ( number.Real*number.Real + number.Imag*number.Imag ); - polar.Phase = atan2f( number.Imag , number.Real ); - - return polar; -} - -/* Converts ALphasor to ALcomplex*/ -static inline ALcomplex polar2rect( ALphasor number ) -{ - ALcomplex cartesian; - - cartesian.Real = number.Amplitude * cosf( number.Phase ); - cartesian.Imag = number.Amplitude * sinf( number.Phase ); - - return cartesian; -} - -/* Addition of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_add( ALcomplex a, ALcomplex b ) -{ - ALcomplex result; - - result.Real = ( a.Real + b.Real ); - result.Imag = ( a.Imag + b.Imag ); - - return result; -} - -/* Substraction of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_subst( ALcomplex a, ALcomplex b ) -{ - ALcomplex result; - - result.Real = ( a.Real - b.Real ); - result.Imag = ( a.Imag - b.Imag ); - - return result; -} - -/* Multiplication of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_mult( ALcomplex a, ALcomplex b ) -{ - ALcomplex result; - - result.Real = ( a.Real * b.Real - a.Imag * b.Imag ); - result.Imag = ( a.Imag * b.Real + a.Real * b.Imag ); - - return result; -} - -/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is FFT and 1 is - iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the Discrete Fourier Transform (DFT) - of the time domain data stored in FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of - complex numbers (ALcomplex), FFTSize MUST BE power of two.*/ - -static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign) -{ - ALfloat arg; - ALsizei i, j, k, mask, step, step2; - ALcomplex temp, u, w; - - /*bit-reversal permutation applied to a sequence of FFTSize items*/ - for (i = 1; i < FFTSize-1; i++ ) - { - - for ( mask = 0x1, j = 0; mask < FFTSize; mask <<= 1 ) - { - if ( ( i & mask ) != 0 ) j++; - - j <<= 1; - } - - j >>= 1; - - if ( i < j ) - { - temp = FFTBuffer[i]; - FFTBuffer[i] = FFTBuffer[j]; - FFTBuffer[j] = temp; - } - } - - /* Iterative form of Danielson–Lanczos lemma */ - for ( i = 1, step = 2; i < FFTSize; i<<=1, step <<= 1 ) - { - - step2 = step >> 1; - arg = F_PI / step2; - - w.Real = cosf( arg ); - w.Imag = sinf( arg ) * Sign; - - u.Real = 1.0f; - u.Imag = 0.0f; - - for ( j = 0; j < step2; j++ ) - { - - for ( k = j; k < FFTSize; k += step ) - { - - temp = complex_mult( FFTBuffer[k+step2], u ); - FFTBuffer[k+step2] = complex_subst( FFTBuffer[k], temp ); - FFTBuffer[k] = complex_add( FFTBuffer[k], temp ); - } - - u = complex_mult(u,w); - } - } -} +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + +#define MAX_SIZE 2048 + +typedef struct ALcomplex { + ALfloat Real; + ALfloat Imag; +} ALcomplex; + +typedef struct ALphasor { + ALfloat Amplitude; + ALfloat Phase; +} ALphasor; + +typedef struct ALFrequencyDomain { + ALfloat Amplitude; + ALfloat Frequency; +} ALfrequencyDomain; + +typedef struct ALpshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect gains for each channel */ + ALfloat Gain[MAX_OUTPUT_CHANNELS]; + + /* Effect parameters */ + ALsizei count; + ALsizei STFT_size; + ALsizei step; + ALsizei FIFOLatency; + ALsizei oversamp; + ALfloat PitchShift; + ALfloat Frequency; + + /*Effects buffers*/ + ALfloat InFIFO[MAX_SIZE]; + ALfloat OutFIFO[MAX_SIZE]; + ALfloat LastPhase[(MAX_SIZE>>1) +1]; + ALfloat SumPhase[(MAX_SIZE>>1) +1]; + ALfloat OutputAccum[MAX_SIZE<<1]; + ALfloat window[MAX_SIZE]; + + ALcomplex FFTbuffer[MAX_SIZE]; + + ALfrequencyDomain Analysis_buffer[MAX_SIZE]; + ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; +} ALpshifterState; + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state); +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device); +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); + + +/* Converts ALcomplex to ALphasor*/ +static inline ALphasor rect2polar( ALcomplex number ) +{ + ALphasor polar; + + polar.Amplitude = sqrtf ( number.Real*number.Real + number.Imag*number.Imag ); + polar.Phase = atan2f( number.Imag , number.Real ); + + return polar; +} + +/* Converts ALphasor to ALcomplex*/ +static inline ALcomplex polar2rect( ALphasor number ) +{ + ALcomplex cartesian; + + cartesian.Real = number.Amplitude * cosf( number.Phase ); + cartesian.Imag = number.Amplitude * sinf( number.Phase ); + + return cartesian; +} + +/* Addition of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_add( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real + b.Real ); + result.Imag = ( a.Imag + b.Imag ); + + return result; +} + +/* Substraction of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_subst( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real - b.Real ); + result.Imag = ( a.Imag - b.Imag ); + + return result; +} + +/* Multiplication of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_mult( ALcomplex a, ALcomplex b ) +{ + ALcomplex result; + + result.Real = ( a.Real * b.Real - a.Imag * b.Imag ); + result.Imag = ( a.Imag * b.Real + a.Real * b.Imag ); + + return result; +} + +/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is FFT and 1 is + iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the Discrete Fourier Transform (DFT) + of the time domain data stored in FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of + complex numbers (ALcomplex), FFTSize MUST BE power of two.*/ +static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign) +{ + ALfloat arg; + ALsizei i, j, k, mask, step, step2; + ALcomplex temp, u, w; + + /*bit-reversal permutation applied to a sequence of FFTSize items*/ + for (i = 1; i < FFTSize-1; i++ ) + { + for ( mask = 0x1, j = 0; mask < FFTSize; mask <<= 1 ) + { + if ( ( i & mask ) != 0 ) j++; + + j <<= 1; + } + + j >>= 1; + + if ( i < j ) + { + temp = FFTBuffer[i]; + FFTBuffer[i] = FFTBuffer[j]; + FFTBuffer[j] = temp; + } + } + + /* Iterative form of Danielson–Lanczos lemma */ + for ( i = 1, step = 2; i < FFTSize; i<<=1, step <<= 1 ) + { + step2 = step >> 1; + arg = F_PI / step2; + + w.Real = cosf( arg ); + w.Imag = sinf( arg ) * Sign; + + u.Real = 1.0f; + u.Imag = 0.0f; + + for ( j = 0; j < step2; j++ ) + { + for ( k = j; k < FFTSize; k += step ) + { + temp = complex_mult( FFTBuffer[k+step2], u ); + FFTBuffer[k+step2] = complex_subst( FFTBuffer[k], temp ); + FFTBuffer[k] = complex_add( FFTBuffer[k], temp ); + } + + u = complex_mult(u,w); + } + } +} + + +static void ALpshifterState_Construct(ALpshifterState *state) +{ + ALsizei i; + + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALpshifterState, ALeffectState, state); + + /*Initializing parameters and set to zero the buffers */ + state->STFT_size = MAX_SIZE>>1; + state->oversamp = 1<<2; + + state->step = state->STFT_size / state->oversamp ; + state->FIFOLatency = state->step * ( state->oversamp-1 ); + state->count = state->FIFOLatency; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); + memset(state->LastPhase, 0, sizeof(state->LastPhase)); + memset(state->SumPhase, 0, sizeof(state->SumPhase)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); + + /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ + for ( i = 0; i < state->STFT_size>>1 ; i++ ) + { + state->window[i] = state->window[state->STFT_size-(i+1)] \ + = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(state->STFT_size-1))); + } +} + +static ALvoid ALpshifterState_Destruct(ALpshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *UNUSED(state), ALCdevice *UNUSED(device)) +{ + return AL_TRUE; +} + +static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + const ALfloat adjust = 0.707945784384f; /*-3dB adjust*/ + + state->Frequency = (ALfloat)device->Frequency; + state->PitchShift = powf(2.0f,((ALfloat)props->Pshifter.CoarseTune + props->Pshifter.FineTune/100.0f)/12.0f); + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * adjust, state->Gain); +} + +static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + /* Pitch shifter engine based on the work of Stephan Bernsee. + * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ + */ + + ALsizei i, j, k, STFT_half_size; + ALfloat freq_bin, expected, tmp; + ALfloat bufferOut[BUFFERSIZE]; + ALphasor component; + + STFT_half_size = state->STFT_size >> 1; + freq_bin = state->Frequency / (ALfloat)state->STFT_size; + expected = F_TAU / (ALfloat)state->oversamp; + + for (i = 0; i < SamplesToDo; i++) + { + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + bufferOut[i] = state->OutFIFO[state->count - state->FIFOLatency]; + + state->count++; + + /* Check whether FIFO buffer is filled */ + if ( state->count >= state->STFT_size ) + { + state->count = state->FIFOLatency; + + /* Real signal windowing and store in FFTbuffer */ + for ( k = 0; k < state->STFT_size; k++ ) + { + state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; + state->FFTbuffer[k].Imag = 0.0f; + } + + /* ANALYSIS */ + /* Apply FFT to FFTbuffer data */ + FFT( state->FFTbuffer, state->STFT_size, -1 ); + + /* Analyze the obtained data. Since the real FFT is symmetric, only + * STFT_half_size+1 samples are needed. + */ + for ( k = 0; k <= STFT_half_size; k++ ) + { + /* Compute amplitude and phase */ + component = rect2polar( state->FFTbuffer[k] ); + + /* Compute phase difference and subtract expected phase difference */ + tmp = ( component.Phase - state->LastPhase[k] ) - (ALfloat)k*expected; + + /* Map delta phase into +/- Pi interval */ + tmp -= F_PI*(ALfloat)( fastf2i(tmp/F_PI) + fastf2i(tmp/F_PI) % 2 ); + + /* Get deviation from bin frequency from the +/- Pi interval */ + tmp /= expected; + + /* Compute the k-th partials' true frequency, twice the + * amplitude for maintain the gain (because half of bins are + * used) and store amplitude and true frequency in analysis + * buffer. + */ + state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; + state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; + + /* Store actual phase[k] for the calculations in the next frame*/ + state->LastPhase[k] = component.Phase; + } + + /* PROCESSING */ + /* pitch shifting */ + memset(state->Syntesis_buffer, 0, state->STFT_size*sizeof(ALfrequencyDomain)); + + for (k = 0; k <= STFT_half_size; k++) + { + j = fastf2i( (ALfloat)k*state->PitchShift ); + + if ( j <= STFT_half_size ) + { + state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; + state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * + state->PitchShift; + } + } + + /* SYNTHESIS */ + /* Synthesis the processing data */ + for ( k = 0; k <= STFT_half_size; k++ ) + { + /* Compute bin deviation from scaled freq */ + tmp = state->Syntesis_buffer[k].Frequency /freq_bin - (ALfloat)k; + + /* Calculate actual delta phase and accumulate it to get bin phase */ + state->SumPhase[k] += ((ALfloat)k + tmp) * expected; + + component.Amplitude = state->Syntesis_buffer[k].Amplitude; + component.Phase = state->SumPhase[k]; + + /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ + state->FFTbuffer[k] = polar2rect( component ); + } + + /* zero negative frequencies for recontruct a real signal */ + memset( &state->FFTbuffer[STFT_half_size+1], 0, (STFT_half_size-1) * sizeof(ALcomplex) ); + + /* Apply iFFT to buffer data */ + FFT( state->FFTbuffer, state->STFT_size, 1 ); + + /* Windowing and add to output */ + for( k=0; k < state->STFT_size; k++ ) + { + state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / + (STFT_half_size * state->oversamp); + } + + /* Shift accumulator, input & output FIFO */ + memmove(state->OutFIFO , state->OutputAccum , state->step *sizeof(ALfloat)); + memmove(state->OutputAccum, state->OutputAccum+state->step, state->STFT_size *sizeof(ALfloat)); + memmove(state->InFIFO , state->InFIFO +state->step, state->FIFOLatency*sizeof(ALfloat)); + } + } + + /* Now, mix the processed sound data to the output*/ + for (j = 0; j < NumChannels; j++ ) + { + ALfloat gain = state->Gain[j]; + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < SamplesToDo;i++) + SamplesOut[j][i] += gain * bufferOut[i]; + } +} + +typedef struct PshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} PshifterStateFactory; + +static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory)) +{ + ALpshifterState *state; + + NEW_OBJ0(state, ALpshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory); + +EffectStateFactory *PshifterStateFactory_getFactory(void) +{ + static PshifterStateFactory PshifterFactory = { { GET_VTABLE2(PshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &PshifterFactory); +} + + +void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param ); +} + +void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals)) +{ + alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param ); +} + +void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range"); + props->Pshifter.CoarseTune = val; + break; + + case AL_PITCH_SHIFTER_FINE_TUNE: + if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range"); + props->Pshifter.FineTune = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALpshifter_setParami(effect, context, param, vals[0]); +} + +void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_PITCH_SHIFTER_COARSE_TUNE: + *val = (ALint)props->Pshifter.CoarseTune; + break; + case AL_PITCH_SHIFTER_FINE_TUNE: + *val = (ALint)props->Pshifter.FineTune; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param); + } +} +void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALpshifter_getParami(effect, context, param, vals); +} + +void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param); +} + +void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param); +} + +DEFINE_ALEFFECT_VTABLE(ALpshifter); -- cgit v1.2.3 From 22a7bcd5ad448bf3021931e0d9ca6b59a5b90c04 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 09:01:32 -0700 Subject: Avoid placing a 2K sample buffer on the stack --- Alc/effects/pshifter.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index a9921028..a0cf4f45 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -49,9 +49,6 @@ typedef struct ALFrequencyDomain { typedef struct ALpshifterState { DERIVE_FROM_TYPE(ALeffectState); - /* Effect gains for each channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; - /* Effect parameters */ ALsizei count; ALsizei STFT_size; @@ -73,6 +70,11 @@ typedef struct ALpshifterState { ALfrequencyDomain Analysis_buffer[MAX_SIZE]; ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; + + ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat Gain[MAX_OUTPUT_CHANNELS]; } ALpshifterState; static ALvoid ALpshifterState_Destruct(ALpshifterState *state); @@ -256,9 +258,9 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ */ + ALfloat *restrict bufferOut = state->BufferOut; ALsizei i, j, k, STFT_half_size; ALfloat freq_bin, expected, tmp; - ALfloat bufferOut[BUFFERSIZE]; ALphasor component; STFT_half_size = state->STFT_size >> 1; -- cgit v1.2.3 From f11d7eeadfcf9ec2ea427fa14aa96037e8cdf008 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 09:23:58 -0700 Subject: Don't use mutable fields for constant values --- Alc/effects/pshifter.c | 81 ++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index a0cf4f45..15e26e3d 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -29,8 +29,16 @@ #include "alError.h" #include "alu.h" + #define MAX_SIZE 2048 +#define STFT_SIZE (MAX_SIZE>>1) +#define STFT_HALF_SIZE (STFT_SIZE>>1) +#define OVERSAMP (1<<2) + +#define STFT_STEP (STFT_SIZE / OVERSAMP) +#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) + typedef struct ALcomplex { ALfloat Real; ALfloat Imag; @@ -51,10 +59,6 @@ typedef struct ALpshifterState { /* Effect parameters */ ALsizei count; - ALsizei STFT_size; - ALsizei step; - ALsizei FIFOLatency; - ALsizei oversamp; ALfloat PitchShift; ALfloat Frequency; @@ -205,13 +209,10 @@ static void ALpshifterState_Construct(ALpshifterState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - /*Initializing parameters and set to zero the buffers */ - state->STFT_size = MAX_SIZE>>1; - state->oversamp = 1<<2; - - state->step = state->STFT_size / state->oversamp ; - state->FIFOLatency = state->step * ( state->oversamp-1 ); - state->count = state->FIFOLatency; + /* Initializing parameters and set to zero the buffers. */ + state->count = FIFO_LATENCY; + state->PitchShift = 1.0f; + state->Frequency = 1.0f; memset(state->InFIFO, 0, sizeof(state->InFIFO)); memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); @@ -222,10 +223,10 @@ static void ALpshifterState_Construct(ALpshifterState *state) memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ - for ( i = 0; i < state->STFT_size>>1 ; i++ ) + for ( i = 0; i < STFT_SIZE>>1 ; i++ ) { - state->window[i] = state->window[state->STFT_size-(i+1)] \ - = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(state->STFT_size-1))); + state->window[i] = state->window[STFT_SIZE-(i+1)] + = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(STFT_SIZE-1))); } } @@ -258,30 +259,26 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ */ + static const ALfloat expected = F_TAU / (ALfloat)OVERSAMP; + const ALfloat freq_bin = state->Frequency / (ALfloat)STFT_SIZE; ALfloat *restrict bufferOut = state->BufferOut; - ALsizei i, j, k, STFT_half_size; - ALfloat freq_bin, expected, tmp; - ALphasor component; - - STFT_half_size = state->STFT_size >> 1; - freq_bin = state->Frequency / (ALfloat)state->STFT_size; - expected = F_TAU / (ALfloat)state->oversamp; + ALsizei i, j, k; for (i = 0; i < SamplesToDo; i++) { /* Fill FIFO buffer with samples data */ state->InFIFO[state->count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[state->count - state->FIFOLatency]; + bufferOut[i] = state->OutFIFO[state->count - FIFO_LATENCY]; state->count++; /* Check whether FIFO buffer is filled */ - if ( state->count >= state->STFT_size ) + if ( state->count >= STFT_SIZE ) { - state->count = state->FIFOLatency; + state->count = FIFO_LATENCY; /* Real signal windowing and store in FFTbuffer */ - for ( k = 0; k < state->STFT_size; k++ ) + for ( k = 0; k < STFT_SIZE; k++ ) { state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; state->FFTbuffer[k].Imag = 0.0f; @@ -289,13 +286,16 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - FFT( state->FFTbuffer, state->STFT_size, -1 ); + FFT( state->FFTbuffer, STFT_SIZE, -1 ); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_half_size+1 samples are needed. */ - for ( k = 0; k <= STFT_half_size; k++ ) + for ( k = 0; k <= STFT_HALF_SIZE; k++ ) { + ALphasor component; + ALfloat tmp; + /* Compute amplitude and phase */ component = rect2polar( state->FFTbuffer[k] ); @@ -322,13 +322,13 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* PROCESSING */ /* pitch shifting */ - memset(state->Syntesis_buffer, 0, state->STFT_size*sizeof(ALfrequencyDomain)); + memset(state->Syntesis_buffer, 0, STFT_SIZE*sizeof(ALfrequencyDomain)); - for (k = 0; k <= STFT_half_size; k++) + for (k = 0; k <= STFT_HALF_SIZE; k++) { j = fastf2i( (ALfloat)k*state->PitchShift ); - if ( j <= STFT_half_size ) + if ( j <= STFT_HALF_SIZE ) { state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * @@ -338,10 +338,13 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* SYNTHESIS */ /* Synthesis the processing data */ - for ( k = 0; k <= STFT_half_size; k++ ) + for ( k = 0; k <= STFT_HALF_SIZE; k++ ) { + ALphasor component; + ALfloat tmp; + /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency /freq_bin - (ALfloat)k; + tmp = state->Syntesis_buffer[k].Frequency/freq_bin - (ALfloat)k; /* Calculate actual delta phase and accumulate it to get bin phase */ state->SumPhase[k] += ((ALfloat)k + tmp) * expected; @@ -354,22 +357,22 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD } /* zero negative frequencies for recontruct a real signal */ - memset( &state->FFTbuffer[STFT_half_size+1], 0, (STFT_half_size-1) * sizeof(ALcomplex) ); + memset( &state->FFTbuffer[STFT_HALF_SIZE+1], 0, (STFT_HALF_SIZE-1)*sizeof(ALcomplex)); /* Apply iFFT to buffer data */ - FFT( state->FFTbuffer, state->STFT_size, 1 ); + FFT( state->FFTbuffer, STFT_SIZE, 1 ); /* Windowing and add to output */ - for( k=0; k < state->STFT_size; k++ ) + for( k=0; k < STFT_SIZE; k++ ) { state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / - (STFT_half_size * state->oversamp); + (STFT_HALF_SIZE * OVERSAMP); } /* Shift accumulator, input & output FIFO */ - memmove(state->OutFIFO , state->OutputAccum , state->step *sizeof(ALfloat)); - memmove(state->OutputAccum, state->OutputAccum+state->step, state->STFT_size *sizeof(ALfloat)); - memmove(state->InFIFO , state->InFIFO +state->step, state->FIFOLatency*sizeof(ALfloat)); + memmove(state->OutFIFO , state->OutputAccum , STFT_STEP *sizeof(ALfloat)); + memmove(state->OutputAccum, state->OutputAccum+STFT_STEP, STFT_SIZE *sizeof(ALfloat)); + memmove(state->InFIFO , state->InFIFO +STFT_STEP, FIFO_LATENCY*sizeof(ALfloat)); } } -- cgit v1.2.3 From 0a6c17c5440ce31b58bab6edb9d5fa26f70af93f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 09:32:04 -0700 Subject: Don't auto-attenuate the pitch shifter output --- Alc/effects/pshifter.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 15e26e3d..e38f4ed2 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -244,13 +244,14 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; - const ALfloat adjust = 0.707945784384f; /*-3dB adjust*/ state->Frequency = (ALfloat)device->Frequency; - state->PitchShift = powf(2.0f,((ALfloat)props->Pshifter.CoarseTune + props->Pshifter.FineTune/100.0f)/12.0f); + state->PitchShift = powf(2.0f, + (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f + ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * adjust, state->Gain); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gain); } static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -- cgit v1.2.3 From 8f3d4965414e4e0963f1b1414135cb2a650ea289 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 20:39:04 -0700 Subject: Avoid duplicate path searches in the router And avoid inadvertently increasing the priority of the system path over the executable's path, or either of them over the current working directory. --- router/router.c | 57 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/router/router.c b/router/router.c index a0b554f4..bff73776 100644 --- a/router/router.c +++ b/router/router.c @@ -344,26 +344,47 @@ static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD leng void LoadDriverList(void) { - WCHAR path[MAX_PATH+1] = L""; + WCHAR dll_path[MAX_PATH+1] = L""; + WCHAR cwd_path[MAX_PATH+1] = L""; + WCHAR proc_path[MAX_PATH+1] = L""; + WCHAR sys_path[MAX_PATH+1] = L""; int len; - if(GetLoadedModuleDirectory(L"OpenAL32.dll", path, MAX_PATH)) - SearchDrivers(path); - - GetCurrentDirectoryW(MAX_PATH, path); - len = lstrlenW(path); - if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) - path[len-1] = '\0'; - SearchDrivers(path); - - if(GetLoadedModuleDirectory(NULL, path, MAX_PATH)) - SearchDrivers(path); - - GetSystemDirectoryW(path, MAX_PATH); - len = lstrlenW(path); - if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) - path[len-1] = '\0'; - SearchDrivers(path); + if(GetLoadedModuleDirectory(L"OpenAL32.dll", dll_path, MAX_PATH)) + TRACE("Got DLL path %ls\n", dll_path); + + GetCurrentDirectoryW(MAX_PATH, cwd_path); + len = lstrlenW(cwd_path); + if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/')) + cwd_path[len-1] = '\0'; + TRACE("Got current working directory %ls\n", cwd_path); + + if(GetLoadedModuleDirectory(NULL, proc_path, MAX_PATH)) + TRACE("Got proc path %ls\n", proc_path); + + GetSystemDirectoryW(sys_path, MAX_PATH); + len = lstrlenW(sys_path); + if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/')) + sys_path[len-1] = '\0'; + TRACE("Got system path %ls\n", sys_path); + + /* Don't search the DLL's path if it is the same as the current working + * directory, app's path, or system path (don't want to do duplicate + * searches, or increase the priority of the app or system path). + */ + if(dll_path[0] && + (!cwd_path[0] || wcscmp(dll_path, cwd_path) != 0) && + (!proc_path[0] || wcscmp(dll_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(dll_path, sys_path) != 0)) + SearchDrivers(dll_path); + if(cwd_path[0] && + (!proc_path[0] || wcscmp(cwd_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(cwd_path, sys_path) != 0)) + SearchDrivers(cwd_path); + if(proc_path[0] && (!sys_path[0] || wcscmp(proc_path, sys_path) != 0)) + SearchDrivers(proc_path); + if(sys_path[0]) + SearchDrivers(sys_path); } -- cgit v1.2.3 From 7b95753cf760edf7fe5fd4ce13e9f4bc0c08a9d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 21 Mar 2018 23:10:12 -0700 Subject: Fix typo (Substraction -> Subtraction) and rename related function --- Alc/effects/pshifter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index e38f4ed2..641df2f3 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -123,8 +123,8 @@ static inline ALcomplex complex_add( ALcomplex a, ALcomplex b ) return result; } -/* Substraction of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_subst( ALcomplex a, ALcomplex b ) +/* Subtraction of two complex numbers (ALcomplex format)*/ +static inline ALcomplex complex_sub( ALcomplex a, ALcomplex b ) { ALcomplex result; @@ -192,7 +192,7 @@ static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign) for ( k = j; k < FFTSize; k += step ) { temp = complex_mult( FFTBuffer[k+step2], u ); - FFTBuffer[k+step2] = complex_subst( FFTBuffer[k], temp ); + FFTBuffer[k+step2] = complex_sub( FFTBuffer[k], temp ); FFTBuffer[k] = complex_add( FFTBuffer[k], temp ); } -- cgit v1.2.3 From 4da6364fc25a19aad8f69ae3c593a3884374b16d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 02:10:51 -0700 Subject: Slightly restructure the pitch-shifter process loop --- Alc/effects/pshifter.c | 225 ++++++++++++++++++++++++------------------------- 1 file changed, 110 insertions(+), 115 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 641df2f3..e7a69dee 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -209,19 +209,6 @@ static void ALpshifterState_Construct(ALpshifterState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - /* Initializing parameters and set to zero the buffers. */ - state->count = FIFO_LATENCY; - state->PitchShift = 1.0f; - state->Frequency = 1.0f; - - memset(state->InFIFO, 0, sizeof(state->InFIFO)); - memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); - memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); - memset(state->LastPhase, 0, sizeof(state->LastPhase)); - memset(state->SumPhase, 0, sizeof(state->SumPhase)); - memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); - memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); - /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ for ( i = 0; i < STFT_SIZE>>1 ; i++ ) { @@ -235,8 +222,21 @@ static ALvoid ALpshifterState_Destruct(ALpshifterState *state) ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } -static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *UNUSED(state), ALCdevice *UNUSED(device)) +static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) { + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->PitchShift = 1.0f; + state->Frequency = (ALfloat)device->Frequency; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->FFTbuffer, 0, sizeof(state->FFTbuffer)); + memset(state->LastPhase, 0, sizeof(state->LastPhase)); + memset(state->SumPhase, 0, sizeof(state->SumPhase)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); + return AL_TRUE; } @@ -245,7 +245,6 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; - state->Frequency = (ALfloat)device->Frequency; state->PitchShift = powf(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); @@ -265,116 +264,112 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD ALfloat *restrict bufferOut = state->BufferOut; ALsizei i, j, k; - for (i = 0; i < SamplesToDo; i++) + for(i = 0;i < SamplesToDo;) { - /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[state->count - FIFO_LATENCY]; + do { + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + bufferOut[i] = state->OutFIFO[state->count - FIFO_LATENCY]; - state->count++; + state->count++; + } while(++i < SamplesToDo && state->count < STFT_SIZE); /* Check whether FIFO buffer is filled */ - if ( state->count >= STFT_SIZE ) + if(state->count < STFT_SIZE) break; + + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in FFTbuffer */ + for(k = 0;k < STFT_SIZE;k++) + { + state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; + state->FFTbuffer[k].Imag = 0.0f; + } + + /* ANALYSIS */ + /* Apply FFT to FFTbuffer data */ + FFT(state->FFTbuffer, STFT_SIZE, -1); + + /* Analyze the obtained data. Since the real FFT is symmetric, only + * STFT_half_size+1 samples are needed. + */ + for(k = 0;k <= STFT_HALF_SIZE;k++) { - state->count = FIFO_LATENCY; + ALphasor component; + ALfloat tmp; + + /* Compute amplitude and phase */ + component = rect2polar(state->FFTbuffer[k]); - /* Real signal windowing and store in FFTbuffer */ - for ( k = 0; k < STFT_SIZE; k++ ) - { - state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; - state->FFTbuffer[k].Imag = 0.0f; - } + /* Compute phase difference and subtract expected phase difference */ + tmp = (component.Phase - state->LastPhase[k]) - (ALfloat)k*expected; - /* ANALYSIS */ - /* Apply FFT to FFTbuffer data */ - FFT( state->FFTbuffer, STFT_SIZE, -1 ); + /* Map delta phase into +/- Pi interval */ + tmp -= F_PI * (ALfloat)(fastf2i(tmp/F_PI) + (fastf2i(tmp/F_PI)&1)); - /* Analyze the obtained data. Since the real FFT is symmetric, only - * STFT_half_size+1 samples are needed. + /* Get deviation from bin frequency from the +/- Pi interval */ + tmp /= expected; + + /* Compute the k-th partials' true frequency, twice the amplitude + * for maintain the gain (because half of bins are used) and store + * amplitude and true frequency in analysis buffer. */ - for ( k = 0; k <= STFT_HALF_SIZE; k++ ) - { - ALphasor component; - ALfloat tmp; - - /* Compute amplitude and phase */ - component = rect2polar( state->FFTbuffer[k] ); - - /* Compute phase difference and subtract expected phase difference */ - tmp = ( component.Phase - state->LastPhase[k] ) - (ALfloat)k*expected; - - /* Map delta phase into +/- Pi interval */ - tmp -= F_PI*(ALfloat)( fastf2i(tmp/F_PI) + fastf2i(tmp/F_PI) % 2 ); - - /* Get deviation from bin frequency from the +/- Pi interval */ - tmp /= expected; - - /* Compute the k-th partials' true frequency, twice the - * amplitude for maintain the gain (because half of bins are - * used) and store amplitude and true frequency in analysis - * buffer. - */ - state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; - state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; - - /* Store actual phase[k] for the calculations in the next frame*/ - state->LastPhase[k] = component.Phase; - } - - /* PROCESSING */ - /* pitch shifting */ - memset(state->Syntesis_buffer, 0, STFT_SIZE*sizeof(ALfrequencyDomain)); - - for (k = 0; k <= STFT_HALF_SIZE; k++) - { - j = fastf2i( (ALfloat)k*state->PitchShift ); - - if ( j <= STFT_HALF_SIZE ) - { - state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; - state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * - state->PitchShift; - } - } - - /* SYNTHESIS */ - /* Synthesis the processing data */ - for ( k = 0; k <= STFT_HALF_SIZE; k++ ) - { - ALphasor component; - ALfloat tmp; - - /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency/freq_bin - (ALfloat)k; - - /* Calculate actual delta phase and accumulate it to get bin phase */ - state->SumPhase[k] += ((ALfloat)k + tmp) * expected; - - component.Amplitude = state->Syntesis_buffer[k].Amplitude; - component.Phase = state->SumPhase[k]; - - /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ - state->FFTbuffer[k] = polar2rect( component ); - } - - /* zero negative frequencies for recontruct a real signal */ - memset( &state->FFTbuffer[STFT_HALF_SIZE+1], 0, (STFT_HALF_SIZE-1)*sizeof(ALcomplex)); - - /* Apply iFFT to buffer data */ - FFT( state->FFTbuffer, STFT_SIZE, 1 ); - - /* Windowing and add to output */ - for( k=0; k < STFT_SIZE; k++ ) - { - state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / - (STFT_HALF_SIZE * OVERSAMP); - } - - /* Shift accumulator, input & output FIFO */ - memmove(state->OutFIFO , state->OutputAccum , STFT_STEP *sizeof(ALfloat)); - memmove(state->OutputAccum, state->OutputAccum+STFT_STEP, STFT_SIZE *sizeof(ALfloat)); - memmove(state->InFIFO , state->InFIFO +STFT_STEP, FIFO_LATENCY*sizeof(ALfloat)); + state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; + state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; + + /* Store actual phase[k] for the calculations in the next frame*/ + state->LastPhase[k] = component.Phase; + } + + /* PROCESSING */ + /* pitch shifting */ + memset(state->Syntesis_buffer, 0, STFT_SIZE*sizeof(ALfrequencyDomain)); + + for(k = 0;k <= STFT_HALF_SIZE;k++) + { + j = fastf2i((ALfloat)k * state->PitchShift); + if(j > STFT_HALF_SIZE) break; + + state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; + state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * + state->PitchShift; + } + + /* SYNTHESIS */ + /* Synthesis the processing data */ + for(k = 0;k <= STFT_HALF_SIZE;k++) + { + ALphasor component; + ALfloat tmp; + + /* Compute bin deviation from scaled freq */ + tmp = state->Syntesis_buffer[k].Frequency/freq_bin - (ALfloat)k; + + /* Calculate actual delta phase and accumulate it to get bin phase */ + state->SumPhase[k] += ((ALfloat)k + tmp) * expected; + + component.Amplitude = state->Syntesis_buffer[k].Amplitude; + component.Phase = state->SumPhase[k]; + + /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ + state->FFTbuffer[k] = polar2rect(component); } + + /* zero negative frequencies for recontruct a real signal */ + memset(&state->FFTbuffer[STFT_HALF_SIZE+1], 0, (STFT_HALF_SIZE-1)*sizeof(ALcomplex)); + + /* Apply iFFT to buffer data */ + FFT(state->FFTbuffer, STFT_SIZE, 1); + + /* Windowing and add to output */ + for(k = 0;k < STFT_SIZE;k++) + state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / + (STFT_HALF_SIZE * OVERSAMP); + + /* Shift accumulator, input & output FIFO */ + memmove(state->OutFIFO , state->OutputAccum , STFT_STEP *sizeof(ALfloat)); + memmove(state->OutputAccum, state->OutputAccum+STFT_STEP, STFT_SIZE *sizeof(ALfloat)); + memmove(state->InFIFO , state->InFIFO +STFT_STEP, FIFO_LATENCY*sizeof(ALfloat)); } /* Now, mix the processed sound data to the output*/ -- cgit v1.2.3 From d157d66678ed634550ca5991dde9c68178c41768 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 02:13:40 -0700 Subject: Change a parameter type to float since that's what it's used as --- Alc/effects/pshifter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index e7a69dee..137c7d04 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -149,7 +149,7 @@ static inline ALcomplex complex_mult( ALcomplex a, ALcomplex b ) iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the Discrete Fourier Transform (DFT) of the time domain data stored in FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers (ALcomplex), FFTSize MUST BE power of two.*/ -static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALint Sign) +static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALfloat Sign) { ALfloat arg; ALsizei i, j, k, mask, step, step2; @@ -288,7 +288,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - FFT(state->FFTbuffer, STFT_SIZE, -1); + FFT(state->FFTbuffer, STFT_SIZE, -1.0f); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_half_size+1 samples are needed. @@ -359,7 +359,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD memset(&state->FFTbuffer[STFT_HALF_SIZE+1], 0, (STFT_HALF_SIZE-1)*sizeof(ALcomplex)); /* Apply iFFT to buffer data */ - FFT(state->FFTbuffer, STFT_SIZE, 1); + FFT(state->FFTbuffer, STFT_SIZE, 1.0f); /* Windowing and add to output */ for(k = 0;k < STFT_SIZE;k++) -- cgit v1.2.3 From 6ad171781a8e2270f598263149356385cc06d8f9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 02:29:34 -0700 Subject: Use the global MixSamples for the pitch shifter output --- Alc/effects/pshifter.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 137c7d04..d36597ae 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -75,10 +75,11 @@ typedef struct ALpshifterState { ALfrequencyDomain Analysis_buffer[MAX_SIZE]; ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; - ALfloat BufferOut[BUFFERSIZE]; + alignas(16) ALfloat BufferOut[BUFFERSIZE]; /* Effect gains for each output channel */ - ALfloat Gain[MAX_OUTPUT_CHANNELS]; + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; } ALpshifterState; static ALvoid ALpshifterState_Destruct(ALpshifterState *state); @@ -237,6 +238,9 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + return AL_TRUE; } @@ -250,7 +254,7 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gain); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) @@ -372,17 +376,9 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD memmove(state->InFIFO , state->InFIFO +STFT_STEP, FIFO_LATENCY*sizeof(ALfloat)); } - /* Now, mix the processed sound data to the output*/ - for (j = 0; j < NumChannels; j++ ) - { - ALfloat gain = state->Gain[j]; - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < SamplesToDo;i++) - SamplesOut[j][i] += gain * bufferOut[i]; - } + /* Now, mix the processed sound data to the output. */ + MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); } typedef struct PshifterStateFactory { -- cgit v1.2.3 From 091e676db34ff51a709427d5b1203bfcd0788fb4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 05:06:15 -0700 Subject: Move mixer sources into a sub-directory --- Alc/ALu.c | 2 +- Alc/bformatdec.c | 1 - Alc/converter.c | 2 +- Alc/effects/reverb.c | 1 - Alc/mixer.c | 781 ------------------------------------------------ Alc/mixer/defs.h | 119 ++++++++ Alc/mixer/mixer_c.c | 209 +++++++++++++ Alc/mixer/mixer_inc.c | 114 +++++++ Alc/mixer/mixer_neon.c | 261 ++++++++++++++++ Alc/mixer/mixer_sse.c | 229 ++++++++++++++ Alc/mixer/mixer_sse2.c | 82 +++++ Alc/mixer/mixer_sse3.c | 0 Alc/mixer/mixer_sse41.c | 86 ++++++ Alc/mixer_c.c | 208 ------------- Alc/mixer_defs.h | 119 -------- Alc/mixer_inc.c | 114 ------- Alc/mixer_neon.c | 261 ---------------- Alc/mixer_sse.c | 229 -------------- Alc/mixer_sse2.c | 82 ----- Alc/mixer_sse3.c | 0 Alc/mixer_sse41.c | 86 ------ Alc/mixvoice.c | 781 ++++++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 24 +- 23 files changed, 1895 insertions(+), 1896 deletions(-) delete mode 100644 Alc/mixer.c create mode 100644 Alc/mixer/defs.h create mode 100644 Alc/mixer/mixer_c.c create mode 100644 Alc/mixer/mixer_inc.c create mode 100644 Alc/mixer/mixer_neon.c create mode 100644 Alc/mixer/mixer_sse.c create mode 100644 Alc/mixer/mixer_sse2.c create mode 100644 Alc/mixer/mixer_sse3.c create mode 100644 Alc/mixer/mixer_sse41.c delete mode 100644 Alc/mixer_c.c delete mode 100644 Alc/mixer_defs.h delete mode 100644 Alc/mixer_inc.c delete mode 100644 Alc/mixer_neon.c delete mode 100644 Alc/mixer_sse.c delete mode 100644 Alc/mixer_sse2.c delete mode 100644 Alc/mixer_sse3.c delete mode 100644 Alc/mixer_sse41.c create mode 100644 Alc/mixvoice.c diff --git a/Alc/ALu.c b/Alc/ALu.c index 1aa35cb7..63d13838 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -40,9 +40,9 @@ #include "static_assert.h" #include "ringbuffer.h" +#include "mixer/defs.h" #include "fpu_modes.h" #include "cpu_caps.h" -#include "mixer_defs.h" #include "bsinc_inc.h" #include "backends/base.h" diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 28dbc742..ff0cd657 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -3,7 +3,6 @@ #include "bformatdec.h" #include "ambdec.h" -#include "mixer_defs.h" #include "alu.h" #include "bool.h" diff --git a/Alc/converter.c b/Alc/converter.c index 157073f2..6e28b4a6 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -4,7 +4,7 @@ #include "converter.h" #include "fpu_modes.h" -#include "mixer_defs.h" +#include "mixer/defs.h" SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index bd5553ad..ff1ee143 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -31,7 +31,6 @@ #include "alFilter.h" #include "alListener.h" #include "alError.h" -#include "mixer_defs.h" /* This is a user config option for modifying the overall output of the reverb * effect. diff --git a/Alc/mixer.c b/Alc/mixer.c deleted file mode 100644 index 7a7bbfe0..00000000 --- a/Alc/mixer.c +++ /dev/null @@ -1,781 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "AL/al.h" -#include "AL/alc.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "sample_cvt.h" -#include "alu.h" -#include "alconfig.h" -#include "ringbuffer.h" - -#include "cpu_caps.h" -#include "mixer_defs.h" - - -static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, - "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); - -extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); - - -/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); - - -enum Resampler ResamplerDefault = LinearResampler; - -MixerFunc MixSamples = Mix_C; -RowMixerFunc MixRowSamples = MixRow_C; -static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; -static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; - -static MixerFunc SelectMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; -#endif - return Mix_C; -} - -static RowMixerFunc SelectRowMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixRow_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixRow_SSE; -#endif - return MixRow_C; -} - -static inline HrtfMixerFunc SelectHrtfMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtf_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtf_SSE; -#endif - return MixHrtf_C; -} - -static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) -{ -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return MixHrtfBlend_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return MixHrtfBlend_SSE; -#endif - return MixHrtfBlend_C; -} - -ResamplerFunc SelectResampler(enum Resampler resampler) -{ - switch(resampler) - { - case PointResampler: - return Resample_point_C; - case LinearResampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_lerp_Neon; -#endif -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_lerp_SSE41; -#endif -#ifdef HAVE_SSE2 - if((CPUCapFlags&CPU_CAP_SSE2)) - return Resample_lerp_SSE2; -#endif - return Resample_lerp_C; - case FIR4Resampler: - return Resample_cubic_C; - case BSinc12Resampler: - case BSinc24Resampler: -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Resample_bsinc_Neon; -#endif -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Resample_bsinc_SSE; -#endif - return Resample_bsinc_C; - } - - return Resample_point_C; -} - - -void aluInitMixer(void) -{ - const char *str; - - if(ConfigValueStr(NULL, NULL, "resampler", &str)) - { - if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) - ResamplerDefault = PointResampler; - else if(strcasecmp(str, "linear") == 0) - ResamplerDefault = LinearResampler; - else if(strcasecmp(str, "cubic") == 0) - ResamplerDefault = FIR4Resampler; - else if(strcasecmp(str, "bsinc12") == 0) - ResamplerDefault = BSinc12Resampler; - else if(strcasecmp(str, "bsinc24") == 0) - ResamplerDefault = BSinc24Resampler; - else if(strcasecmp(str, "bsinc") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); - ResamplerDefault = BSinc12Resampler; - } - else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) - { - WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); - ResamplerDefault = FIR4Resampler; - } - else - { - char *end; - long n = strtol(str, &end, 0); - if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) - ResamplerDefault = n; - else - WARN("Invalid resampler: %s\n", str); - } - } - - MixHrtfBlendSamples = SelectHrtfBlendMixer(); - MixHrtfSamples = SelectHrtfMixer(); - MixSamples = SelectMixer(); - MixRowSamples = SelectRowMixer(); -} - - -static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, - ALuint objid, ALuint param, const char *msg) -{ - AsyncEvent evt; - evt.EnumType = enumtype; - evt.Type = type; - evt.ObjectId = objid; - evt.Param = param; - strcpy(evt.Message, msg); - if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) - alsem_post(&context->EventSem); -} - - -static inline ALfloat Sample_ALubyte(ALubyte val) -{ return (val-128) * (1.0f/128.0f); } - -static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32768.0f); } - -static inline ALfloat Sample_ALfloat(ALfloat val) -{ return val; } - -static inline ALfloat Sample_ALdouble(ALdouble val) -{ return (ALfloat)val; } - -typedef ALubyte ALmulaw; -static inline ALfloat Sample_ALmulaw(ALmulaw val) -{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } - -typedef ALubyte ALalaw; -static inline ALfloat Sample_ALalaw(ALalaw val) -{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } - -#define DECL_TEMPLATE(T) \ -static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ - ALint srcstep, ALsizei samples) \ -{ \ - ALsizei i; \ - for(i = 0;i < samples;i++) \ - dst[i] += Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALubyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) -DECL_TEMPLATE(ALdouble) -DECL_TEMPLATE(ALmulaw) -DECL_TEMPLATE(ALalaw) - -#undef DECL_TEMPLATE - -static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep, - enum FmtType srctype, ALsizei samples) -{ -#define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break - switch(srctype) - { - HANDLE_FMT(FmtUByte, ALubyte); - HANDLE_FMT(FmtShort, ALshort); - HANDLE_FMT(FmtFloat, ALfloat); - HANDLE_FMT(FmtDouble, ALdouble); - HANDLE_FMT(FmtMulaw, ALmulaw); - HANDLE_FMT(FmtAlaw, ALalaw); - } -#undef HANDLE_FMT -} - - -static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter, - ALfloat *restrict dst, const ALfloat *restrict src, - ALsizei numsamples, enum ActiveFilters type) -{ - ALsizei i; - switch(type) - { - case AF_None: - ALfilterState_processPassthru(lpfilter, src, numsamples); - ALfilterState_processPassthru(hpfilter, src, numsamples); - break; - - case AF_LowPass: - ALfilterState_process(lpfilter, dst, src, numsamples); - ALfilterState_processPassthru(hpfilter, dst, numsamples); - return dst; - case AF_HighPass: - ALfilterState_processPassthru(lpfilter, src, numsamples); - ALfilterState_process(hpfilter, dst, src, numsamples); - return dst; - - case AF_BandPass: - for(i = 0;i < numsamples;) - { - ALfloat temp[256]; - ALsizei todo = mini(256, numsamples-i); - - ALfilterState_process(lpfilter, temp, src+i, todo); - ALfilterState_process(hpfilter, dst+i, temp, todo); - i += todo; - } - return dst; - } - return src; -} - - -/* This function uses these device temp buffers. */ -#define SOURCE_DATA_BUF 0 -#define RESAMPLED_BUF 1 -#define FILTERED_BUF 2 -#define NFC_DATA_BUF 3 -ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) -{ - ALCdevice *Device = Context->Device; - ALbufferlistitem *BufferListItem; - ALbufferlistitem *BufferLoopItem; - ALsizei NumChannels, SampleSize; - ALbitfieldSOFT enabledevt; - ALsizei buffers_done = 0; - ResamplerFunc Resample; - ALsizei DataPosInt; - ALsizei DataPosFrac; - ALint64 DataSize64; - ALint increment; - ALsizei Counter; - ALsizei OutPos; - ALsizei IrSize; - bool isplaying; - bool firstpass; - bool isstatic; - ALsizei chan; - ALsizei send; - - /* Get source info */ - isplaying = true; /* Will only be called while playing. */ - isstatic = !!(voice->Flags&VOICE_IS_STATIC); - DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); - DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); - BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); - NumChannels = voice->NumChannels; - SampleSize = voice->SampleSize; - increment = voice->Step; - - IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); - - Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? - Resample_copy_C : voice->Resampler); - - Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; - firstpass = true; - OutPos = 0; - - do { - ALsizei SrcBufferSize, DstBufferSize; - - /* Figure out how many buffer samples will be needed */ - DataSize64 = SamplesToDo-OutPos; - DataSize64 *= increment; - DataSize64 += DataPosFrac+FRACTIONMASK; - DataSize64 >>= FRACTIONBITS; - DataSize64 += MAX_RESAMPLE_PADDING*2; - SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); - - /* Figure out how many samples we can actually mix from this. */ - DataSize64 = SrcBufferSize; - DataSize64 -= MAX_RESAMPLE_PADDING*2; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, - SamplesToDo - OutPos); - - /* Some mixers like having a multiple of 4, so try to give that unless - * this is the last update. */ - if(DstBufferSize < SamplesToDo-OutPos) - DstBufferSize &= ~3; - - /* It's impossible to have a buffer list item with no entries. */ - assert(BufferListItem->num_buffers > 0); - - for(chan = 0;chan < NumChannels;chan++) - { - const ALfloat *ResampledData; - ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; - ALsizei FilledAmt; - - /* Load the previous samples into the source data first, and clear the rest. */ - memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); - memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* - sizeof(ALfloat)); - FilledAmt = MAX_RESAMPLE_PADDING; - - if(isstatic) - { - /* TODO: For static sources, loop points are taken from the - * first buffer (should be adjusted by any buffer offset, to - * possibly be added later). - */ - const ALbuffer *Buffer0 = BufferListItem->buffers[0]; - const ALsizei LoopStart = Buffer0->LoopStart; - const ALsizei LoopEnd = Buffer0->LoopEnd; - const ALsizei LoopSize = LoopEnd - LoopStart; - - /* If current pos is beyond the loop range, do not loop */ - if(!BufferLoopItem || DataPosInt >= LoopEnd) - { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; - - BufferLoopItem = NULL; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(DataPosInt >= buffer->SampleLen) - continue; - - /* Load what's left to play from the buffer */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - } - else - { - ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(DataPosInt >= buffer->SampleLen) - continue; - - /* Load what's left of this loop iteration */ - DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(DataPosInt*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - - while(SrcBufferSize > FilledAmt) - { - const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); - - CompLen = 0; - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - const ALubyte *Data = buffer->data; - ALsizei DataSize; - - if(LoopStart >= buffer->SampleLen) - continue; - - DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); - CompLen = maxi(CompLen, DataSize); - - LoadSamples(&SrcData[FilledAmt], - &Data[(LoopStart*NumChannels + chan)*SampleSize], - NumChannels, buffer->FmtType, DataSize - ); - } - FilledAmt += CompLen; - } - } - } - else - { - /* Crawl the buffer queue to fill in the temp buffer */ - ALbufferlistitem *tmpiter = BufferListItem; - ALsizei pos = DataPosInt; - - while(tmpiter && SrcBufferSize > FilledAmt) - { - ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < tmpiter->num_buffers;i++) - { - const ALbuffer *ALBuffer = tmpiter->buffers[i]; - ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; - CompLen = maxi(CompLen, DataSize); - - if(DataSize > pos) - { - const ALubyte *Data = ALBuffer->data; - Data += (pos*NumChannels + chan)*SampleSize; - - DataSize = minu(SizeToDo, DataSize - pos); - LoadSamples(&SrcData[FilledAmt], Data, NumChannels, - ALBuffer->FmtType, DataSize); - } - } - if(pos > CompLen) - pos -= CompLen; - else - { - FilledAmt += CompLen - pos; - pos = 0; - } - if(SrcBufferSize > FilledAmt) - { - tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); - if(!tmpiter) tmpiter = BufferLoopItem; - } - } - } - - /* Store the last source samples used for next time. */ - memcpy(voice->PrevSamples[chan], - &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], - MAX_RESAMPLE_PADDING*sizeof(ALfloat) - ); - - /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample(&voice->ResampleState, - &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, - Device->TempBuffer[RESAMPLED_BUF], DstBufferSize - ); - { - DirectParams *parms = &voice->Direct.Params[chan]; - const ALfloat *samples; - - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Direct.FilterType - ); - if(!(voice->Flags&VOICE_HAS_HRTF)) - { - if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); - if(!(voice->Flags&VOICE_HAS_NFC)) - MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); - else - { - ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; - ALsizei chanoffset = 0; - - MixSamples(samples, - voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, - DstBufferSize - ); - chanoffset += voice->Direct.ChannelsPerOrder[0]; -#define APPLY_NFC_MIX(order) \ - if(voice->Direct.ChannelsPerOrder[order] > 0) \ - { \ - NfcFilterUpdate##order(&parms->NFCtrlFilter, nfcsamples, samples, \ - DstBufferSize); \ - MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ - voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ - parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ - ); \ - chanoffset += voice->Direct.ChannelsPerOrder[order]; \ - } - APPLY_NFC_MIX(1) - APPLY_NFC_MIX(2) - APPLY_NFC_MIX(3) -#undef APPLY_NFC_MIX - } - } - else - { - MixHrtfParams hrtfparams; - ALsizei fademix = 0; - int lidx, ridx; - - lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); - - if(!Counter) - { - /* No fading, just overwrite the old HRTF params. */ - parms->Hrtf.Old = parms->Hrtf.Target; - } - else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) - { - /* The old HRTF params are silent, so overwrite the old - * coefficients with the new, and reset the old gain to - * 0. The future mix will then fade from silence. - */ - parms->Hrtf.Old = parms->Hrtf.Target; - parms->Hrtf.Old.Gain = 0.0f; - } - else if(firstpass) - { - ALfloat gain; - - /* Fade between the coefficients over 128 samples. */ - fademix = mini(DstBufferSize, 128); - - /* The new coefficients need to fade in completely - * since they're replacing the old ones. To keep the - * gain fading consistent, interpolate between the old - * and new target gains given how much of the fade time - * this mix handles. - */ - gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, - minf(1.0f, (ALfloat)fademix/Counter)); - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = 0.0f; - hrtfparams.GainStep = gain / (ALfloat)fademix; - - MixHrtfBlendSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, - &hrtfparams, &parms->Hrtf.State, fademix - ); - /* Update the old parameters with the result. */ - parms->Hrtf.Old = parms->Hrtf.Target; - if(fademix < Counter) - parms->Hrtf.Old.Gain = hrtfparams.Gain; - } - - if(fademix < DstBufferSize) - { - ALsizei todo = DstBufferSize - fademix; - ALfloat gain = parms->Hrtf.Target.Gain; - - /* Interpolate the target gain if the gain fading lasts - * longer than this mix. - */ - if(Counter > DstBufferSize) - gain = lerp(parms->Hrtf.Old.Gain, gain, - (ALfloat)todo/(Counter-fademix)); - - hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; - hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; - hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; - hrtfparams.Gain = parms->Hrtf.Old.Gain; - hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, - &hrtfparams, &parms->Hrtf.State, todo - ); - /* Store the interpolated gain or the final target gain - * depending if the fade is done. - */ - if(DstBufferSize < Counter) - parms->Hrtf.Old.Gain = gain; - else - parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; - } - } - } - - for(send = 0;send < Device->NumAuxSends;send++) - { - SendParams *parms = &voice->Send[send].Params[chan]; - const ALfloat *samples; - - if(!voice->Send[send].Buffer) - continue; - - samples = DoFilters( - &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], - ResampledData, DstBufferSize, voice->Send[send].FilterType - ); - - if(!Counter) - memcpy(parms->Gains.Current, parms->Gains.Target, - sizeof(parms->Gains.Current)); - MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, - parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize - ); - } - } - /* Update positions */ - DataPosFrac += increment*DstBufferSize; - DataPosInt += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - - OutPos += DstBufferSize; - voice->Offset += DstBufferSize; - Counter = maxi(DstBufferSize, Counter) - DstBufferSize; - firstpass = false; - - if(isstatic) - { - if(BufferLoopItem) - { - /* Handle looping static source */ - const ALbuffer *Buffer = BufferListItem->buffers[0]; - ALsizei LoopStart = Buffer->LoopStart; - ALsizei LoopEnd = Buffer->LoopEnd; - if(DataPosInt >= LoopEnd) - { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; - } - } - else - { - /* Handle non-looping static source */ - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); - } - - if(DataPosInt >= CompLen) - { - isplaying = false; - BufferListItem = NULL; - DataPosInt = 0; - DataPosFrac = 0; - break; - } - } - } - else while(1) - { - /* Handle streaming source */ - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); - } - - if(CompLen > DataPosInt) - break; - - buffers_done += BufferListItem->num_buffers; - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); - if(!BufferListItem && !(BufferListItem=BufferLoopItem)) - { - isplaying = false; - DataPosInt = 0; - DataPosFrac = 0; - break; - } - - DataPosInt -= CompLen; - } - } while(isplaying && OutPos < SamplesToDo); - - voice->Flags |= VOICE_IS_FADING; - - /* Update source info */ - ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); - ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); - ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); - - /* Send any events now, after the position/buffer info was updated. */ - enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); - if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) - SendAsyncEvent(Context, EventType_BufferCompleted, - AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" - ); - - return isplaying; -} diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h new file mode 100644 index 00000000..fe19cef4 --- /dev/null +++ b/Alc/mixer/defs.h @@ -0,0 +1,119 @@ +#ifndef MIXER_DEFS_H +#define MIXER_DEFS_H + +#include "AL/alc.h" +#include "AL/al.h" +#include "alMain.h" +#include "alu.h" + +struct MixGains; + +struct MixHrtfParams; +struct HrtfState; + +/* C resamplers */ +const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); +const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); + + +/* C mixers */ +void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); +void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize); +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); + +/* SSE mixers */ +void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); +void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize); +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); + +/* SSE resamplers */ +inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) +{ + ALsizei i; + + pos_arr[0] = 0; + frac_arr[0] = frac; + for(i = 1;i < size;i++) + { + ALint frac_tmp = frac_arr[i-1] + increment; + pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); + frac_arr[i] = frac_tmp&FRACTIONMASK; + } +} + +const ALfloat *Resample_lerp_SSE2(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); +const ALfloat *Resample_lerp_SSE41(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); + +const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen); + +/* Neon mixers */ +void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, struct MixHrtfParams *hrtfparams, + struct HrtfState *hrtfstate, ALsizei BufferSize); +void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize); +void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize); +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize); +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, + const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, + ALsizei InPos, ALsizei BufferSize); + +/* Neon resamplers */ +const ALfloat *Resample_lerp_Neon(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei numsamples); +const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen); + +#endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c new file mode 100644 index 00000000..0c33e9b0 --- /dev/null +++ b/Alc/mixer/mixer_c.c @@ -0,0 +1,209 @@ +#include "config.h" + +#include + +#include "alMain.h" +#include "alu.h" +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" + + +static inline ALfloat do_point(const ALfloat *restrict vals, ALsizei UNUSED(frac)) +{ return vals[0]; } +static inline ALfloat do_lerp(const ALfloat *restrict vals, ALsizei frac) +{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } +static inline ALfloat do_cubic(const ALfloat *restrict vals, ALsizei frac) +{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } + +const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment), + ALfloat *restrict dst, ALsizei numsamples) +{ +#if defined(HAVE_SSE) || defined(HAVE_NEON) + /* Avoid copying the source data if it's aligned like the destination. */ + if((((intptr_t)src)&15) == (((intptr_t)dst)&15)) + return src; +#endif + memcpy(dst, src, numsamples*sizeof(ALfloat)); + return dst; +} + +#define DECL_TEMPLATE(Tag, Sampler, O) \ +const ALfloat *Resample_##Tag##_C(const InterpState* UNUSED(state), \ + const ALfloat *restrict src, ALsizei frac, ALint increment, \ + ALfloat *restrict dst, ALsizei numsamples) \ +{ \ + ALsizei i; \ + \ + src -= O; \ + for(i = 0;i < numsamples;i++) \ + { \ + dst[i] = Sampler(src, frac); \ + \ + frac += increment; \ + src += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + } \ + return dst; \ +} + +DECL_TEMPLATE(point, do_point, 0) +DECL_TEMPLATE(lerp, do_lerp, 0) +DECL_TEMPLATE(cubic, do_cubic, 1) + +#undef DECL_TEMPLATE + +const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen) +{ + const ALfloat *fil, *scd, *phd, *spd; + const ALfloat *const filter = state->bsinc.filter; + const ALfloat sf = state->bsinc.sf; + const ALsizei m = state->bsinc.m; + ALsizei j_f, pi, i; + ALfloat pf, r; + + src += state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) +{ + ALsizei i; + if(LIKELY(numsamples > 1)) + { + ALfloat x0 = filter->x[0]; + ALfloat x1 = filter->x[1]; + ALfloat y0 = filter->y[0]; + ALfloat y1 = filter->y[1]; + + for(i = 0;i < numsamples;i++) + { + dst[i] = filter->b0* src[i] + + filter->b1*x0 + filter->b2*x1 - + filter->a1*y0 - filter->a2*y1; + y1 = y0; y0 = dst[i]; + x1 = x0; x0 = src[i]; + } + + filter->x[0] = x0; + filter->x[1] = x1; + filter->y[0] = y0; + filter->y[1] = y1; + } + else if(numsamples == 1) + { + dst[0] = filter->b0 * src[0] + + filter->b1 * filter->x[0] + + filter->b2 * filter->x[1] - + filter->a1 * filter->y[0] - + filter->a2 * filter->y[1]; + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = dst[0]; + } +} + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALsizei c; + for(c = 0;c < IrSize;c++) + { + const ALsizei off = (Offset+c)&HRIR_MASK; + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + } +} + +#define MixHrtf MixHrtf_C +#define MixHrtfBlend MixHrtfBlend_C +#define MixDirectHrtf MixDirectHrtf_C +#include "mixer_inc.c" +#undef MixHrtf + + +void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + ALfloat gain, delta, step; + ALsizei c; + + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos]*gain; + gain += step; + } + if(pos == Counter) + gain = TargetGains[c]; + CurrentGains[c] = gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +/* Basically the inverse of the above. Rather than one input going to multiple + * outputs (each with its own gain), it's multiple inputs (each with its own + * gain) going to one output. This applies one row (vs one column) of a matrix + * transform. And as the matrices are more or less static once set up, no + * stepping is necessary. + */ +void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + ALsizei c, i; + + for(c = 0;c < InChans;c++) + { + ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < BufferSize;i++) + OutBuffer[i] += data[c][InPos+i] * gain; + } +} diff --git a/Alc/mixer/mixer_inc.c b/Alc/mixer/mixer_inc.c new file mode 100644 index 00000000..ad0daa63 --- /dev/null +++ b/Alc/mixer/mixer_inc.c @@ -0,0 +1,114 @@ +#include "config.h" + +#include "alMain.h" +#include "alSource.h" + +#include "hrtf.h" +#include "align.h" +#include "alu.h" +#include "defs.h" + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei irSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat left, ALfloat right); + + +void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); + const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; + ALfloat gainstep = hrtfparams->GainStep; + ALfloat gain = hrtfparams->Gain; + ALfloat left, right; + ALsizei i; + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; + + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + gain += gainstep; + Offset++; + } + hrtfparams->Gain = gain; +} + +void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); + const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; + ALfloat oldGain = oldparams->Gain; + ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); + const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; + ALfloat newGain = newparams->Gain; + ALfloat newGainStep = newparams->GainStep; + ALfloat left, right; + ALsizei i; + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + + left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; + right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); + + left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; + right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + oldGain += oldGainStep; + newGain += newGainStep; + Offset++; + } + newparams->Gain = newGain; +} + +void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize) +{ + ALfloat insample; + ALsizei i; + + for(i = 0;i < BufferSize;i++) + { + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + insample = *(data++); + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + *(LeftOut++) += Values[Offset&HRIR_MASK][0]; + *(RightOut++) += Values[Offset&HRIR_MASK][1]; + } +} diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c new file mode 100644 index 00000000..b93d11fd --- /dev/null +++ b/Alc/mixer/mixer_neon.c @@ -0,0 +1,261 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" +#include "hrtf.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALsizei frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) +{ + const int32x4_t increment4 = vdupq_n_s32(increment*4); + const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); + const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); + alignas(16) ALint pos_[4]; + alignas(16) ALsizei frac_[4]; + int32x4_t pos4; + int32x4_t frac4; + ALsizei i; + + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + + frac4 = vld1q_s32(frac_); + pos4 = vld1q_s32(pos_); + + for(i = 0;numsamples-i > 3;i += 4) + { + const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]}; + const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]}; + + /* val1 + (val2-val1)*mu */ + const float32x4_t r0 = vsubq_f32(val2, val1); + const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); + const float32x4_t out = vmlaq_f32(val1, mu, r0); + + vst1q_f32(&dst[i], out); + + frac4 = vaddq_s32(frac4, increment4); + pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); + frac4 = vandq_s32(frac4, fracMask4); + + vst1q_s32(pos_, pos4); + } + + if(i < numsamples) + { + /* NOTE: These four elements represent the position *after* the last + * four samples, so the lowest element is the next position to + * resample. + */ + ALint pos = pos_[0]; + frac = vgetq_lane_s32(frac4, 0); + do { + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } while(++i < numsamples); + } + return dst; +} + +const ALfloat *Resample_bsinc_Neon(const InterpState *state, + const ALfloat *restrict src, ALsizei frac, ALint increment, + ALfloat *restrict dst, ALsizei dstlen) +{ + const ALfloat *const filter = state->bsinc.filter; + const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); + const ALsizei m = state->bsinc.m; + const float32x4_t *fil, *scd, *phd, *spd; + ALsizei pi, i, j, offset; + float32x4_t r4; + ALfloat pf; + + src += state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALsizei c; + float32x4_t leftright4; + { + float32x2_t leftright2 = vdup_n_f32(0.0); + leftright2 = vset_lane_f32(left, leftright2, 0); + leftright2 = vset_lane_f32(right, leftright2, 1); + leftright4 = vcombine_f32(leftright2, leftright2); + } + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); + for(c = 0;c < IrSize;c += 2) + { + const ALsizei o0 = (Offset+c)&HRIR_MASK; + const ALsizei o1 = (o0+1)&HRIR_MASK; + float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), + vld1_f32((float32_t*)&Values[o1][0])); + float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); + + vals = vmlaq_f32(vals, coefs, leftright4); + + vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); + vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); + } +} + +#define MixHrtf MixHrtf_Neon +#define MixHrtfBlend MixHrtfBlend_Neon +#define MixDirectHrtf MixDirectHrtf_Neon +#include "mixer_inc.c" +#undef MixHrtf + + +void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + ALfloat gain, delta, step; + float32x4_t gain4; + ALsizei c; + + data = ASSUME_ALIGNED(data, 16); + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); + + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + /* Mix with applying gain steps in aligned multiples of 4. */ + if(minsize-pos > 3) + { + float32x4_t step4; + gain4 = vsetq_lane_f32(gain, gain4, 0); + gain4 = vsetq_lane_f32(gain + step, gain4, 1); + gain4 = vsetq_lane_f32(gain + step + step, gain4, 2); + gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3); + step4 = vdupq_n_f32(step + step + step + step); + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + gain4 = vaddq_f32(gain4, step4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(minsize-pos > 3); + /* NOTE: gain4 now represents the next four gains after the + * last four mixed samples, so the lowest element represents + * the next gain to apply. + */ + gain = vgetq_lane_f32(gain4, 0); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos]*gain; + gain += step; + } + if(pos == Counter) + gain = TargetGains[c]; + CurrentGains[c] = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + gain4 = vdupq_n_f32(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + float32x4_t gain4; + ALsizei c; + + data = ASSUME_ALIGNED(data, 16); + OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); + + for(c = 0;c < InChans;c++) + { + ALsizei pos = 0; + ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + gain4 = vdupq_n_f32(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][InPos+pos]*gain; + } +} diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c new file mode 100644 index 00000000..288661b2 --- /dev/null +++ b/Alc/mixer/mixer_sse.c @@ -0,0 +1,229 @@ +#include "config.h" + +#include + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" + +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "defs.h" + + +const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, + ALsizei frac, ALint increment, ALfloat *restrict dst, + ALsizei dstlen) +{ + const ALfloat *const filter = state->bsinc.filter; + const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); + const ALsizei m = state->bsinc.m; + const __m128 *fil, *scd, *phd, *spd; + ALsizei pi, i, j, offset; + ALfloat pf; + __m128 r4; + + src += state->bsinc.l; + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat left, ALfloat right) +{ + const __m128 lrlr = _mm_setr_ps(left, right, left, right); + __m128 vals = _mm_setzero_ps(); + __m128 coeffs; + ALsizei i; + + Values = ASSUME_ALIGNED(Values, 16); + Coeffs = ASSUME_ALIGNED(Coeffs, 16); + if((Offset&1)) + { + const ALsizei o0 = Offset&HRIR_MASK; + const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; + __m128 imp0, imp1; + + coeffs = _mm_load_ps(&Coeffs[0][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); + imp0 = _mm_mul_ps(lrlr, coeffs); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi((__m64*)&Values[o0][0], vals); + for(i = 1;i < IrSize-1;i += 2) + { + const ALsizei o2 = (Offset+i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[o2][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _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 ALsizei o = (Offset + i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i][0]); + vals = _mm_load_ps(&Values[o][0]); + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[o][0], vals); + } + } +} + +#define MixHrtf MixHrtf_SSE +#define MixHrtfBlend MixHrtfBlend_SSE +#define MixDirectHrtf MixDirectHrtf_SSE +#include "mixer_inc.c" +#undef MixHrtf + + +void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, + ALsizei BufferSize) +{ + ALfloat gain, delta, step; + __m128 gain4; + ALsizei c; + + delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; + + for(c = 0;c < OutChans;c++) + { + ALsizei pos = 0; + gain = CurrentGains[c]; + step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) + { + ALsizei minsize = mini(BufferSize, Counter); + /* Mix with applying gain steps in aligned multiples of 4. */ + if(minsize-pos > 3) + { + __m128 step4; + gain4 = _mm_setr_ps( + gain, + gain + step, + gain + step + step, + gain + step + step + step + ); + step4 = _mm_set1_ps(step + step + step + step); + do { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + gain4 = _mm_add_ps(gain4, step4); + _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(minsize-pos > 3); + /* NOTE: gain4 now represents the next four gains after the + * last four mixed samples, so the lowest element represents + * the next gain to apply. + */ + gain = _mm_cvtss_f32(gain4); + } + /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ + for(;pos < minsize;pos++) + { + OutBuffer[c][OutPos+pos] += data[pos]*gain; + gain += step; + } + if(pos == Counter) + gain = TargetGains[c]; + CurrentGains[c] = gain; + + /* Mix until pos is aligned with 4 or the mix is done. */ + minsize = mini(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + gain4 = _mm_set1_ps(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[c][OutPos+pos] += data[pos]*gain; + } +} + +void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) +{ + __m128 gain4; + ALsizei c; + + for(c = 0;c < InChans;c++) + { + ALsizei pos = 0; + ALfloat gain = Gains[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + gain4 = _mm_set1_ps(gain); + for(;BufferSize-pos > 3;pos += 4) + { + const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[pos], dry4); + } + for(;pos < BufferSize;pos++) + OutBuffer[pos] += data[c][InPos+pos]*gain; + } +} diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c new file mode 100644 index 00000000..19d07719 --- /dev/null +++ b/Alc/mixer/mixer_sse2.c @@ -0,0 +1,82 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alu.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALsizei frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) +{ + const __m128i increment4 = _mm_set1_epi32(increment*4); + const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); + const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); + union { alignas(16) ALint i[4]; float f[4]; } pos_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; + __m128i frac4, pos4; + ALint pos; + ALsizei i; + + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + + frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); + pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); + + for(i = 0;numsamples-i > 3;i += 4) + { + const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); + const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); + + /* val1 + (val2-val1)*mu */ + const __m128 r0 = _mm_sub_ps(val2, val1); + const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4); + const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0)); + + _mm_store_ps(&dst[i], out); + + frac4 = _mm_add_epi32(frac4, increment4); + pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); + frac4 = _mm_and_si128(frac4, fracMask4); + + _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4)); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = pos_.i[0]; + frac = _mm_cvtsi128_si32(frac4); + + for(;i < numsamples;i++) + { + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} diff --git a/Alc/mixer/mixer_sse3.c b/Alc/mixer/mixer_sse3.c new file mode 100644 index 00000000..e69de29b diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c new file mode 100644 index 00000000..85fd0f5e --- /dev/null +++ b/Alc/mixer/mixer_sse41.c @@ -0,0 +1,86 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2014 by Timothy Arceri . + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include + +#include "alu.h" +#include "defs.h" + + +const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), + const ALfloat *restrict src, ALsizei frac, ALint increment, + ALfloat *restrict dst, ALsizei numsamples) +{ + const __m128i increment4 = _mm_set1_epi32(increment*4); + const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); + const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); + union { alignas(16) ALint i[4]; float f[4]; } pos_; + union { alignas(16) ALsizei i[4]; float f[4]; } frac_; + __m128i frac4, pos4; + ALint pos; + ALsizei i; + + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + + frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); + pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); + + for(i = 0;numsamples-i > 3;i += 4) + { + const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); + const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); + + /* val1 + (val2-val1)*mu */ + const __m128 r0 = _mm_sub_ps(val2, val1); + const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4); + const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0)); + + _mm_store_ps(&dst[i], out); + + frac4 = _mm_add_epi32(frac4, increment4); + pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); + frac4 = _mm_and_si128(frac4, fracMask4); + + pos_.i[0] = _mm_extract_epi32(pos4, 0); + pos_.i[1] = _mm_extract_epi32(pos4, 1); + pos_.i[2] = _mm_extract_epi32(pos4, 2); + pos_.i[3] = _mm_extract_epi32(pos4, 3); + } + + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = pos_.i[0]; + frac = _mm_cvtsi128_si32(frac4); + + for(;i < numsamples;i++) + { + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c deleted file mode 100644 index 2346080a..00000000 --- a/Alc/mixer_c.c +++ /dev/null @@ -1,208 +0,0 @@ -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" - - -static inline ALfloat do_point(const ALfloat *restrict vals, ALsizei UNUSED(frac)) -{ return vals[0]; } -static inline ALfloat do_lerp(const ALfloat *restrict vals, ALsizei frac) -{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const ALfloat *restrict vals, ALsizei frac) -{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } - -const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment), - ALfloat *restrict dst, ALsizei numsamples) -{ -#if defined(HAVE_SSE) || defined(HAVE_NEON) - /* Avoid copying the source data if it's aligned like the destination. */ - if((((intptr_t)src)&15) == (((intptr_t)dst)&15)) - return src; -#endif - memcpy(dst, src, numsamples*sizeof(ALfloat)); - return dst; -} - -#define DECL_TEMPLATE(Tag, Sampler, O) \ -const ALfloat *Resample_##Tag##_C(const InterpState* UNUSED(state), \ - const ALfloat *restrict src, ALsizei frac, ALint increment, \ - ALfloat *restrict dst, ALsizei numsamples) \ -{ \ - ALsizei i; \ - \ - src -= O; \ - for(i = 0;i < numsamples;i++) \ - { \ - dst[i] = Sampler(src, frac); \ - \ - frac += increment; \ - src += frac>>FRACTIONBITS; \ - frac &= FRACTIONMASK; \ - } \ - return dst; \ -} - -DECL_TEMPLATE(point, do_point, 0) -DECL_TEMPLATE(lerp, do_lerp, 0) -DECL_TEMPLATE(cubic, do_cubic, 1) - -#undef DECL_TEMPLATE - -const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen) -{ - const ALfloat *fil, *scd, *phd, *spd; - const ALfloat *const filter = state->bsinc.filter; - const ALfloat sf = state->bsinc.sf; - const ALsizei m = state->bsinc.m; - ALsizei j_f, pi, i; - ALfloat pf, r; - - src += state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) -{ - ALsizei i; - if(LIKELY(numsamples > 1)) - { - ALfloat x0 = filter->x[0]; - ALfloat x1 = filter->x[1]; - ALfloat y0 = filter->y[0]; - ALfloat y1 = filter->y[1]; - - for(i = 0;i < numsamples;i++) - { - dst[i] = filter->b0* src[i] + - filter->b1*x0 + filter->b2*x1 - - filter->a1*y0 - filter->a2*y1; - y1 = y0; y0 = dst[i]; - x1 = x0; x0 = src[i]; - } - - filter->x[0] = x0; - filter->x[1] = x1; - filter->y[0] = y0; - filter->y[1] = y1; - } - else if(numsamples == 1) - { - dst[0] = filter->b0 * src[0] + - filter->b1 * filter->x[0] + - filter->b2 * filter->x[1] - - filter->a1 * filter->y[0] - - filter->a2 * filter->y[1]; - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = dst[0]; - } -} - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALsizei c; - for(c = 0;c < IrSize;c++) - { - const ALsizei off = (Offset+c)&HRIR_MASK; - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; - } -} - -#define MixHrtf MixHrtf_C -#define MixHrtfBlend MixHrtfBlend_C -#define MixDirectHrtf MixDirectHrtf_C -#include "mixer_inc.c" -#undef MixHrtf - - -void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - ALfloat gain, delta, step; - ALsizei c; - - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; - if(fabsf(step) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; - } - if(pos == Counter) - gain = TargetGains[c]; - CurrentGains[c] = gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -/* Basically the inverse of the above. Rather than one input going to multiple - * outputs (each with its own gain), it's multiple inputs (each with its own - * gain) going to one output. This applies one row (vs one column) of a matrix - * transform. And as the matrices are more or less static once set up, no - * stepping is necessary. - */ -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - ALsizei c, i; - - for(c = 0;c < InChans;c++) - { - ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - for(i = 0;i < BufferSize;i++) - OutBuffer[i] += data[c][InPos+i] * gain; - } -} diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h deleted file mode 100644 index fe19cef4..00000000 --- a/Alc/mixer_defs.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef MIXER_DEFS_H -#define MIXER_DEFS_H - -#include "AL/alc.h" -#include "AL/al.h" -#include "alMain.h" -#include "alu.h" - -struct MixGains; - -struct MixHrtfParams; -struct HrtfState; - -/* C resamplers */ -const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); -const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen); - - -/* C mixers */ -void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize); -void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize); -void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize); -void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, - ALsizei InPos, ALsizei BufferSize); - -/* SSE mixers */ -void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize); -void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize); -void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize); -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, - ALsizei InPos, ALsizei BufferSize); - -/* SSE resamplers */ -inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) -{ - ALsizei i; - - pos_arr[0] = 0; - frac_arr[0] = frac; - for(i = 1;i < size;i++) - { - ALint frac_tmp = frac_arr[i-1] + increment; - pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); - frac_arr[i] = frac_tmp&FRACTIONMASK; - } -} - -const ALfloat *Resample_lerp_SSE2(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); -const ALfloat *Resample_lerp_SSE41(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); - -const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen); - -/* Neon mixers */ -void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, struct MixHrtfParams *hrtfparams, - struct HrtfState *hrtfstate, ALsizei BufferSize); -void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize); -void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize); -void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize); -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, - const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, - ALsizei InPos, ALsizei BufferSize); - -/* Neon resamplers */ -const ALfloat *Resample_lerp_Neon(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei numsamples); -const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen); - -#endif /* MIXER_DEFS_H */ diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c deleted file mode 100644 index 3c9d4dc5..00000000 --- a/Alc/mixer_inc.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "config.h" - -#include "alMain.h" -#include "alSource.h" - -#include "hrtf.h" -#include "mixer_defs.h" -#include "align.h" -#include "alu.h" - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei irSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right); - - -void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); - const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; - ALfloat gainstep = hrtfparams->GainStep; - ALfloat gain = hrtfparams->Gain; - ALfloat left, right; - ALsizei i; - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; - - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - gain += gainstep; - Offset++; - } - hrtfparams->Gain = gain; -} - -void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); - const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; - ALfloat oldGain = oldparams->Gain; - ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; - const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); - const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; - ALfloat newGain = newparams->Gain; - ALfloat newGainStep = newparams->GainStep; - ALfloat left, right; - ALsizei i; - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; - right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); - - left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; - right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); - - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - oldGain += oldGainStep; - newGain += newGainStep; - Offset++; - } - newparams->Gain = newGain; -} - -void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize) -{ - ALfloat insample; - ALsizei i; - - for(i = 0;i < BufferSize;i++) - { - Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - insample = *(data++); - ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); - *(LeftOut++) += Values[Offset&HRIR_MASK][0]; - *(RightOut++) += Values[Offset&HRIR_MASK][1]; - } -} diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c deleted file mode 100644 index 631e4f7c..00000000 --- a/Alc/mixer_neon.c +++ /dev/null @@ -1,261 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" -#include "hrtf.h" -#include "mixer_defs.h" - - -const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const int32x4_t increment4 = vdupq_n_s32(increment*4); - const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); - const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); - alignas(16) ALint pos_[4]; - alignas(16) ALsizei frac_[4]; - int32x4_t pos4; - int32x4_t frac4; - ALsizei i; - - InitiatePositionArrays(frac, increment, frac_, pos_, 4); - - frac4 = vld1q_s32(frac_); - pos4 = vld1q_s32(pos_); - - for(i = 0;numsamples-i > 3;i += 4) - { - const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]}; - const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]}; - - /* val1 + (val2-val1)*mu */ - const float32x4_t r0 = vsubq_f32(val2, val1); - const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4); - const float32x4_t out = vmlaq_f32(val1, mu, r0); - - vst1q_f32(&dst[i], out); - - frac4 = vaddq_s32(frac4, increment4); - pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); - frac4 = vandq_s32(frac4, fracMask4); - - vst1q_s32(pos_, pos4); - } - - if(i < numsamples) - { - /* NOTE: These four elements represent the position *after* the last - * four samples, so the lowest element is the next position to - * resample. - */ - ALint pos = pos_[0]; - frac = vgetq_lane_s32(frac4, 0); - do { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } while(++i < numsamples); - } - return dst; -} - -const ALfloat *Resample_bsinc_Neon(const InterpState *state, - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei dstlen) -{ - const ALfloat *const filter = state->bsinc.filter; - const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const float32x4_t *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; - float32x4_t r4; - ALfloat pf; - - src += state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALsizei c; - float32x4_t leftright4; - { - float32x2_t leftright2 = vdup_n_f32(0.0); - leftright2 = vset_lane_f32(left, leftright2, 0); - leftright2 = vset_lane_f32(right, leftright2, 1); - leftright4 = vcombine_f32(leftright2, leftright2); - } - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); - for(c = 0;c < IrSize;c += 2) - { - const ALsizei o0 = (Offset+c)&HRIR_MASK; - const ALsizei o1 = (o0+1)&HRIR_MASK; - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), - vld1_f32((float32_t*)&Values[o1][0])); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - - vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); - } -} - -#define MixHrtf MixHrtf_Neon -#define MixHrtfBlend MixHrtfBlend_Neon -#define MixDirectHrtf MixDirectHrtf_Neon -#include "mixer_inc.c" -#undef MixHrtf - - -void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - ALfloat gain, delta, step; - float32x4_t gain4; - ALsizei c; - - data = ASSUME_ALIGNED(data, 16); - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; - if(fabsf(step) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - /* Mix with applying gain steps in aligned multiples of 4. */ - if(minsize-pos > 3) - { - float32x4_t step4; - gain4 = vsetq_lane_f32(gain, gain4, 0); - gain4 = vsetq_lane_f32(gain + step, gain4, 1); - gain4 = vsetq_lane_f32(gain + step + step, gain4, 2); - gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3); - step4 = vdupq_n_f32(step + step + step + step); - do { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - gain4 = vaddq_f32(gain4, step4); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(minsize-pos > 3); - /* NOTE: gain4 now represents the next four gains after the - * last four mixed samples, so the lowest element represents - * the next gain to apply. - */ - gain = vgetq_lane_f32(gain4, 0); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; - } - if(pos == Counter) - gain = TargetGains[c]; - CurrentGains[c] = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - gain4 = vdupq_n_f32(gain); - for(;BufferSize-pos > 3;pos += 4) - { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - float32x4_t gain4; - ALsizei c; - - data = ASSUME_ALIGNED(data, 16); - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - - for(c = 0;c < InChans;c++) - { - ALsizei pos = 0; - ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - gain4 = vdupq_n_f32(gain); - for(;BufferSize-pos > 3;pos += 4) - { - const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][InPos+pos]*gain; - } -} diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c deleted file mode 100644 index 281b6f85..00000000 --- a/Alc/mixer_sse.c +++ /dev/null @@ -1,229 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" - -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "mixer_defs.h" - - -const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen) -{ - const ALfloat *const filter = state->bsinc.filter; - const __m128 sf4 = _mm_set1_ps(state->bsinc.sf); - const ALsizei m = state->bsinc.m; - const __m128 *fil, *scd, *phd, *spd; - ALsizei pi, i, j, offset; - ALfloat pf; - __m128 r4; - - src += state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - const __m128 lrlr = _mm_setr_ps(left, right, left, right); - __m128 vals = _mm_setzero_ps(); - __m128 coeffs; - ALsizei i; - - Values = ASSUME_ALIGNED(Values, 16); - Coeffs = ASSUME_ALIGNED(Coeffs, 16); - if((Offset&1)) - { - const ALsizei o0 = Offset&HRIR_MASK; - const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK; - __m128 imp0, imp1; - - coeffs = _mm_load_ps(&Coeffs[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); - imp0 = _mm_mul_ps(lrlr, coeffs); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o0][0], vals); - for(i = 1;i < IrSize-1;i += 2) - { - const ALsizei o2 = (Offset+i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[o2][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _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 ALsizei o = (Offset + i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i][0]); - vals = _mm_load_ps(&Values[o][0]); - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[o][0], vals); - } - } -} - -#define MixHrtf MixHrtf_SSE -#define MixHrtfBlend MixHrtfBlend_SSE -#define MixDirectHrtf MixDirectHrtf_SSE -#include "mixer_inc.c" -#undef MixHrtf - - -void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, - ALsizei BufferSize) -{ - ALfloat gain, delta, step; - __m128 gain4; - ALsizei c; - - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - - for(c = 0;c < OutChans;c++) - { - ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; - if(fabsf(step) > FLT_EPSILON) - { - ALsizei minsize = mini(BufferSize, Counter); - /* Mix with applying gain steps in aligned multiples of 4. */ - if(minsize-pos > 3) - { - __m128 step4; - gain4 = _mm_setr_ps( - gain, - gain + step, - gain + step + step, - gain + step + step + step - ); - step4 = _mm_set1_ps(step + step + step + step); - do { - const __m128 val4 = _mm_load_ps(&data[pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - gain4 = _mm_add_ps(gain4, step4); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(minsize-pos > 3); - /* NOTE: gain4 now represents the next four gains after the - * last four mixed samples, so the lowest element represents - * the next gain to apply. - */ - gain = _mm_cvtss_f32(gain4); - } - /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < minsize;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; - } - if(pos == Counter) - gain = TargetGains[c]; - CurrentGains[c] = gain; - - /* Mix until pos is aligned with 4 or the mix is done. */ - minsize = mini(BufferSize, (pos+3)&~3); - for(;pos < minsize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - gain4 = _mm_set1_ps(gain); - for(;BufferSize-pos > 3;pos += 4) - { - const __m128 val4 = _mm_load_ps(&data[pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} - -void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) -{ - __m128 gain4; - ALsizei c; - - for(c = 0;c < InChans;c++) - { - ALsizei pos = 0; - ALfloat gain = Gains[c]; - if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) - continue; - - gain4 = _mm_set1_ps(gain); - for(;BufferSize-pos > 3;pos += 4) - { - const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[pos] += data[c][InPos+pos]*gain; - } -} diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c deleted file mode 100644 index 3f8224e7..00000000 --- a/Alc/mixer_sse2.c +++ /dev/null @@ -1,82 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alu.h" -#include "mixer_defs.h" - - -const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const __m128i increment4 = _mm_set1_epi32(increment*4); - const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); - const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALsizei i[4]; float f[4]; } frac_; - __m128i frac4, pos4; - ALint pos; - ALsizei i; - - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); - - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - for(i = 0;numsamples-i > 3;i += 4) - { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); - const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); - - /* val1 + (val2-val1)*mu */ - const __m128 r0 = _mm_sub_ps(val2, val1); - const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4); - const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0)); - - _mm_store_ps(&dst[i], out); - - frac4 = _mm_add_epi32(frac4, increment4); - pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); - frac4 = _mm_and_si128(frac4, fracMask4); - - _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4)); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = pos_.i[0]; - frac = _mm_cvtsi128_si32(frac4); - - for(;i < numsamples;i++) - { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c deleted file mode 100644 index e69de29b..00000000 diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c deleted file mode 100644 index 4f88d540..00000000 --- a/Alc/mixer_sse41.c +++ /dev/null @@ -1,86 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alu.h" -#include "mixer_defs.h" - - -const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), - const ALfloat *restrict src, ALsizei frac, ALint increment, - ALfloat *restrict dst, ALsizei numsamples) -{ - const __m128i increment4 = _mm_set1_epi32(increment*4); - const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); - const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALsizei i[4]; float f[4]; } frac_; - __m128i frac4, pos4; - ALint pos; - ALsizei i; - - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); - - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - for(i = 0;numsamples-i > 3;i += 4) - { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); - const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); - - /* val1 + (val2-val1)*mu */ - const __m128 r0 = _mm_sub_ps(val2, val1); - const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4); - const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0)); - - _mm_store_ps(&dst[i], out); - - frac4 = _mm_add_epi32(frac4, increment4); - pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); - frac4 = _mm_and_si128(frac4, fracMask4); - - pos_.i[0] = _mm_extract_epi32(pos4, 0); - pos_.i[1] = _mm_extract_epi32(pos4, 1); - pos_.i[2] = _mm_extract_epi32(pos4, 2); - pos_.i[3] = _mm_extract_epi32(pos4, 3); - } - - /* NOTE: These four elements represent the position *after* the last four - * samples, so the lowest element is the next position to resample. - */ - pos = pos_.i[0]; - frac = _mm_cvtsi128_si32(frac4); - - for(;i < numsamples;i++) - { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c new file mode 100644 index 00000000..0e039115 --- /dev/null +++ b/Alc/mixvoice.c @@ -0,0 +1,781 @@ +/** + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alListener.h" +#include "alAuxEffectSlot.h" +#include "sample_cvt.h" +#include "alu.h" +#include "alconfig.h" +#include "ringbuffer.h" + +#include "cpu_caps.h" +#include "mixer/defs.h" + + +static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, + "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); + +extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); + + +/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ +static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!"); + + +enum Resampler ResamplerDefault = LinearResampler; + +MixerFunc MixSamples = Mix_C; +RowMixerFunc MixRowSamples = MixRow_C; +static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; +static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C; + +static MixerFunc SelectMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Mix_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Mix_SSE; +#endif + return Mix_C; +} + +static RowMixerFunc SelectRowMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixRow_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixRow_SSE; +#endif + return MixRow_C; +} + +static inline HrtfMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtf_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_SSE; +#endif + return MixHrtf_C; +} + +static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void) +{ +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtfBlend_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtfBlend_SSE; +#endif + return MixHrtfBlend_C; +} + +ResamplerFunc SelectResampler(enum Resampler resampler) +{ + switch(resampler) + { + case PointResampler: + return Resample_point_C; + case LinearResampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_lerp_Neon; +#endif +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_lerp_SSE41; +#endif +#ifdef HAVE_SSE2 + if((CPUCapFlags&CPU_CAP_SSE2)) + return Resample_lerp_SSE2; +#endif + return Resample_lerp_C; + case FIR4Resampler: + return Resample_cubic_C; + case BSinc12Resampler: + case BSinc24Resampler: +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return Resample_bsinc_Neon; +#endif +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_bsinc_SSE; +#endif + return Resample_bsinc_C; + } + + return Resample_point_C; +} + + +void aluInitMixer(void) +{ + const char *str; + + if(ConfigValueStr(NULL, NULL, "resampler", &str)) + { + if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + ResamplerDefault = PointResampler; + else if(strcasecmp(str, "linear") == 0) + ResamplerDefault = LinearResampler; + else if(strcasecmp(str, "cubic") == 0) + ResamplerDefault = FIR4Resampler; + else if(strcasecmp(str, "bsinc12") == 0) + ResamplerDefault = BSinc12Resampler; + else if(strcasecmp(str, "bsinc24") == 0) + ResamplerDefault = BSinc24Resampler; + else if(strcasecmp(str, "bsinc") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str); + ResamplerDefault = BSinc12Resampler; + } + else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0) + { + WARN("Resampler option \"%s\" is deprecated, using cubic\n", str); + ResamplerDefault = FIR4Resampler; + } + else + { + char *end; + long n = strtol(str, &end, 0); + if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) + ResamplerDefault = n; + else + WARN("Invalid resampler: %s\n", str); + } + } + + MixHrtfBlendSamples = SelectHrtfBlendMixer(); + MixHrtfSamples = SelectHrtfMixer(); + MixSamples = SelectMixer(); + MixRowSamples = SelectRowMixer(); +} + + +static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, + ALuint objid, ALuint param, const char *msg) +{ + AsyncEvent evt; + evt.EnumType = enumtype; + evt.Type = type; + evt.ObjectId = objid; + evt.Param = param; + strcpy(evt.Message, msg); + if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) + alsem_post(&context->EventSem); +} + + +static inline ALfloat Sample_ALubyte(ALubyte val) +{ return (val-128) * (1.0f/128.0f); } + +static inline ALfloat Sample_ALshort(ALshort val) +{ return val * (1.0f/32768.0f); } + +static inline ALfloat Sample_ALfloat(ALfloat val) +{ return val; } + +static inline ALfloat Sample_ALdouble(ALdouble val) +{ return (ALfloat)val; } + +typedef ALubyte ALmulaw; +static inline ALfloat Sample_ALmulaw(ALmulaw val) +{ return muLawDecompressionTable[val] * (1.0f/32768.0f); } + +typedef ALubyte ALalaw; +static inline ALfloat Sample_ALalaw(ALalaw val) +{ return aLawDecompressionTable[val] * (1.0f/32768.0f); } + +#define DECL_TEMPLATE(T) \ +static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \ + ALint srcstep, ALsizei samples) \ +{ \ + ALsizei i; \ + for(i = 0;i < samples;i++) \ + dst[i] += Sample_##T(src[i*srcstep]); \ +} + +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) + +#undef DECL_TEMPLATE + +static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep, + enum FmtType srctype, ALsizei samples) +{ +#define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break + switch(srctype) + { + HANDLE_FMT(FmtUByte, ALubyte); + HANDLE_FMT(FmtShort, ALshort); + HANDLE_FMT(FmtFloat, ALfloat); + HANDLE_FMT(FmtDouble, ALdouble); + HANDLE_FMT(FmtMulaw, ALmulaw); + HANDLE_FMT(FmtAlaw, ALalaw); + } +#undef HANDLE_FMT +} + + +static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter, + ALfloat *restrict dst, const ALfloat *restrict src, + ALsizei numsamples, enum ActiveFilters type) +{ + ALsizei i; + switch(type) + { + case AF_None: + ALfilterState_processPassthru(lpfilter, src, numsamples); + ALfilterState_processPassthru(hpfilter, src, numsamples); + break; + + case AF_LowPass: + ALfilterState_process(lpfilter, dst, src, numsamples); + ALfilterState_processPassthru(hpfilter, dst, numsamples); + return dst; + case AF_HighPass: + ALfilterState_processPassthru(lpfilter, src, numsamples); + ALfilterState_process(hpfilter, dst, src, numsamples); + return dst; + + case AF_BandPass: + for(i = 0;i < numsamples;) + { + ALfloat temp[256]; + ALsizei todo = mini(256, numsamples-i); + + ALfilterState_process(lpfilter, temp, src+i, todo); + ALfilterState_process(hpfilter, dst+i, temp, todo); + i += todo; + } + return dst; + } + return src; +} + + +/* This function uses these device temp buffers. */ +#define SOURCE_DATA_BUF 0 +#define RESAMPLED_BUF 1 +#define FILTERED_BUF 2 +#define NFC_DATA_BUF 3 +ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo) +{ + ALCdevice *Device = Context->Device; + ALbufferlistitem *BufferListItem; + ALbufferlistitem *BufferLoopItem; + ALsizei NumChannels, SampleSize; + ALbitfieldSOFT enabledevt; + ALsizei buffers_done = 0; + ResamplerFunc Resample; + ALsizei DataPosInt; + ALsizei DataPosFrac; + ALint64 DataSize64; + ALint increment; + ALsizei Counter; + ALsizei OutPos; + ALsizei IrSize; + bool isplaying; + bool firstpass; + bool isstatic; + ALsizei chan; + ALsizei send; + + /* Get source info */ + isplaying = true; /* Will only be called while playing. */ + isstatic = !!(voice->Flags&VOICE_IS_STATIC); + DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire); + DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); + BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed); + NumChannels = voice->NumChannels; + SampleSize = voice->SampleSize; + increment = voice->Step; + + IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0); + + Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_copy_C : voice->Resampler); + + Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0; + firstpass = true; + OutPos = 0; + + do { + ALsizei SrcBufferSize, DstBufferSize; + + /* Figure out how many buffer samples will be needed */ + DataSize64 = SamplesToDo-OutPos; + DataSize64 *= increment; + DataSize64 += DataPosFrac+FRACTIONMASK; + DataSize64 >>= FRACTIONBITS; + DataSize64 += MAX_RESAMPLE_PADDING*2; + SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE); + + /* Figure out how many samples we can actually mix from this. */ + DataSize64 = SrcBufferSize; + DataSize64 -= MAX_RESAMPLE_PADDING*2; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= DataPosFrac; + DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment, + SamplesToDo - OutPos); + + /* Some mixers like having a multiple of 4, so try to give that unless + * this is the last update. */ + if(DstBufferSize < SamplesToDo-OutPos) + DstBufferSize &= ~3; + + /* It's impossible to have a buffer list item with no entries. */ + assert(BufferListItem->num_buffers > 0); + + for(chan = 0;chan < NumChannels;chan++) + { + const ALfloat *ResampledData; + ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF]; + ALsizei FilledAmt; + + /* Load the previous samples into the source data first, and clear the rest. */ + memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat)); + memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)* + sizeof(ALfloat)); + FilledAmt = MAX_RESAMPLE_PADDING; + + if(isstatic) + { + /* TODO: For static sources, loop points are taken from the + * first buffer (should be adjusted by any buffer offset, to + * possibly be added later). + */ + const ALbuffer *Buffer0 = BufferListItem->buffers[0]; + const ALsizei LoopStart = Buffer0->LoopStart; + const ALsizei LoopEnd = Buffer0->LoopEnd; + const ALsizei LoopSize = LoopEnd - LoopStart; + + /* If current pos is beyond the loop range, do not loop */ + if(!BufferLoopItem || DataPosInt >= LoopEnd) + { + ALsizei SizeToDo = SrcBufferSize - FilledAmt; + ALsizei CompLen = 0; + ALsizei i; + + BufferLoopItem = NULL; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = buffer->data; + ALsizei DataSize; + + if(DataPosInt >= buffer->SampleLen) + continue; + + /* Load what's left to play from the buffer */ + DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(DataPosInt*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + } + else + { + ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt); + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = buffer->data; + ALsizei DataSize; + + if(DataPosInt >= buffer->SampleLen) + continue; + + /* Load what's left of this loop iteration */ + DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(DataPosInt*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + + while(SrcBufferSize > FilledAmt) + { + const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize); + + CompLen = 0; + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + const ALubyte *Data = buffer->data; + ALsizei DataSize; + + if(LoopStart >= buffer->SampleLen) + continue; + + DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart); + CompLen = maxi(CompLen, DataSize); + + LoadSamples(&SrcData[FilledAmt], + &Data[(LoopStart*NumChannels + chan)*SampleSize], + NumChannels, buffer->FmtType, DataSize + ); + } + FilledAmt += CompLen; + } + } + } + else + { + /* Crawl the buffer queue to fill in the temp buffer */ + ALbufferlistitem *tmpiter = BufferListItem; + ALsizei pos = DataPosInt; + + while(tmpiter && SrcBufferSize > FilledAmt) + { + ALsizei SizeToDo = SrcBufferSize - FilledAmt; + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < tmpiter->num_buffers;i++) + { + const ALbuffer *ALBuffer = tmpiter->buffers[i]; + ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; + CompLen = maxi(CompLen, DataSize); + + if(DataSize > pos) + { + const ALubyte *Data = ALBuffer->data; + Data += (pos*NumChannels + chan)*SampleSize; + + DataSize = minu(SizeToDo, DataSize - pos); + LoadSamples(&SrcData[FilledAmt], Data, NumChannels, + ALBuffer->FmtType, DataSize); + } + } + if(pos > CompLen) + pos -= CompLen; + else + { + FilledAmt += CompLen - pos; + pos = 0; + } + if(SrcBufferSize > FilledAmt) + { + tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); + if(!tmpiter) tmpiter = BufferLoopItem; + } + } + } + + /* Store the last source samples used for next time. */ + memcpy(voice->PrevSamples[chan], + &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + MAX_RESAMPLE_PADDING*sizeof(ALfloat) + ); + + /* Now resample, then filter and mix to the appropriate outputs. */ + ResampledData = Resample(&voice->ResampleState, + &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment, + Device->TempBuffer[RESAMPLED_BUF], DstBufferSize + ); + { + DirectParams *parms = &voice->Direct.Params[chan]; + const ALfloat *samples; + + samples = DoFilters( + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], + ResampledData, DstBufferSize, voice->Direct.FilterType + ); + if(!(voice->Flags&VOICE_HAS_HRTF)) + { + if(!Counter) + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); + if(!(voice->Flags&VOICE_HAS_NFC)) + MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + else + { + ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF]; + ALsizei chanoffset = 0; + + MixSamples(samples, + voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, + DstBufferSize + ); + chanoffset += voice->Direct.ChannelsPerOrder[0]; +#define APPLY_NFC_MIX(order) \ + if(voice->Direct.ChannelsPerOrder[order] > 0) \ + { \ + NfcFilterUpdate##order(&parms->NFCtrlFilter, nfcsamples, samples, \ + DstBufferSize); \ + MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ + voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ + parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \ + ); \ + chanoffset += voice->Direct.ChannelsPerOrder[order]; \ + } + APPLY_NFC_MIX(1) + APPLY_NFC_MIX(2) + APPLY_NFC_MIX(3) +#undef APPLY_NFC_MIX + } + } + else + { + MixHrtfParams hrtfparams; + ALsizei fademix = 0; + int lidx, ridx; + + lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(&Device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + + if(!Counter) + { + /* No fading, just overwrite the old HRTF params. */ + parms->Hrtf.Old = parms->Hrtf.Target; + } + else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)) + { + /* The old HRTF params are silent, so overwrite the old + * coefficients with the new, and reset the old gain to + * 0. The future mix will then fade from silence. + */ + parms->Hrtf.Old = parms->Hrtf.Target; + parms->Hrtf.Old.Gain = 0.0f; + } + else if(firstpass) + { + ALfloat gain; + + /* Fade between the coefficients over 128 samples. */ + fademix = mini(DstBufferSize, 128); + + /* The new coefficients need to fade in completely + * since they're replacing the old ones. To keep the + * gain fading consistent, interpolate between the old + * and new target gains given how much of the fade time + * this mix handles. + */ + gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + minf(1.0f, (ALfloat)fademix/Counter)); + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / (ALfloat)fademix; + + MixHrtfBlendSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old, + &hrtfparams, &parms->Hrtf.State, fademix + ); + /* Update the old parameters with the result. */ + parms->Hrtf.Old = parms->Hrtf.Target; + if(fademix < Counter) + parms->Hrtf.Old.Gain = hrtfparams.Gain; + } + + if(fademix < DstBufferSize) + { + ALsizei todo = DstBufferSize - fademix; + ALfloat gain = parms->Hrtf.Target.Gain; + + /* Interpolate the target gain if the gain fading lasts + * longer than this mix. + */ + if(Counter > DstBufferSize) + gain = lerp(parms->Hrtf.Old.Gain, gain, + (ALfloat)todo/(Counter-fademix)); + + hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs; + hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0]; + hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1]; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize, + &hrtfparams, &parms->Hrtf.State, todo + ); + /* Store the interpolated gain or the final target gain + * depending if the fade is done. + */ + if(DstBufferSize < Counter) + parms->Hrtf.Old.Gain = gain; + else + parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain; + } + } + } + + for(send = 0;send < Device->NumAuxSends;send++) + { + SendParams *parms = &voice->Send[send].Params[chan]; + const ALfloat *samples; + + if(!voice->Send[send].Buffer) + continue; + + samples = DoFilters( + &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF], + ResampledData, DstBufferSize, voice->Send[send].FilterType + ); + + if(!Counter) + memcpy(parms->Gains.Current, parms->Gains.Target, + sizeof(parms->Gains.Current)); + MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer, + parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize + ); + } + } + /* Update positions */ + DataPosFrac += increment*DstBufferSize; + DataPosInt += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + + OutPos += DstBufferSize; + voice->Offset += DstBufferSize; + Counter = maxi(DstBufferSize, Counter) - DstBufferSize; + firstpass = false; + + if(isstatic) + { + if(BufferLoopItem) + { + /* Handle looping static source */ + const ALbuffer *Buffer = BufferListItem->buffers[0]; + ALsizei LoopStart = Buffer->LoopStart; + ALsizei LoopEnd = Buffer->LoopEnd; + if(DataPosInt >= LoopEnd) + { + assert(LoopEnd > LoopStart); + DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; + } + } + else + { + /* Handle non-looping static source */ + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); + } + + if(DataPosInt >= CompLen) + { + isplaying = false; + BufferListItem = NULL; + DataPosInt = 0; + DataPosFrac = 0; + break; + } + } + } + else while(1) + { + /* Handle streaming source */ + ALsizei CompLen = 0; + ALsizei i; + + for(i = 0;i < BufferListItem->num_buffers;i++) + { + const ALbuffer *buffer = BufferListItem->buffers[i]; + if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); + } + + if(CompLen > DataPosInt) + break; + + buffers_done += BufferListItem->num_buffers; + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); + if(!BufferListItem && !(BufferListItem=BufferLoopItem)) + { + isplaying = false; + DataPosInt = 0; + DataPosFrac = 0; + break; + } + + DataPosInt -= CompLen; + } + } while(isplaying && OutPos < SamplesToDo); + + voice->Flags |= VOICE_IS_FADING; + + /* Update source info */ + ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed); + ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release); + + /* Send any events now, after the position/buffer info was updated. */ + enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire); + if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted)) + SendAsyncEvent(Context, EventType_BufferCompleted, + AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed" + ); + + return isplaying; +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 986a6c32..646a437c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -735,8 +735,8 @@ SET(ALC_OBJS Alc/ALc.c Alc/bformatdec.c Alc/nfcfilter.c Alc/panning.c - Alc/mixer.c - Alc/mixer_c.c + Alc/mixvoice.c + Alc/mixer/mixer_c.c ) @@ -770,9 +770,9 @@ IF(HAVE_XMMINTRIN_H) IF(ALSOFT_CPUEXT_SSE) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse.c) IF(SSE_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse.c PROPERTIES COMPILE_FLAGS "${SSE_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE") @@ -790,9 +790,9 @@ IF(HAVE_EMMINTRIN_H) IF(HAVE_SSE AND ALSOFT_CPUEXT_SSE2) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE2 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse2.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse2.c) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse2.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse2.c PROPERTIES COMPILE_FLAGS "${SSE2_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE2") @@ -810,9 +810,9 @@ IF(HAVE_EMMINTRIN_H) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE3 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse3.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse3.c) IF(SSE2_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse3.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse3.c PROPERTIES COMPILE_FLAGS "${SSE3_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE3") @@ -830,9 +830,9 @@ IF(HAVE_SMMINTRIN_H) IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE4_1) IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) SET(HAVE_SSE4_1 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse41.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_sse41.c) IF(SSE4_1_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse41.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_sse41.c PROPERTIES COMPILE_FLAGS "${SSE4_1_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, SSE4.1") @@ -850,9 +850,9 @@ IF(HAVE_ARM_NEON_H) OPTION(ALSOFT_CPUEXT_NEON "Enable ARM Neon support" ON) IF(ALSOFT_CPUEXT_NEON) SET(HAVE_NEON 1) - SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_neon.c) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer/mixer_neon.c) IF(FPU_NEON_SWITCH) - SET_SOURCE_FILES_PROPERTIES(Alc/mixer_neon.c PROPERTIES + SET_SOURCE_FILES_PROPERTIES(Alc/mixer/mixer_neon.c PROPERTIES COMPILE_FLAGS "${FPU_NEON_SWITCH}") ENDIF() SET(CPU_EXTS "${CPU_EXTS}, Neon") -- cgit v1.2.3 From 6ea3b5445fc574c8c18ae88d6f853dfb8c14ef1e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 05:41:42 -0700 Subject: Rename mixer_inc.c to hrtf_inc.c --- Alc/mixer/hrtf_inc.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ Alc/mixer/mixer_c.c | 2 +- Alc/mixer/mixer_inc.c | 114 ------------------------------------------------- Alc/mixer/mixer_neon.c | 2 +- Alc/mixer/mixer_sse.c | 2 +- 5 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 Alc/mixer/hrtf_inc.c delete mode 100644 Alc/mixer/mixer_inc.c diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c new file mode 100644 index 00000000..ad0daa63 --- /dev/null +++ b/Alc/mixer/hrtf_inc.c @@ -0,0 +1,114 @@ +#include "config.h" + +#include "alMain.h" +#include "alSource.h" + +#include "hrtf.h" +#include "align.h" +#include "alu.h" +#include "defs.h" + + +static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], + const ALsizei irSize, + const ALfloat (*restrict Coeffs)[2], + ALfloat left, ALfloat right); + + +void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); + const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; + ALfloat gainstep = hrtfparams->GainStep; + ALfloat gain = hrtfparams->Gain; + ALfloat left, right; + ALsizei i; + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; + + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + gain += gainstep; + Offset++; + } + hrtfparams->Gain = gain; +} + +void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, ALsizei OutPos, + const ALsizei IrSize, const HrtfParams *oldparams, + MixHrtfParams *newparams, HrtfState *hrtfstate, + ALsizei BufferSize) +{ + const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); + const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; + ALfloat oldGain = oldparams->Gain; + ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); + const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; + ALfloat newGain = newparams->Gain; + ALfloat newGainStep = newparams->GainStep; + ALfloat left, right; + ALsizei i; + + LeftOut += OutPos; + RightOut += OutPos; + for(i = 0;i < BufferSize;i++) + { + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; + hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; + + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); + + left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; + right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); + + left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; + right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; + ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); + + *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; + *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; + + oldGain += oldGainStep; + newGain += newGainStep; + Offset++; + } + newparams->Gain = newGain; +} + +void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, + const ALfloat *data, ALsizei Offset, const ALsizei IrSize, + const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], + ALsizei BufferSize) +{ + ALfloat insample; + ALsizei i; + + for(i = 0;i < BufferSize;i++) + { + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + insample = *(data++); + ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); + *(LeftOut++) += Values[Offset&HRIR_MASK][0]; + *(RightOut++) += Values[Offset&HRIR_MASK][1]; + } +} diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 0c33e9b0..5f913101 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -149,7 +149,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtf MixHrtf_C #define MixHrtfBlend MixHrtfBlend_C #define MixDirectHrtf MixDirectHrtf_C -#include "mixer_inc.c" +#include "hrtf_inc.c" #undef MixHrtf diff --git a/Alc/mixer/mixer_inc.c b/Alc/mixer/mixer_inc.c deleted file mode 100644 index ad0daa63..00000000 --- a/Alc/mixer/mixer_inc.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "config.h" - -#include "alMain.h" -#include "alSource.h" - -#include "hrtf.h" -#include "align.h" -#include "alu.h" -#include "defs.h" - - -static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], - const ALsizei irSize, - const ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right); - - -void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); - const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; - ALfloat gainstep = hrtfparams->GainStep; - ALfloat gain = hrtfparams->Gain; - ALfloat left, right; - ALsizei i; - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; - - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - gain += gainstep; - Offset++; - } - hrtfparams->Gain = gain; -} - -void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, ALsizei OutPos, - const ALsizei IrSize, const HrtfParams *oldparams, - MixHrtfParams *newparams, HrtfState *hrtfstate, - ALsizei BufferSize) -{ - const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); - const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; - ALfloat oldGain = oldparams->Gain; - ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; - const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); - const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; - ALfloat newGain = newparams->Gain; - ALfloat newGainStep = newparams->GainStep; - ALfloat left, right; - ALsizei i; - - LeftOut += OutPos; - RightOut += OutPos; - for(i = 0;i < BufferSize;i++) - { - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; - - hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - - left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; - right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); - - left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; - right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; - ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); - - *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; - *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - - oldGain += oldGainStep; - newGain += newGainStep; - Offset++; - } - newparams->Gain = newGain; -} - -void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, - const ALfloat *data, ALsizei Offset, const ALsizei IrSize, - const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2], - ALsizei BufferSize) -{ - ALfloat insample; - ALsizei i; - - for(i = 0;i < BufferSize;i++) - { - Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - Offset++; - - insample = *(data++); - ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample); - *(LeftOut++) += Values[Offset&HRIR_MASK][0]; - *(RightOut++) += Values[Offset&HRIR_MASK][1]; - } -} diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index b93d11fd..7f8dd1d4 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -153,7 +153,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtf MixHrtf_Neon #define MixHrtfBlend MixHrtfBlend_Neon #define MixDirectHrtf MixDirectHrtf_Neon -#include "mixer_inc.c" +#include "hrtf_inc.c" #undef MixHrtf diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 288661b2..c9615c25 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -125,7 +125,7 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtf MixHrtf_SSE #define MixHrtfBlend MixHrtfBlend_SSE #define MixDirectHrtf MixDirectHrtf_SSE -#include "mixer_inc.c" +#include "hrtf_inc.c" #undef MixHrtf -- cgit v1.2.3 From 7a23330ffe34c0d04f882fdb45f68733ba49659d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 07:05:40 -0700 Subject: Move the filter implementation to a separate directory --- Alc/ALc.c | 2 + Alc/effects/chorus.c | 2 +- Alc/effects/dedicated.c | 2 +- Alc/effects/distortion.c | 2 +- Alc/effects/echo.c | 1 + Alc/effects/equalizer.c | 2 +- Alc/effects/modulator.c | 2 +- Alc/effects/pshifter.c | 2 +- Alc/effects/reverb.c | 3 +- Alc/filters/defs.h | 118 +++++++++++++++++++++++++++++++++++++++ Alc/filters/filter.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ Alc/mixer/mixer_c.c | 39 ------------- CMakeLists.txt | 1 + OpenAL32/Include/alFilter.h | 117 +------------------------------------- OpenAL32/Include/alu.h | 3 +- OpenAL32/alFilter.c | 85 ---------------------------- OpenAL32/alSource.c | 1 + 17 files changed, 266 insertions(+), 249 deletions(-) create mode 100644 Alc/filters/defs.h create mode 100644 Alc/filters/filter.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 8cfc7d25..597cc890 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -34,6 +34,8 @@ #include "alListener.h" #include "alSource.h" #include "alBuffer.h" +#include "alFilter.h" +#include "alEffect.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "mastering.h" diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 4f8c7ce3..eb0818e3 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -24,10 +24,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch"); diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index b9dd7db3..62a3894f 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -23,10 +23,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" typedef struct ALdedicatedState { diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index b112032c..09289175 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -24,10 +24,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" typedef struct ALdistortionState { diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 34010c47..10e00f39 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -28,6 +28,7 @@ #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" typedef struct ALechoState { diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 22db5d54..a5c65cee 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -24,10 +24,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" /* The document "Effects Extension Guide.pdf" says that low and high * diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 9ec0d47e..bf8e8fd7 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -24,10 +24,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" #define MAX_UPDATE_SAMPLES 128 diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index d36597ae..6542be56 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -24,10 +24,10 @@ #include #include "alMain.h" -#include "alFilter.h" #include "alAuxEffectSlot.h" #include "alError.h" #include "alu.h" +#include "filters/defs.h" #define MAX_SIZE 2048 diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ff1ee143..cd38b492 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -27,10 +27,9 @@ #include "alMain.h" #include "alu.h" #include "alAuxEffectSlot.h" -#include "alEffect.h" -#include "alFilter.h" #include "alListener.h" #include "alError.h" +#include "filters/defs.h" /* This is a user config option for modifying the overall output of the reverb * effect. diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h new file mode 100644 index 00000000..f4e1e62c --- /dev/null +++ b/Alc/filters/defs.h @@ -0,0 +1,118 @@ +#ifndef ALC_FILTER_H +#define ALC_FILTER_H + +#include "AL/al.h" +#include "math_defs.h" + +/* 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 + */ +/* Implementation note: For the shelf filters, the specified gain is for the + * reference frequency, which is the centerpoint of the transition band. This + * better matches EFX filter design. To set the gain for the shelf itself, use + * the square root of the desired linear gain (or halve the dB gain). + */ + +typedef enum ALfilterType { + /** EFX-style low-pass filter, specifying a gain and reference frequency. */ + ALfilterType_HighShelf, + /** EFX-style high-pass filter, specifying a gain and reference frequency. */ + ALfilterType_LowShelf, + /** Peaking filter, specifying a gain and reference frequency. */ + ALfilterType_Peaking, + + /** Low-pass cut-off filter, specifying a cut-off frequency. */ + ALfilterType_LowPass, + /** High-pass cut-off filter, specifying a cut-off frequency. */ + ALfilterType_HighPass, + /** Band-pass filter, specifying a center frequency. */ + ALfilterType_BandPass, +} ALfilterType; + +typedef struct ALfilterState { + ALfloat x[2]; /* History of two last input samples */ + ALfloat y[2]; /* History of two last output samples */ + ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ + ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ +} ALfilterState; +/* Currently only a C-based filter process method is implemented. */ +#define ALfilterState_process ALfilterState_processC + +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the + * reference gain and shelf slope parameter. + * \param gain 0 < gain + * \param slope 0 < slope <= 1 + */ +inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) +{ + return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); +} +/** + * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized + * reference frequency and bandwidth. + * \param f0norm 0 < f0norm < 0.5. + * \param bandwidth 0 < bandwidth + */ +inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) +{ + ALfloat w0 = F_TAU * f0norm; + return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); +} + +inline void ALfilterState_clear(ALfilterState *filter) +{ + filter->x[0] = 0.0f; + filter->x[1] = 0.0f; + filter->y[0] = 0.0f; + filter->y[1] = 0.0f; +} + +/** + * Sets up the filter state for the specified filter type and its parameters. + * + * \param filter The filter object to prepare. + * \param type The type of filter for the object to apply. + * \param gain The gain for the reference frequency response. Only used by the + * Shelf and Peaking filter types. + * \param f0norm The normalized reference frequency (ref_freq / sample_rate). + * This is the center point for the Shelf, Peaking, and BandPass + * filter types, or the cutoff frequency for the LowPass and + * HighPass filter types. + * \param rcpQ The reciprocal of the Q coefficient for the filter's transition + * band. Can be generated from calc_rcpQ_from_slope or + * calc_rcpQ_from_bandwidth depending on the available data. + */ +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); + +inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src) +{ + dst->b0 = src->b0; + dst->b1 = src->b1; + dst->b2 = src->b2; + dst->a1 = src->a1; + dst->a2 = src->a2; +} + +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); + +inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples) +{ + if(numsamples >= 2) + { + filter->x[1] = src[numsamples-2]; + filter->x[0] = src[numsamples-1]; + filter->y[1] = src[numsamples-2]; + filter->y[0] = src[numsamples-1]; + } + else if(numsamples == 1) + { + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = src[0]; + } +} + +#endif /* ALC_FILTER_H */ diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c new file mode 100644 index 00000000..1cf18f08 --- /dev/null +++ b/Alc/filters/filter.c @@ -0,0 +1,133 @@ + +#include "config.h" + +#include "AL/alc.h" +#include "AL/al.h" + +#include "alMain.h" +#include "defs.h" + +extern inline void ALfilterState_clear(ALfilterState *filter); +extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); +extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); +extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); +extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); + + +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) +{ + ALfloat alpha, sqrtgain_alpha_2; + ALfloat w0, sin_w0, cos_w0; + ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; + ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; + + // Limit gain to -100dB + assert(gain > 0.00001f); + + w0 = F_TAU * f0norm; + sin_w0 = sinf(w0); + cos_w0 = cosf(w0); + alpha = sin_w0/2.0f * rcpQ; + + /* Calculate filter coefficients depending on filter type */ + switch(type) + { + case ALfilterType_HighShelf: + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case ALfilterType_LowShelf: + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; + break; + case ALfilterType_Peaking: + gain = sqrtf(gain); + b[0] = 1.0f + alpha * gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha * gain; + a[0] = 1.0f + alpha / gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha / gain; + break; + + case ALfilterType_LowPass: + b[0] = (1.0f - cos_w0) / 2.0f; + b[1] = 1.0f - cos_w0; + b[2] = (1.0f - cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case ALfilterType_HighPass: + b[0] = (1.0f + cos_w0) / 2.0f; + b[1] = -(1.0f + cos_w0); + b[2] = (1.0f + cos_w0) / 2.0f; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + case ALfilterType_BandPass: + b[0] = alpha; + b[1] = 0; + b[2] = -alpha; + a[0] = 1.0f + alpha; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha; + break; + } + + filter->a1 = a[1] / a[0]; + filter->a2 = a[2] / a[0]; + filter->b0 = b[0] / a[0]; + filter->b1 = b[1] / a[0]; + filter->b2 = b[2] / a[0]; +} + + +void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) +{ + ALsizei i; + if(LIKELY(numsamples > 1)) + { + ALfloat x0 = filter->x[0]; + ALfloat x1 = filter->x[1]; + ALfloat y0 = filter->y[0]; + ALfloat y1 = filter->y[1]; + + for(i = 0;i < numsamples;i++) + { + dst[i] = filter->b0* src[i] + + filter->b1*x0 + filter->b2*x1 - + filter->a1*y0 - filter->a2*y1; + y1 = y0; y0 = dst[i]; + x1 = x0; x0 = src[i]; + } + + filter->x[0] = x0; + filter->x[1] = x1; + filter->y[0] = y0; + filter->y[1] = y1; + } + else if(numsamples == 1) + { + dst[0] = filter->b0 * src[0] + + filter->b1 * filter->x[0] + + filter->b2 * filter->x[1] - + filter->a1 * filter->y[0] - + filter->a2 * filter->y[1]; + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = dst[0]; + } +} diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 5f913101..e40c2cad 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -93,45 +93,6 @@ const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restric } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) -{ - ALsizei i; - if(LIKELY(numsamples > 1)) - { - ALfloat x0 = filter->x[0]; - ALfloat x1 = filter->x[1]; - ALfloat y0 = filter->y[0]; - ALfloat y1 = filter->y[1]; - - for(i = 0;i < numsamples;i++) - { - dst[i] = filter->b0* src[i] + - filter->b1*x0 + filter->b2*x1 - - filter->a1*y0 - filter->a2*y1; - y1 = y0; y0 = dst[i]; - x1 = x0; x0 = src[i]; - } - - filter->x[0] = x0; - filter->x[1] = x1; - filter->y[0] = y0; - filter->y[1] = y1; - } - else if(numsamples == 1) - { - dst[0] = filter->b0 * src[0] + - filter->b1 * filter->x[0] + - filter->b2 * filter->x[1] - - filter->a1 * filter->y[0] - - filter->a2 * filter->y[1]; - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = dst[0]; - } -} - - static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei IrSize, const ALfloat (*restrict Coeffs)[2], diff --git a/CMakeLists.txt b/CMakeLists.txt index 646a437c..1be64433 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -728,6 +728,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/effects/null.c Alc/effects/pshifter.c Alc/effects/reverb.c + Alc/filters/filter.c Alc/helpers.c Alc/hrtf.c Alc/uhjfilter.c diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 4e506722..2634d5e8 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -1,9 +1,8 @@ #ifndef _AL_FILTER_H_ #define _AL_FILTER_H_ -#include "alMain.h" - -#include "math_defs.h" +#include "AL/alc.h" +#include "AL/al.h" #ifdef __cplusplus extern "C" { @@ -13,118 +12,6 @@ extern "C" { #define HIGHPASSFREQREF (250.0f) -/* 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 - */ -/* Implementation note: For the shelf filters, the specified gain is for the - * reference frequency, which is the centerpoint of the transition band. This - * better matches EFX filter design. To set the gain for the shelf itself, use - * the square root of the desired linear gain (or halve the dB gain). - */ - -typedef enum ALfilterType { - /** EFX-style low-pass filter, specifying a gain and reference frequency. */ - ALfilterType_HighShelf, - /** EFX-style high-pass filter, specifying a gain and reference frequency. */ - ALfilterType_LowShelf, - /** Peaking filter, specifying a gain and reference frequency. */ - ALfilterType_Peaking, - - /** Low-pass cut-off filter, specifying a cut-off frequency. */ - ALfilterType_LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency. */ - ALfilterType_HighPass, - /** Band-pass filter, specifying a center frequency. */ - ALfilterType_BandPass, -} ALfilterType; - -typedef struct ALfilterState { - ALfloat x[2]; /* History of two last input samples */ - ALfloat y[2]; /* History of two last output samples */ - ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ - ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ -} ALfilterState; -/* Currently only a C-based filter process method is implemented. */ -#define ALfilterState_process ALfilterState_processC - -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the - * reference gain and shelf slope parameter. - * \param gain 0 < gain - * \param slope 0 < slope <= 1 - */ -inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) -{ - return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); -} -/** - * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized - * reference frequency and bandwidth. - * \param f0norm 0 < f0norm < 0.5. - * \param bandwidth 0 < bandwidth - */ -inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) -{ - ALfloat w0 = F_TAU * f0norm; - return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); -} - -inline void ALfilterState_clear(ALfilterState *filter) -{ - filter->x[0] = 0.0f; - filter->x[1] = 0.0f; - filter->y[0] = 0.0f; - filter->y[1] = 0.0f; -} - -/** - * Sets up the filter state for the specified filter type and its parameters. - * - * \param filter The filter object to prepare. - * \param type The type of filter for the object to apply. - * \param gain The gain for the reference frequency response. Only used by the - * Shelf and Peaking filter types. - * \param f0norm The normalized reference frequency (ref_freq / sample_rate). - * This is the center point for the Shelf, Peaking, and BandPass - * filter types, or the cutoff frequency for the LowPass and - * HighPass filter types. - * \param rcpQ The reciprocal of the Q coefficient for the filter's transition - * band. Can be generated from calc_rcpQ_from_slope or - * calc_rcpQ_from_bandwidth depending on the available data. - */ -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); - -inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src) -{ - dst->b0 = src->b0; - dst->b1 = src->b1; - dst->b2 = src->b2; - dst->a1 = src->a1; - dst->a2 = src->a2; -} - -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); - -inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples) -{ - if(numsamples >= 2) - { - filter->x[1] = src[numsamples-2]; - filter->x[0] = src[numsamples-1]; - filter->y[1] = src[numsamples-2]; - filter->y[0] = src[numsamples-1]; - } - else if(numsamples == 1) - { - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = src[0]; - } -} - - struct ALfilter; typedef struct ALfilterVtable { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 14262d9b..341b3760 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -12,13 +12,12 @@ #include "alMain.h" #include "alBuffer.h" -#include "alFilter.h" -#include "alAuxEffectSlot.h" #include "hrtf.h" #include "align.h" #include "nfcfilter.h" #include "math_defs.h" +#include "filters/defs.h" #define MAX_PITCH (255) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 08f66d26..7d8a886c 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -30,11 +30,6 @@ extern inline void LockFilterList(ALCdevice *device); extern inline void UnlockFilterList(ALCdevice *device); -extern inline void ALfilterState_clear(ALfilterState *filter); -extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); -extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); -extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); -extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); static ALfilter *AllocFilter(ALCcontext *context); static void FreeFilter(ALCdevice *device, ALfilter *filter); @@ -343,86 +338,6 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va } -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) -{ - ALfloat alpha, sqrtgain_alpha_2; - ALfloat w0, sin_w0, cos_w0; - ALfloat a[3] = { 1.0f, 0.0f, 0.0f }; - ALfloat b[3] = { 1.0f, 0.0f, 0.0f }; - - // Limit gain to -100dB - assert(gain > 0.00001f); - - w0 = F_TAU * f0norm; - sin_w0 = sinf(w0); - cos_w0 = cosf(w0); - alpha = sin_w0/2.0f * rcpQ; - - /* Calculate filter coefficients depending on filter type */ - switch(type) - { - case ALfilterType_HighShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case ALfilterType_LowShelf: - sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; - b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); - b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); - b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); - a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; - a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); - a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; - break; - case ALfilterType_Peaking: - gain = sqrtf(gain); - b[0] = 1.0f + alpha * gain; - b[1] = -2.0f * cos_w0; - b[2] = 1.0f - alpha * gain; - a[0] = 1.0f + alpha / gain; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha / gain; - break; - - case ALfilterType_LowPass: - b[0] = (1.0f - cos_w0) / 2.0f; - b[1] = 1.0f - cos_w0; - b[2] = (1.0f - cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case ALfilterType_HighPass: - b[0] = (1.0f + cos_w0) / 2.0f; - b[1] = -(1.0f + cos_w0); - b[2] = (1.0f + cos_w0) / 2.0f; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - case ALfilterType_BandPass: - b[0] = alpha; - b[1] = 0; - b[2] = -alpha; - a[0] = 1.0f + alpha; - a[1] = -2.0f * cos_w0; - a[2] = 1.0f - alpha; - break; - } - - filter->a1 = a[1] / a[0]; - filter->a2 = a[2] / a[0]; - filter->b0 = b[0] / a[0]; - filter->b1 = b[1] / a[0]; - filter->b2 = b[2] / a[0]; -} - - static void ALlowpass_setParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, ALint UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); } static void ALlowpass_setParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 40b2c494..e3e40166 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -31,6 +31,7 @@ #include "alError.h" #include "alSource.h" #include "alBuffer.h" +#include "alFilter.h" #include "alAuxEffectSlot.h" #include "ringbuffer.h" -- cgit v1.2.3 From 8e976a92f7e23504275fb9d1d5d55df215c7d47d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 07:15:19 -0700 Subject: Move NFC filters to the filter directory --- Alc/filters/nfc.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/nfc.h | 49 ++++++ Alc/nfcfilter.c | 428 ------------------------------------------------- Alc/nfcfilter.h | 51 ------ CMakeLists.txt | 2 +- OpenAL32/Include/alu.h | 2 +- 6 files changed, 479 insertions(+), 481 deletions(-) create mode 100644 Alc/filters/nfc.c create mode 100644 Alc/filters/nfc.h delete mode 100644 Alc/nfcfilter.c delete mode 100644 Alc/nfcfilter.h diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c new file mode 100644 index 00000000..b9006955 --- /dev/null +++ b/Alc/filters/nfc.c @@ -0,0 +1,428 @@ + +#include "config.h" + +#include "nfc.h" + +#include + + +/* Near-field control filters are the basis for handling the near-field effect. + * The near-field effect is a bass-boost present in the directional components + * of a recorded signal, created as a result of the wavefront curvature (itself + * a function of sound distance). Proper reproduction dictates this be + * compensated for using a bass-cut given the playback speaker distance, to + * avoid excessive bass in the playback. + * + * For real-time rendered audio, emulating the near-field effect based on the + * sound source's distance, and subsequently compensating for it at output + * based on the speaker distances, can create a more realistic perception of + * sound distance beyond a simple 1/r attenuation. + * + * These filters do just that. Each one applies a low-shelf filter, created as + * the combination of a bass-boost for a given sound source distance (near- + * field emulation) along with a bass-cut for a given control/speaker distance + * (near-field compensation). + * + * Note that it is necessary to apply a cut along with the boost, since the + * boost alone is unstable in higher-order ambisonics as it causes an infinite + * DC gain (even first-order ambisonics requires there to be no DC offset for + * the boost to work). Consequently, ambisonics requires a control parameter to + * be used to avoid an unstable boost-only filter. NFC-HOA defines this control + * as a reference delay, calculated with: + * + * reference_delay = control_distance / speed_of_sound + * + * This means w0 (for input) or w1 (for output) should be set to: + * + * wN = 1 / (reference_delay * sample_rate) + * + * when dealing with NFC-HOA content. For FOA input content, which does not + * specify a reference_delay variable, w0 should be set to 0 to apply only + * near-field compensation for output. It's important that w1 be a finite, + * positive, non-0 value or else the bass-boost will become unstable again. + * Also, w0 should not be too large compared to w1, to avoid excessively loud + * low frequencies. + */ + +static const float B[4][3] = { + { 0.0f }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ +}; + +static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) +{ + float b_00, g_0; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[1] = (2.0f * b_00) / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[1+1] = (2.0f * b_00) / g_0; +} + +static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) +{ + float b_00, g_0; + float r; + + r = 0.5f * w0; + b_00 = B[1][0] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] = nfc->g * g_0; + nfc->coeffs[1] = (2.0f * b_00) / g_0; +} + + +static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2+2] = (4.0f * b_11) / g_1; +} + +static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) +{ + float b_10, b_11, g_1; + float r; + + r = 0.5f * w0; + b_10 = B[2][0] * r; + b_11 = B[2][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] = nfc->g * g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; +} + + +static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* Calculate bass-boost coefficients. */ + r = 0.5f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[2+1] = (2.0f * b_00) / g_0; + + /* Calculate bass-cut coefficients. */ + r = 0.5f * w1; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[3+2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0; +} + +static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) +{ + float b_10, b_11, g_1; + float b_00, g_0; + float r; + + r = 0.5f * w0; + b_10 = B[3][0] * r; + b_11 = B[3][1] * r * r; + g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] = nfc->g * g_1; + nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[2] = (4.0f * b_11) / g_1; + + b_00 = B[3][2] * r; + g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[2+1] = (2.0f * b_00) / g_0; +} + + +void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) +{ + memset(nfc, 0, sizeof(*nfc)); + NfcFilterCreate1(&nfc->first, w0, w1); + NfcFilterCreate2(&nfc->second, w0, w1); + NfcFilterCreate3(&nfc->third, w0, w1); +} + +void NfcFilterAdjust(NfcFilter *nfc, const float w0) +{ + NfcFilterAdjust1(&nfc->first, w0); + NfcFilterAdjust2(&nfc->second, w0); + NfcFilterAdjust3(&nfc->third, w0); +} + + +void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->first.coeffs[0]; + const float a0 = nfc->first.coeffs[1]; + const float a1 = nfc->first.coeffs[2]; + float z1 = nfc->first.history[0]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a1*z1); + out = y + (a0*z1); + z1 += y; + + dst[i] = out; + } + nfc->first.history[0] = z1; +} + +void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->second.coeffs[0]; + const float a00 = nfc->second.coeffs[1]; + const float a01 = nfc->second.coeffs[2]; + const float a10 = nfc->second.coeffs[3]; + const float a11 = nfc->second.coeffs[4]; + float z1 = nfc->second.history[0]; + float z2 = nfc->second.history[1]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a10*z1) - (a11*z2); + out = y + (a00*z1) + (a01*z2); + z2 += z1; + z1 += y; + + dst[i] = out; + } + nfc->second.history[0] = z1; + nfc->second.history[1] = z2; +} + +void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +{ + const float b0 = nfc->third.coeffs[0]; + const float a00 = nfc->third.coeffs[1]; + const float a01 = nfc->third.coeffs[2]; + const float a02 = nfc->third.coeffs[3]; + const float a10 = nfc->third.coeffs[4]; + const float a11 = nfc->third.coeffs[5]; + const float a12 = nfc->third.coeffs[6]; + float z1 = nfc->third.history[0]; + float z2 = nfc->third.history[1]; + float z3 = nfc->third.history[2]; + int i; + + for(i = 0;i < count;i++) + { + float out = src[i] * b0; + float y; + + y = out - (a10*z1) - (a11*z2); + out = y + (a00*z1) + (a01*z2); + z2 += z1; + z1 += y; + + y = out - (a12*z3); + out = y + (a02*z3); + z3 += y; + + dst[i] = out; + } + nfc->third.history[0] = z1; + nfc->third.history[1] = z2; + nfc->third.history[2] = z3; +} + +#if 0 /* Original methods the above are derived from. */ +static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) +{ + static const float B[4][5] = { + { }, + { 1.0f }, + { 3.0f, 3.0f }, + { 3.6778f, 6.4595f, 2.3222f }, + { 4.2076f, 11.4877f, 5.7924f, 9.1401f } + }; + float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); + float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); + ALsizei i; + float r; + + nfc->g = 1.0f; + nfc->coeffs[0] = 1.0f; + + /* NOTE: Slight adjustment from the literature to raise the center + * frequency a bit (0.5 -> 1.0). + */ + r = 1.0f * w0; + for(i = 0; i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->b[i] = b_10; + nfc->b[i + 1] = b_11; + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->b[i] = b_00; + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } + + r = 1.0f * w1; + for(i = 0;i < (order-1);i += 2) + { + float b_10 = B[order][i ] * r; + float b_11 = B[order][i+1] * r * r; + float g_1 = 1.0f + b_10 + b_11; + + nfc->g /= g_1; + nfc->coeffs[0] /= g_1; + nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; + } + if(i < order) + { + float b_00 = B[order][i] * r; + float g_0 = 1.0f + b_00; + + nfc->g /= g_0; + nfc->coeffs[0] /= g_0; + nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; + } + + for(i = 0; i < MAX_AMBI_ORDER; i++) + nfc->history[i] = 0.0f; +} + +static void NfcFilterAdjust(NfcFilter *nfc, const float distance) +{ + int i; + + nfc->coeffs[0] = nfc->g; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float b_10 = nfc->b[i] / distance; + float b_11 = nfc->b[i+1] / (distance * distance); + float g_1 = 1.0f + b_10 + b_11; + + nfc->coeffs[0] *= g_1; + nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; + nfc->coeffs[i+2] = (4.0f * b_11) / g_1; + } + if(i < nfc->order) + { + float b_00 = nfc->b[i] / distance; + float g_0 = 1.0f + b_00; + + nfc->coeffs[0] *= g_0; + nfc->coeffs[i+1] = (2.0f * b_00) / g_0; + } +} + +static float NfcFilterUpdate(const float in, NfcFilter *nfc) +{ + int i; + float out = in * nfc->coeffs[0]; + + for(i = 0;i < (nfc->order-1);i += 2) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - + (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; + out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); + + nfc->history[i+1] += nfc->history[i]; + nfc->history[i] += y; + } + if(i < nfc->order) + { + float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; + + out = y + (nfc->coeffs[i+1] * nfc->history[i]); + nfc->history[i] += y; + } + + return out; +} +#endif diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h new file mode 100644 index 00000000..f0987d97 --- /dev/null +++ b/Alc/filters/nfc.h @@ -0,0 +1,49 @@ +#ifndef FILTER_NFC_H +#define FILTER_NFC_H + +struct NfcFilter1 { + float g; + float coeffs[1*2 + 1]; + float history[1]; +}; +struct NfcFilter2 { + float g; + float coeffs[2*2 + 1]; + float history[2]; +}; +struct NfcFilter3 { + float g; + float coeffs[3*2 + 1]; + float history[3]; +}; + +typedef struct NfcFilter { + struct NfcFilter1 first; + struct NfcFilter2 second; + struct NfcFilter3 third; +} NfcFilter; + + +/* NOTE: + * w0 = speed_of_sound / (source_distance * sample_rate); + * w1 = speed_of_sound / (control_distance * sample_rate); + * + * Generally speaking, the control distance should be approximately the average + * speaker distance, or based on the reference delay if outputing NFC-HOA. It + * must not be negative, 0, or infinite. The source distance should not be too + * small relative to the control distance. + */ + +void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); +void NfcFilterAdjust(NfcFilter *nfc, const float w0); + +/* Near-field control filter for first-order ambisonic channels (1-3). */ +void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +/* Near-field control filter for second-order ambisonic channels (4-8). */ +void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +/* Near-field control filter for third-order ambisonic channels (9-15). */ +void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); + +#endif /* FILTER_NFC_H */ diff --git a/Alc/nfcfilter.c b/Alc/nfcfilter.c deleted file mode 100644 index 57a3e28f..00000000 --- a/Alc/nfcfilter.c +++ /dev/null @@ -1,428 +0,0 @@ - -#include "config.h" - -#include "nfcfilter.h" - -#include "alu.h" - - -/* Near-field control filters are the basis for handling the near-field effect. - * The near-field effect is a bass-boost present in the directional components - * of a recorded signal, created as a result of the wavefront curvature (itself - * a function of sound distance). Proper reproduction dictates this be - * compensated for using a bass-cut given the playback speaker distance, to - * avoid excessive bass in the playback. - * - * For real-time rendered audio, emulating the near-field effect based on the - * sound source's distance, and subsequently compensating for it at output - * based on the speaker distances, can create a more realistic perception of - * sound distance beyond a simple 1/r attenuation. - * - * These filters do just that. Each one applies a low-shelf filter, created as - * the combination of a bass-boost for a given sound source distance (near- - * field emulation) along with a bass-cut for a given control/speaker distance - * (near-field compensation). - * - * Note that it is necessary to apply a cut along with the boost, since the - * boost alone is unstable in higher-order ambisonics as it causes an infinite - * DC gain (even first-order ambisonics requires there to be no DC offset for - * the boost to work). Consequently, ambisonics requires a control parameter to - * be used to avoid an unstable boost-only filter. NFC-HOA defines this control - * as a reference delay, calculated with: - * - * reference_delay = control_distance / speed_of_sound - * - * This means w0 (for input) or w1 (for output) should be set to: - * - * wN = 1 / (reference_delay * sample_rate) - * - * when dealing with NFC-HOA content. For FOA input content, which does not - * specify a reference_delay variable, w0 should be set to 0 to apply only - * near-field compensation for output. It's important that w1 be a finite, - * positive, non-0 value or else the bass-boost will become unstable again. - * Also, w0 should not be too large compared to w1, to avoid excessively loud - * low frequencies. - */ - -static const float B[4][3] = { - { 0.0f }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/ -}; - -static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1) -{ - float b_00, g_0; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[1] = (2.0f * b_00) / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[1+1] = (2.0f * b_00) / g_0; -} - -static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) -{ - float b_00, g_0; - float r; - - r = 0.5f * w0; - b_00 = B[1][0] * r; - g_0 = 1.0f + b_00; - - nfc->coeffs[0] = nfc->g * g_0; - nfc->coeffs[1] = (2.0f * b_00) / g_0; -} - - -static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1) -{ - float b_10, b_11, g_1; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] *= g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2+2] = (4.0f * b_11) / g_1; -} - -static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) -{ - float b_10, b_11, g_1; - float r; - - r = 0.5f * w0; - b_10 = B[2][0] * r; - b_11 = B[2][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] = nfc->g * g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; -} - - -static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1) -{ - float b_10, b_11, g_1; - float b_00, g_0; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* Calculate bass-boost coefficients. */ - r = 0.5f * w0; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] *= g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[2+1] = (2.0f * b_00) / g_0; - - /* Calculate bass-cut coefficients. */ - r = 0.5f * w1; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[3+2] = (4.0f * b_11) / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0; -} - -static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) -{ - float b_10, b_11, g_1; - float b_00, g_0; - float r; - - r = 0.5f * w0; - b_10 = B[3][0] * r; - b_11 = B[3][1] * r * r; - g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] = nfc->g * g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; - - b_00 = B[3][2] * r; - g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[2+1] = (2.0f * b_00) / g_0; -} - - -void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1) -{ - memset(nfc, 0, sizeof(*nfc)); - NfcFilterCreate1(&nfc->first, w0, w1); - NfcFilterCreate2(&nfc->second, w0, w1); - NfcFilterCreate3(&nfc->third, w0, w1); -} - -void NfcFilterAdjust(NfcFilter *nfc, const float w0) -{ - NfcFilterAdjust1(&nfc->first, w0); - NfcFilterAdjust2(&nfc->second, w0); - NfcFilterAdjust3(&nfc->third, w0); -} - - -void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) -{ - const float b0 = nfc->first.coeffs[0]; - const float a0 = nfc->first.coeffs[1]; - const float a1 = nfc->first.coeffs[2]; - float z1 = nfc->first.history[0]; - int i; - - for(i = 0;i < count;i++) - { - float out = src[i] * b0; - float y; - - y = out - (a1*z1); - out = y + (a0*z1); - z1 += y; - - dst[i] = out; - } - nfc->first.history[0] = z1; -} - -void NfcFilterUpdate2(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) -{ - const float b0 = nfc->second.coeffs[0]; - const float a00 = nfc->second.coeffs[1]; - const float a01 = nfc->second.coeffs[2]; - const float a10 = nfc->second.coeffs[3]; - const float a11 = nfc->second.coeffs[4]; - float z1 = nfc->second.history[0]; - float z2 = nfc->second.history[1]; - int i; - - for(i = 0;i < count;i++) - { - float out = src[i] * b0; - float y; - - y = out - (a10*z1) - (a11*z2); - out = y + (a00*z1) + (a01*z2); - z2 += z1; - z1 += y; - - dst[i] = out; - } - nfc->second.history[0] = z1; - nfc->second.history[1] = z2; -} - -void NfcFilterUpdate3(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count) -{ - const float b0 = nfc->third.coeffs[0]; - const float a00 = nfc->third.coeffs[1]; - const float a01 = nfc->third.coeffs[2]; - const float a02 = nfc->third.coeffs[3]; - const float a10 = nfc->third.coeffs[4]; - const float a11 = nfc->third.coeffs[5]; - const float a12 = nfc->third.coeffs[6]; - float z1 = nfc->third.history[0]; - float z2 = nfc->third.history[1]; - float z3 = nfc->third.history[2]; - int i; - - for(i = 0;i < count;i++) - { - float out = src[i] * b0; - float y; - - y = out - (a10*z1) - (a11*z2); - out = y + (a00*z1) + (a01*z2); - z2 += z1; - z1 += y; - - y = out - (a12*z3); - out = y + (a02*z3); - z3 += y; - - dst[i] = out; - } - nfc->third.history[0] = z1; - nfc->third.history[1] = z2; - nfc->third.history[2] = z3; -} - -#if 0 /* Original methods the above are derived from. */ -static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate) -{ - static const float B[4][5] = { - { }, - { 1.0f }, - { 3.0f, 3.0f }, - { 3.6778f, 6.4595f, 2.3222f }, - { 4.2076f, 11.4877f, 5.7924f, 9.1401f } - }; - float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate); - float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate); - ALsizei i; - float r; - - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; - - /* NOTE: Slight adjustment from the literature to raise the center - * frequency a bit (0.5 -> 1.0). - */ - r = 1.0f * w0; - for(i = 0; i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->b[i] = b_10; - nfc->b[i + 1] = b_11; - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->b[i] = b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } - - r = 1.0f * w1; - for(i = 0;i < (order-1);i += 2) - { - float b_10 = B[order][i ] * r; - float b_11 = B[order][i+1] * r * r; - float g_1 = 1.0f + b_10 + b_11; - - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1; - } - if(i < order) - { - float b_00 = B[order][i] * r; - float g_0 = 1.0f + b_00; - - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0; - } - - for(i = 0; i < MAX_AMBI_ORDER; i++) - nfc->history[i] = 0.0f; -} - -static void NfcFilterAdjust(NfcFilter *nfc, const float distance) -{ - int i; - - nfc->coeffs[0] = nfc->g; - - for(i = 0;i < (nfc->order-1);i += 2) - { - float b_10 = nfc->b[i] / distance; - float b_11 = nfc->b[i+1] / (distance * distance); - float g_1 = 1.0f + b_10 + b_11; - - nfc->coeffs[0] *= g_1; - nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[i+2] = (4.0f * b_11) / g_1; - } - if(i < nfc->order) - { - float b_00 = nfc->b[i] / distance; - float g_0 = 1.0f + b_00; - - nfc->coeffs[0] *= g_0; - nfc->coeffs[i+1] = (2.0f * b_00) / g_0; - } -} - -static float NfcFilterUpdate(const float in, NfcFilter *nfc) -{ - int i; - float out = in * nfc->coeffs[0]; - - for(i = 0;i < (nfc->order-1);i += 2) - { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) - - (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f; - out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]); - - nfc->history[i+1] += nfc->history[i]; - nfc->history[i] += y; - } - if(i < nfc->order) - { - float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f; - - out = y + (nfc->coeffs[i+1] * nfc->history[i]); - nfc->history[i] += y; - } - - return out; -} -#endif diff --git a/Alc/nfcfilter.h b/Alc/nfcfilter.h deleted file mode 100644 index 0bf9a5c4..00000000 --- a/Alc/nfcfilter.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef NFCFILTER_H -#define NFCFILTER_H - -#include "alMain.h" - -struct NfcFilter1 { - float g; - float coeffs[1*2 + 1]; - float history[1]; -}; -struct NfcFilter2 { - float g; - float coeffs[2*2 + 1]; - float history[2]; -}; -struct NfcFilter3 { - float g; - float coeffs[3*2 + 1]; - float history[3]; -}; - -typedef struct NfcFilter { - struct NfcFilter1 first; - struct NfcFilter2 second; - struct NfcFilter3 third; -} NfcFilter; - - -/* NOTE: - * w0 = speed_of_sound / (source_distance * sample_rate); - * w1 = speed_of_sound / (control_distance * sample_rate); - * - * Generally speaking, the control distance should be approximately the average - * speaker distance, or based on the reference delay if outputing NFC-HOA. It - * must not be negative, 0, or infinite. The source distance should not be too - * small relative to the control distance. - */ - -void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); -void NfcFilterAdjust(NfcFilter *nfc, const float w0); - -/* Near-field control filter for first-order ambisonic channels (1-3). */ -void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); - -/* Near-field control filter for second-order ambisonic channels (4-8). */ -void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); - -/* Near-field control filter for third-order ambisonic channels (9-15). */ -void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); - -#endif /* NFCFILTER_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1be64433..883c43d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -729,12 +729,12 @@ SET(ALC_OBJS Alc/ALc.c Alc/effects/pshifter.c Alc/effects/reverb.c Alc/filters/filter.c + Alc/filters/nfc.c Alc/helpers.c Alc/hrtf.c Alc/uhjfilter.c Alc/ambdec.c Alc/bformatdec.c - Alc/nfcfilter.c Alc/panning.c Alc/mixvoice.c Alc/mixer/mixer_c.c diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 341b3760..6113c256 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -15,9 +15,9 @@ #include "hrtf.h" #include "align.h" -#include "nfcfilter.h" #include "math_defs.h" #include "filters/defs.h" +#include "filters/nfc.h" #define MAX_PITCH (255) -- cgit v1.2.3 From bc3a96308e04f5a6e1df7cf5c0f9e9c86931d4ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 08:05:48 -0700 Subject: Use appropriately-sized buffers for the pitch shifter --- Alc/effects/pshifter.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 6542be56..4017dc0a 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -30,9 +30,7 @@ #include "filters/defs.h" -#define MAX_SIZE 2048 - -#define STFT_SIZE (MAX_SIZE>>1) +#define STFT_SIZE 1024 #define STFT_HALF_SIZE (STFT_SIZE>>1) #define OVERSAMP (1<<2) @@ -58,22 +56,22 @@ typedef struct ALpshifterState { DERIVE_FROM_TYPE(ALeffectState); /* Effect parameters */ - ALsizei count; - ALfloat PitchShift; - ALfloat Frequency; + ALsizei count; + ALfloat PitchShift; + ALfloat Frequency; /*Effects buffers*/ - ALfloat InFIFO[MAX_SIZE]; - ALfloat OutFIFO[MAX_SIZE]; - ALfloat LastPhase[(MAX_SIZE>>1) +1]; - ALfloat SumPhase[(MAX_SIZE>>1) +1]; - ALfloat OutputAccum[MAX_SIZE<<1]; - ALfloat window[MAX_SIZE]; + ALfloat InFIFO[STFT_SIZE]; + ALfloat OutFIFO[STFT_STEP]; + ALfloat LastPhase[STFT_HALF_SIZE+1]; + ALfloat SumPhase[STFT_HALF_SIZE+1]; + ALfloat OutputAccum[STFT_SIZE]; + ALfloat window[STFT_SIZE]; - ALcomplex FFTbuffer[MAX_SIZE]; + ALcomplex FFTbuffer[STFT_SIZE]; - ALfrequencyDomain Analysis_buffer[MAX_SIZE]; - ALfrequencyDomain Syntesis_buffer[MAX_SIZE]; + ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1]; + ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1]; alignas(16) ALfloat BufferOut[BUFFERSIZE]; @@ -237,6 +235,7 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice memset(state->SumPhase, 0, sizeof(state->SumPhase)); memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer)); + memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); memset(state->TargetGains, 0, sizeof(state->TargetGains)); @@ -295,9 +294,9 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD FFT(state->FFTbuffer, STFT_SIZE, -1.0f); /* Analyze the obtained data. Since the real FFT is symmetric, only - * STFT_half_size+1 samples are needed. + * STFT_HALF_SIZE+1 samples are needed. */ - for(k = 0;k <= STFT_HALF_SIZE;k++) + for(k = 0;k < STFT_HALF_SIZE+1;k++) { ALphasor component; ALfloat tmp; @@ -327,12 +326,12 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* PROCESSING */ /* pitch shifting */ - memset(state->Syntesis_buffer, 0, STFT_SIZE*sizeof(ALfrequencyDomain)); + memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); - for(k = 0;k <= STFT_HALF_SIZE;k++) + for(k = 0;k < STFT_HALF_SIZE+1;k++) { j = fastf2i((ALfloat)k * state->PitchShift); - if(j > STFT_HALF_SIZE) break; + if(j >= STFT_HALF_SIZE+1) break; state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * @@ -341,7 +340,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* SYNTHESIS */ /* Synthesis the processing data */ - for(k = 0;k <= STFT_HALF_SIZE;k++) + for(k = 0;k < STFT_HALF_SIZE+1;k++) { ALphasor component; ALfloat tmp; @@ -371,9 +370,11 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD (STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ - memmove(state->OutFIFO , state->OutputAccum , STFT_STEP *sizeof(ALfloat)); - memmove(state->OutputAccum, state->OutputAccum+STFT_STEP, STFT_SIZE *sizeof(ALfloat)); - memmove(state->InFIFO , state->InFIFO +STFT_STEP, FIFO_LATENCY*sizeof(ALfloat)); + for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0f; + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; } /* Now, mix the processed sound data to the output. */ -- cgit v1.2.3 From 23fd7451d00697c2be6c16266305c1366fc3b57e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 08:15:50 -0700 Subject: Avoid some memset calls in the pitch shifter process loop --- Alc/effects/pshifter.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 4017dc0a..2110141c 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -326,14 +326,18 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* PROCESSING */ /* pitch shifting */ - memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer)); + for(k = 0;k < STFT_HALF_SIZE+1;k++) + { + state->Syntesis_buffer[k].Amplitude = 0.0f; + state->Syntesis_buffer[k].Frequency = 0.0f; + } for(k = 0;k < STFT_HALF_SIZE+1;k++) { j = fastf2i((ALfloat)k * state->PitchShift); if(j >= STFT_HALF_SIZE+1) break; - state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; + state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; state->Syntesis_buffer[j].Frequency = state->Analysis_buffer[k].Frequency * state->PitchShift; } @@ -357,9 +361,12 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/ state->FFTbuffer[k] = polar2rect(component); } - /* zero negative frequencies for recontruct a real signal */ - memset(&state->FFTbuffer[STFT_HALF_SIZE+1], 0, (STFT_HALF_SIZE-1)*sizeof(ALcomplex)); + for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++) + { + state->FFTbuffer[k].Real = 0.0f; + state->FFTbuffer[k].Imag = 0.0f; + } /* Apply iFFT to buffer data */ FFT(state->FFTbuffer, STFT_SIZE, 1.0f); -- cgit v1.2.3 From eeff730034de1f637e82c4391eb945337dc8a5ce Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 08:30:09 -0700 Subject: Hold some immediate values on the stack --- Alc/effects/pshifter.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 2110141c..ee6ca806 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -58,7 +58,7 @@ typedef struct ALpshifterState { /* Effect parameters */ ALsizei count; ALfloat PitchShift; - ALfloat Frequency; + ALfloat FreqBin; /*Effects buffers*/ ALfloat InFIFO[STFT_SIZE]; @@ -226,7 +226,7 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; state->PitchShift = 1.0f; - state->Frequency = (ALfloat)device->Frequency; + state->FreqBin = device->Frequency / (ALfloat)STFT_SIZE; memset(state->InFIFO, 0, sizeof(state->InFIFO)); memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); @@ -263,24 +263,24 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD */ static const ALfloat expected = F_TAU / (ALfloat)OVERSAMP; - const ALfloat freq_bin = state->Frequency / (ALfloat)STFT_SIZE; + const ALfloat freq_bin = state->FreqBin; ALfloat *restrict bufferOut = state->BufferOut; + ALsizei count = state->count; ALsizei i, j, k; for(i = 0;i < SamplesToDo;) { do { /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - bufferOut[i] = state->OutFIFO[state->count - FIFO_LATENCY]; + state->InFIFO[count] = SamplesIn[0][i]; + bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY]; - state->count++; - } while(++i < SamplesToDo && state->count < STFT_SIZE); + count++; + } while(++i < SamplesToDo && count < STFT_SIZE); /* Check whether FIFO buffer is filled */ - if(state->count < STFT_SIZE) break; - - state->count = FIFO_LATENCY; + if(count < STFT_SIZE) break; + count = FIFO_LATENCY; /* Real signal windowing and store in FFTbuffer */ for(k = 0;k < STFT_SIZE;k++) @@ -308,7 +308,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD tmp = (component.Phase - state->LastPhase[k]) - (ALfloat)k*expected; /* Map delta phase into +/- Pi interval */ - tmp -= F_PI * (ALfloat)(fastf2i(tmp/F_PI) + (fastf2i(tmp/F_PI)&1)); + j = fastf2i(tmp / F_PI); + tmp -= F_PI * (ALfloat)(j + (j&1)); /* Get deviation from bin frequency from the +/- Pi interval */ tmp /= expected; @@ -383,6 +384,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD for(k = 0;k < FIFO_LATENCY;k++) state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; } + state->count = count; /* Now, mix the processed sound data to the output. */ MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, -- cgit v1.2.3 From 1d6622aa2b2408a18c010d40974a3f3f83ced962 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 08:56:48 -0700 Subject: Fix a delta phase offset calculation in the pitch shifter tmp can be negative, and &1 is not the same as %2 in that case. --- Alc/effects/pshifter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index ee6ca806..4597da6b 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -309,7 +309,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Map delta phase into +/- Pi interval */ j = fastf2i(tmp / F_PI); - tmp -= F_PI * (ALfloat)(j + (j&1)); + tmp -= F_PI * (ALfloat)(j + (j%2)); /* Get deviation from bin frequency from the +/- Pi interval */ tmp /= expected; -- cgit v1.2.3 From 7789cc8e32f71201a603809484031fe9988258c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 09:55:15 -0700 Subject: Define the Hanning window globally once for the pitch shifter --- Alc/effects/pshifter.c | 31 ++++++++++++++++++++----------- common/math_defs.h | 4 ++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 4597da6b..33c3e121 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -66,7 +66,6 @@ typedef struct ALpshifterState { ALfloat LastPhase[STFT_HALF_SIZE+1]; ALfloat SumPhase[STFT_HALF_SIZE+1]; ALfloat OutputAccum[STFT_SIZE]; - ALfloat window[STFT_SIZE]; ALcomplex FFTbuffer[STFT_SIZE]; @@ -89,6 +88,23 @@ DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); +/* Define a Hanning window, used to filter the STFT input and output. */ +alignas(16) static ALfloat HanningWindow[STFT_SIZE]; + +static void InitHanningWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hanning window for the desired size, i.e. STFT_SIZE */ + for(i = 0;i < STFT_SIZE>>1;i++) + { + ALdouble val = 1.0 - cos((ALdouble)i / (ALdouble)(STFT_SIZE-1) * (M_PI*2.0)); + HanningWindow[i] = HanningWindow[STFT_SIZE-(i+1)] = (ALfloat)val * 0.5f; + } +} +static alonce_flag HanningInitOnce = AL_ONCE_FLAG_INIT; + + /* Converts ALcomplex to ALphasor*/ static inline ALphasor rect2polar( ALcomplex number ) { @@ -203,17 +219,10 @@ static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALfloat Sign) static void ALpshifterState_Construct(ALpshifterState *state) { - ALsizei i; - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - /* Create lockup table of the Hann window for the desired size, i.e. STFT_size */ - for ( i = 0; i < STFT_SIZE>>1 ; i++ ) - { - state->window[i] = state->window[STFT_SIZE-(i+1)] - = 0.5f * ( 1 - cosf(F_TAU*(ALfloat)i/(ALfloat)(STFT_SIZE-1))); - } + alcall_once(&HanningInitOnce, InitHanningWindow); } static ALvoid ALpshifterState_Destruct(ALpshifterState *state) @@ -285,7 +294,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Real signal windowing and store in FFTbuffer */ for(k = 0;k < STFT_SIZE;k++) { - state->FFTbuffer[k].Real = state->InFIFO[k] * state->window[k]; + state->FFTbuffer[k].Real = state->InFIFO[k] * HanningWindow[k]; state->FFTbuffer[k].Imag = 0.0f; } @@ -374,7 +383,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Windowing and add to output */ for(k = 0;k < STFT_SIZE;k++) - state->OutputAccum[k] += 2.0f * state->window[k]*state->FFTbuffer[k].Real / + state->OutputAccum[k] += 2.0f * HanningWindow[k]*state->FFTbuffer[k].Real / (STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ diff --git a/common/math_defs.h b/common/math_defs.h index 428f5181..8ce93d0a 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -6,6 +6,10 @@ #include #endif +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + #define F_PI (3.14159265358979323846f) #define F_PI_2 (1.57079632679489661923f) #define F_TAU (6.28318530717958647692f) -- cgit v1.2.3 From 6685e0a078a3bf6a42bac8eff9629536e46278eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 11:11:45 -0700 Subject: Don't use an ALsizei for a potentially negative value --- Alc/effects/pshifter.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 33c3e121..42228617 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -309,6 +309,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD { ALphasor component; ALfloat tmp; + ALint qpd; /* Compute amplitude and phase */ component = rect2polar(state->FFTbuffer[k]); @@ -317,8 +318,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD tmp = (component.Phase - state->LastPhase[k]) - (ALfloat)k*expected; /* Map delta phase into +/- Pi interval */ - j = fastf2i(tmp / F_PI); - tmp -= F_PI * (ALfloat)(j + (j%2)); + qpd = fastf2i(tmp / F_PI); + tmp -= F_PI * (ALfloat)(qpd + (qpd%2)); /* Get deviation from bin frequency from the +/- Pi interval */ tmp /= expected; -- cgit v1.2.3 From 63c35248bed5d3718c492e78933a1c5f8d187a16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 22 Mar 2018 11:32:23 -0700 Subject: Some formatting cleanup --- Alc/effects/pshifter.c | 135 +++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 42228617..7fe7246d 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -58,7 +58,7 @@ typedef struct ALpshifterState { /* Effect parameters */ ALsizei count; ALfloat PitchShift; - ALfloat FreqBin; + ALfloat FreqPerBin; /*Effects buffers*/ ALfloat InFIFO[STFT_SIZE]; @@ -105,114 +105,115 @@ static void InitHanningWindow(void) static alonce_flag HanningInitOnce = AL_ONCE_FLAG_INIT; -/* Converts ALcomplex to ALphasor*/ -static inline ALphasor rect2polar( ALcomplex number ) +/* Converts ALcomplex to ALphasor */ +static inline ALphasor rect2polar(ALcomplex number) { ALphasor polar; - polar.Amplitude = sqrtf ( number.Real*number.Real + number.Imag*number.Imag ); - polar.Phase = atan2f( number.Imag , number.Real ); + polar.Amplitude = sqrtf(number.Real*number.Real + number.Imag*number.Imag); + polar.Phase = atan2f(number.Imag , number.Real); return polar; } -/* Converts ALphasor to ALcomplex*/ -static inline ALcomplex polar2rect( ALphasor number ) +/* Converts ALphasor to ALcomplex */ +static inline ALcomplex polar2rect(ALphasor number) { ALcomplex cartesian; - cartesian.Real = number.Amplitude * cosf( number.Phase ); - cartesian.Imag = number.Amplitude * sinf( number.Phase ); + cartesian.Real = number.Amplitude * cosf(number.Phase); + cartesian.Imag = number.Amplitude * sinf(number.Phase); return cartesian; } -/* Addition of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_add( ALcomplex a, ALcomplex b ) +/* Addition of two complex numbers (ALcomplex format) */ +static inline ALcomplex complex_add(ALcomplex a, ALcomplex b) { ALcomplex result; - result.Real = ( a.Real + b.Real ); - result.Imag = ( a.Imag + b.Imag ); + result.Real = a.Real + b.Real; + result.Imag = a.Imag + b.Imag; return result; } -/* Subtraction of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_sub( ALcomplex a, ALcomplex b ) +/* Subtraction of two complex numbers (ALcomplex format) */ +static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) { ALcomplex result; - result.Real = ( a.Real - b.Real ); - result.Imag = ( a.Imag - b.Imag ); + result.Real = a.Real - b.Real; + result.Imag = a.Imag - b.Imag; return result; } -/* Multiplication of two complex numbers (ALcomplex format)*/ -static inline ALcomplex complex_mult( ALcomplex a, ALcomplex b ) +/* Multiplication of two complex numbers (ALcomplex format) */ +static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) { ALcomplex result; - result.Real = ( a.Real * b.Real - a.Imag * b.Imag ); - result.Imag = ( a.Imag * b.Real + a.Real * b.Imag ); + result.Real = a.Real*b.Real - a.Imag*b.Imag; + result.Imag = a.Imag*b.Real + a.Real*b.Imag; return result; } -/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is FFT and 1 is - iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the Discrete Fourier Transform (DFT) - of the time domain data stored in FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of - complex numbers (ALcomplex), FFTSize MUST BE power of two.*/ +/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is + * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the + * Discrete Fourier Transform (DFT) of the time domain data stored in + * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers + * (ALcomplex), FFTSize MUST BE power of two. + */ static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALfloat Sign) { - ALfloat arg; ALsizei i, j, k, mask, step, step2; ALcomplex temp, u, w; + ALfloat arg; - /*bit-reversal permutation applied to a sequence of FFTSize items*/ - for (i = 1; i < FFTSize-1; i++ ) + /* Bit-reversal permutation applied to a sequence of FFTSize items */ + for(i = 1;i < FFTSize-1;i++) { - for ( mask = 0x1, j = 0; mask < FFTSize; mask <<= 1 ) - { - if ( ( i & mask ) != 0 ) j++; - - j <<= 1; - } - - j >>= 1; + for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1) + { + if((i&mask) != 0) + j++; + j <<= 1; + } + j >>= 1; - if ( i < j ) - { - temp = FFTBuffer[i]; - FFTBuffer[i] = FFTBuffer[j]; - FFTBuffer[j] = temp; - } + if(i < j) + { + temp = FFTBuffer[i]; + FFTBuffer[i] = FFTBuffer[j]; + FFTBuffer[j] = temp; + } } /* Iterative form of Danielson–Lanczos lemma */ - for ( i = 1, step = 2; i < FFTSize; i<<=1, step <<= 1 ) + for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) { - step2 = step >> 1; - arg = F_PI / step2; - - w.Real = cosf( arg ); - w.Imag = sinf( arg ) * Sign; - - u.Real = 1.0f; - u.Imag = 0.0f; - - for ( j = 0; j < step2; j++ ) - { - for ( k = j; k < FFTSize; k += step ) - { - temp = complex_mult( FFTBuffer[k+step2], u ); - FFTBuffer[k+step2] = complex_sub( FFTBuffer[k], temp ); - FFTBuffer[k] = complex_add( FFTBuffer[k], temp ); - } - - u = complex_mult(u,w); - } + step2 = step >> 1; + arg = F_PI / step2; + + w.Real = cosf(arg); + w.Imag = sinf(arg) * Sign; + + u.Real = 1.0f; + u.Imag = 0.0f; + + for(j = 0;j < step2;j++) + { + for(k = j;k < FFTSize;k+=step) + { + temp = complex_mult(FFTBuffer[k+step2], u); + FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp); + FFTBuffer[k] = complex_add(FFTBuffer[k], temp); + } + + u = complex_mult(u, w); + } } } @@ -235,7 +236,7 @@ static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; state->PitchShift = 1.0f; - state->FreqBin = device->Frequency / (ALfloat)STFT_SIZE; + state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; memset(state->InFIFO, 0, sizeof(state->InFIFO)); memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); @@ -272,7 +273,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD */ static const ALfloat expected = F_TAU / (ALfloat)OVERSAMP; - const ALfloat freq_bin = state->FreqBin; + const ALfloat freq_per_bin = state->FreqPerBin; ALfloat *restrict bufferOut = state->BufferOut; ALsizei count = state->count; ALsizei i, j, k; @@ -329,7 +330,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD * amplitude and true frequency in analysis buffer. */ state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; - state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_bin; + state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_per_bin; /* Store actual phase[k] for the calculations in the next frame*/ state->LastPhase[k] = component.Phase; @@ -361,7 +362,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD ALfloat tmp; /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency/freq_bin - (ALfloat)k; + tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - (ALfloat)k; /* Calculate actual delta phase and accumulate it to get bin phase */ state->SumPhase[k] += ((ALfloat)k + tmp) * expected; -- cgit v1.2.3 From 63c9d95b845c0554b59eb7edf6bb05e5650633ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Mar 2018 11:39:07 -0700 Subject: Combine multiple allocations into one --- Alc/backends/coreaudio.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index b2545c47..d6d32cc8 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -53,36 +53,25 @@ typedef struct { static const ALCchar ca_device[] = "CoreAudio Default"; -static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) +static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) { AudioBufferList *list; - list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer)); + list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize); if(list) { list->mNumberBuffers = 1; list->mBuffers[0].mNumberChannels = channelCount; list->mBuffers[0].mDataByteSize = byteSize; - list->mBuffers[0].mData = malloc(byteSize); - if(list->mBuffers[0].mData == NULL) - { - free(list); - list = NULL; - } + list->mBuffers[0].mData = &list->mBuffers[1]; } return list; } -static void destroy_buffer_list(AudioBufferList* list) +static void destroy_buffer_list(AudioBufferList *list) { - if(list) - { - UInt32 i; - for(i = 0;i < list->mNumberBuffers;i++) - free(list->mBuffers[i].mData); - free(list); - } + free(list); } -- cgit v1.2.3 From e37634e908c7563e6281997d50800a2f9633d8d2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Mar 2018 11:58:11 -0700 Subject: Remove an unused struct and move some functions to where they're used --- Alc/backends/coreaudio.c | 62 +++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index d6d32cc8..eeb19dab 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -36,45 +36,9 @@ #include "backends/base.h" -typedef struct { - AudioUnit audioUnit; - - ALuint frameSize; - ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate - AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD - - AudioConverterRef audioConverter; // Sample rate converter if needed - AudioBufferList *bufferList; // Buffer for data coming from the input device - ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling - - ll_ringbuffer_t *ring; -} ca_data; - static const ALCchar ca_device[] = "CoreAudio Default"; -static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) -{ - AudioBufferList *list; - - list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize); - if(list) - { - list->mNumberBuffers = 1; - - list->mBuffers[0].mNumberChannels = channelCount; - list->mBuffers[0].mDataByteSize = byteSize; - list->mBuffers[0].mData = &list->mBuffers[1]; - } - return list; -} - -static void destroy_buffer_list(AudioBufferList *list) -{ - free(list); -} - - typedef struct ALCcoreAudioPlayback { DERIVE_FROM_TYPE(ALCbackend); @@ -125,10 +89,10 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon, ALCcoreAudioPlayback *self = inRefCon; ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALCdevice_Lock(device); + ALCcoreAudioPlayback_lock(self); aluMixData(device, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / self->frameSize); - ALCdevice_Unlock(device); + ALCcoreAudioPlayback_unlock(self); return noErr; } @@ -381,6 +345,28 @@ DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture) DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture); +static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) +{ + AudioBufferList *list; + + list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize); + if(list) + { + list->mNumberBuffers = 1; + + list->mBuffers[0].mNumberChannels = channelCount; + list->mBuffers[0].mDataByteSize = byteSize; + list->mBuffers[0].mData = &list->mBuffers[1]; + } + return list; +} + +static void destroy_buffer_list(AudioBufferList *list) +{ + free(list); +} + + static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); -- cgit v1.2.3 From 6990478369e76a55aa27bebceb45db081fe8144e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 23 Mar 2018 14:52:59 -0700 Subject: Rename ALfilterState/Type to BiquadState/Type --- Alc/ALu.c | 32 ++++++++++++++++---------------- Alc/effects/distortion.c | 16 ++++++++-------- Alc/effects/echo.c | 10 +++++----- Alc/effects/equalizer.c | 28 ++++++++++++++-------------- Alc/effects/modulator.c | 8 ++++---- Alc/effects/reverb.c | 24 ++++++++++++------------ Alc/filters/defs.h | 32 ++++++++++++++++---------------- Alc/filters/filter.c | 22 +++++++++++----------- Alc/mixvoice.c | 18 +++++++++--------- OpenAL32/Include/alu.h | 8 ++++---- 10 files changed, 99 insertions(+), 99 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 63d13838..c70a7162 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1070,20 +1070,20 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const voice->Direct.FilterType = AF_None; if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Direct.Params[0].LowPass, ALfilterType_HighShelf, + BiquadState_setParams( + &voice->Direct.Params[0].LowPass, BiquadType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - ALfilterState_setParams( - &voice->Direct.Params[0].HighPass, ALfilterType_LowShelf, + BiquadState_setParams( + &voice->Direct.Params[0].HighPass, BiquadType_LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - ALfilterState_copyParams(&voice->Direct.Params[c].LowPass, - &voice->Direct.Params[0].LowPass); - ALfilterState_copyParams(&voice->Direct.Params[c].HighPass, - &voice->Direct.Params[0].HighPass); + BiquadState_copyParams(&voice->Direct.Params[c].LowPass, + &voice->Direct.Params[0].LowPass); + BiquadState_copyParams(&voice->Direct.Params[c].HighPass, + &voice->Direct.Params[0].HighPass); } } for(i = 0;i < NumSends;i++) @@ -1096,20 +1096,20 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const voice->Send[i].FilterType = AF_None; if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; - ALfilterState_setParams( - &voice->Send[i].Params[0].LowPass, ALfilterType_HighShelf, + BiquadState_setParams( + &voice->Send[i].Params[0].LowPass, BiquadType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - ALfilterState_setParams( - &voice->Send[i].Params[0].HighPass, ALfilterType_LowShelf, + BiquadState_setParams( + &voice->Send[i].Params[0].HighPass, BiquadType_LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - ALfilterState_copyParams(&voice->Send[i].Params[c].LowPass, - &voice->Send[i].Params[0].LowPass); - ALfilterState_copyParams(&voice->Send[i].Params[c].HighPass, - &voice->Send[i].Params[0].HighPass); + BiquadState_copyParams(&voice->Send[i].Params[c].LowPass, + &voice->Send[i].Params[0].LowPass); + BiquadState_copyParams(&voice->Send[i].Params[c].HighPass, + &voice->Send[i].Params[0].HighPass); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 09289175..aa06a0a3 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -37,8 +37,8 @@ typedef struct ALdistortionState { ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ - ALfilterState lowpass; - ALfilterState bandpass; + BiquadState lowpass; + BiquadState bandpass; ALfloat attenuation; ALfloat edge_coeff; @@ -59,8 +59,8 @@ static void ALdistortionState_Construct(ALdistortionState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALdistortionState, ALeffectState, state); - ALfilterState_clear(&state->lowpass); - ALfilterState_clear(&state->bandpass); + BiquadState_clear(&state->lowpass); + BiquadState_clear(&state->bandpass); } static ALvoid ALdistortionState_Destruct(ALdistortionState *state) @@ -93,14 +93,14 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, + BiquadState_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, + BiquadState_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); @@ -136,7 +136,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample * (which is fortunately first step of distortion). So combine three * operations into the one. */ - ALfilterState_process(&state->lowpass, buffer[1], buffer[0], todo); + BiquadState_process(&state->lowpass, buffer[1], buffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of @@ -155,7 +155,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample } /* Third step, do bandpass filtering of distorted signal. */ - ALfilterState_process(&state->bandpass, buffer[1], buffer[0], todo); + BiquadState_process(&state->bandpass, buffer[1], buffer[0], todo); todo >>= 2; for(k = 0;k < NumChannels;k++) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 10e00f39..7d549768 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -52,7 +52,7 @@ typedef struct ALechoState { ALfloat FeedGain; - ALfilterState Filter; + BiquadState Filter; } ALechoState; static ALvoid ALechoState_Destruct(ALechoState *state); @@ -76,7 +76,7 @@ static void ALechoState_Construct(ALechoState *state) state->Tap[1].delay = 0; state->Offset = 0; - ALfilterState_clear(&state->Filter); + BiquadState_clear(&state->Filter); } static ALvoid ALechoState_Destruct(ALechoState *state) @@ -135,9 +135,9 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, state->FeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, - gainhf, LOWPASSFREQREF/frequency, - calc_rcpQ_from_slope(gainhf, 1.0f)); + BiquadState_setParams(&state->Filter, BiquadType_HighShelf, + gainhf, LOWPASSFREQREF/frequency, + calc_rcpQ_from_slope(gainhf, 1.0f)); /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index a5c65cee..3174511a 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -81,7 +81,7 @@ typedef struct ALequalizerState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ - ALfilterState filter[4]; + BiquadState filter[4]; } Chans[MAX_EFFECT_CHANNELS]; ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; @@ -114,7 +114,7 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevic for(i = 0; i < MAX_EFFECT_CHANNELS;i++) { for(j = 0;j < 4;j++) - ALfilterState_clear(&state->Chans[i].filter[j]); + BiquadState_clear(&state->Chans[i].filter[j]); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; } @@ -140,13 +140,13 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - ALfilterState_setParams(&state->Chans[0].filter[0], ALfilterType_LowShelf, + BiquadState_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - ALfilterState_setParams(&state->Chans[0].filter[1], ALfilterType_Peaking, + BiquadState_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid1Width ) @@ -154,7 +154,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - ALfilterState_setParams(&state->Chans[0].filter[2], ALfilterType_Peaking, + BiquadState_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid2Width ) @@ -162,17 +162,17 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - ALfilterState_setParams(&state->Chans[0].filter[3], ALfilterType_HighShelf, + BiquadState_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - ALfilterState_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); - ALfilterState_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); - ALfilterState_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); - ALfilterState_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); + BiquadState_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); + BiquadState_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); + BiquadState_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); + BiquadState_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); } } @@ -183,10 +183,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - ALfilterState_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - ALfilterState_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); - ALfilterState_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); - ALfilterState_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); + BiquadState_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + BiquadState_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); + BiquadState_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); + BiquadState_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); MixSamples(temps[3], NumChannels, SamplesOut, state->Chans[c].CurrentGains, state->Chans[c].TargetGains, diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index bf8e8fd7..7deb648d 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -43,7 +43,7 @@ typedef struct ALmodulatorState { alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES]; struct { - ALfilterState Filter; + BiquadState Filter; ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; @@ -117,7 +117,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevic ALsizei i, j; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - ALfilterState_clear(&state->Chans[i].Filter); + BiquadState_clear(&state->Chans[i].Filter); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; } @@ -151,7 +151,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->Chans[0].Filter.a1 = -a; state->Chans[0].Filter.a2 = 0.0f; for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - ALfilterState_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); + BiquadState_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; @@ -178,7 +178,7 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - ALfilterState_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); + BiquadState_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); for(i = 0;i < td;i++) temps[1][i] = temps[0][i] * modsamples[i]; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index cd38b492..3c5e5e96 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -291,8 +291,8 @@ typedef struct ALreverbState { /* Master effect filters */ struct { - ALfilterState Lp; - ALfilterState Hp; + BiquadState Lp; + BiquadState Hp; } Filter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ @@ -349,8 +349,8 @@ static void ALreverbState_Construct(ALreverbState *state) for(i = 0;i < NUM_LINES;i++) { - ALfilterState_clear(&state->Filter[i].Lp); - ALfilterState_clear(&state->Filter[i].Hp); + BiquadState_clear(&state->Filter[i].Lp); + BiquadState_clear(&state->Filter[i].Hp); } state->Delay.Mask = 0; @@ -1160,16 +1160,16 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - ALfilterState_setParams(&State->Filter[0].Lp, ALfilterType_HighShelf, - gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); + BiquadState_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, + calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = props->Reverb.LFReference / frequency; gainlf = maxf(props->Reverb.GainLF, 0.001f); - ALfilterState_setParams(&State->Filter[0].Hp, ALfilterType_LowShelf, - gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); + BiquadState_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, + calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { - ALfilterState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); - ALfilterState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); + BiquadState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); + BiquadState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); } /* Update the main effect delay and associated taps. */ @@ -1552,8 +1552,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Band-pass the incoming samples. Use the early output lines for * temp storage. */ - ALfilterState_process(&State->Filter[c].Lp, early[0], afmt[c], todo); - ALfilterState_process(&State->Filter[c].Hp, early[1], early[0], todo); + BiquadState_process(&State->Filter[c].Lp, early[0], afmt[c], todo); + BiquadState_process(&State->Filter[c].Hp, early[1], early[0], todo); /* Feed the initial delay line. */ DelayLineIn(&State->Delay, State->Offset, c, early[1], todo); diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index f4e1e62c..c26427fb 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -14,30 +14,30 @@ * the square root of the desired linear gain (or halve the dB gain). */ -typedef enum ALfilterType { +typedef enum BiquadType { /** EFX-style low-pass filter, specifying a gain and reference frequency. */ - ALfilterType_HighShelf, + BiquadType_HighShelf, /** EFX-style high-pass filter, specifying a gain and reference frequency. */ - ALfilterType_LowShelf, + BiquadType_LowShelf, /** Peaking filter, specifying a gain and reference frequency. */ - ALfilterType_Peaking, + BiquadType_Peaking, /** Low-pass cut-off filter, specifying a cut-off frequency. */ - ALfilterType_LowPass, + BiquadType_LowPass, /** High-pass cut-off filter, specifying a cut-off frequency. */ - ALfilterType_HighPass, + BiquadType_HighPass, /** Band-pass filter, specifying a center frequency. */ - ALfilterType_BandPass, -} ALfilterType; + BiquadType_BandPass, +} BiquadType; -typedef struct ALfilterState { +typedef struct BiquadState { ALfloat x[2]; /* History of two last input samples */ ALfloat y[2]; /* History of two last output samples */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ -} ALfilterState; +} BiquadState; /* Currently only a C-based filter process method is implemented. */ -#define ALfilterState_process ALfilterState_processC +#define BiquadState_process BiquadState_processC /** * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the @@ -61,7 +61,7 @@ inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); } -inline void ALfilterState_clear(ALfilterState *filter) +inline void BiquadState_clear(BiquadState *filter) { filter->x[0] = 0.0f; filter->x[1] = 0.0f; @@ -84,9 +84,9 @@ inline void ALfilterState_clear(ALfilterState *filter) * band. Can be generated from calc_rcpQ_from_slope or * calc_rcpQ_from_bandwidth depending on the available data. */ -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); +void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); -inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src) +inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src) { dst->b0 = src->b0; dst->b1 = src->b1; @@ -95,9 +95,9 @@ inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilter dst->a2 = src->a2; } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); +void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); -inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples) +inline void BiquadState_processPassthru(BiquadState *filter, const ALfloat *restrict src, ALsizei numsamples) { if(numsamples >= 2) { diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index 1cf18f08..4d757be7 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -7,14 +7,14 @@ #include "alMain.h" #include "defs.h" -extern inline void ALfilterState_clear(ALfilterState *filter); -extern inline void ALfilterState_copyParams(ALfilterState *restrict dst, const ALfilterState *restrict src); -extern inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict src, ALsizei numsamples); +extern inline void BiquadState_clear(BiquadState *filter); +extern inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src); +extern inline void BiquadState_processPassthru(BiquadState *filter, const ALfloat *restrict src, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) +void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) { ALfloat alpha, sqrtgain_alpha_2; ALfloat w0, sin_w0, cos_w0; @@ -32,7 +32,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g /* Calculate filter coefficients depending on filter type */ switch(type) { - case ALfilterType_HighShelf: + case BiquadType_HighShelf: sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); @@ -41,7 +41,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; - case ALfilterType_LowShelf: + case BiquadType_LowShelf: sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); @@ -50,7 +50,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; - case ALfilterType_Peaking: + case BiquadType_Peaking: gain = sqrtf(gain); b[0] = 1.0f + alpha * gain; b[1] = -2.0f * cos_w0; @@ -60,7 +60,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g a[2] = 1.0f - alpha / gain; break; - case ALfilterType_LowPass: + case BiquadType_LowPass: b[0] = (1.0f - cos_w0) / 2.0f; b[1] = 1.0f - cos_w0; b[2] = (1.0f - cos_w0) / 2.0f; @@ -68,7 +68,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g a[1] = -2.0f * cos_w0; a[2] = 1.0f - alpha; break; - case ALfilterType_HighPass: + case BiquadType_HighPass: b[0] = (1.0f + cos_w0) / 2.0f; b[1] = -(1.0f + cos_w0); b[2] = (1.0f + cos_w0) / 2.0f; @@ -76,7 +76,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g a[1] = -2.0f * cos_w0; a[2] = 1.0f - alpha; break; - case ALfilterType_BandPass: + case BiquadType_BandPass: b[0] = alpha; b[1] = 0; b[2] = -alpha; @@ -94,7 +94,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g } -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) +void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { ALsizei i; if(LIKELY(numsamples > 1)) diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 0e039115..a9d12821 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -263,7 +263,7 @@ static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint } -static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter, +static const ALfloat *DoFilters(BiquadState *lpfilter, BiquadState *hpfilter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples, enum ActiveFilters type) { @@ -271,17 +271,17 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter switch(type) { case AF_None: - ALfilterState_processPassthru(lpfilter, src, numsamples); - ALfilterState_processPassthru(hpfilter, src, numsamples); + BiquadState_processPassthru(lpfilter, src, numsamples); + BiquadState_processPassthru(hpfilter, src, numsamples); break; case AF_LowPass: - ALfilterState_process(lpfilter, dst, src, numsamples); - ALfilterState_processPassthru(hpfilter, dst, numsamples); + BiquadState_process(lpfilter, dst, src, numsamples); + BiquadState_processPassthru(hpfilter, dst, numsamples); return dst; case AF_HighPass: - ALfilterState_processPassthru(lpfilter, src, numsamples); - ALfilterState_process(hpfilter, dst, src, numsamples); + BiquadState_processPassthru(lpfilter, src, numsamples); + BiquadState_process(hpfilter, dst, src, numsamples); return dst; case AF_BandPass: @@ -290,8 +290,8 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter ALfloat temp[256]; ALsizei todo = mini(256, numsamples-i); - ALfilterState_process(lpfilter, temp, src+i, todo); - ALfilterState_process(hpfilter, dst+i, temp, todo); + BiquadState_process(lpfilter, temp, src+i, todo); + BiquadState_process(hpfilter, dst+i, temp, todo); i += todo; } return dst; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 6113c256..cf1560fc 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -153,8 +153,8 @@ typedef struct MixHrtfParams { typedef struct DirectParams { - ALfilterState LowPass; - ALfilterState HighPass; + BiquadState LowPass; + BiquadState HighPass; NfcFilter NFCtrlFilter; @@ -171,8 +171,8 @@ typedef struct DirectParams { } DirectParams; typedef struct SendParams { - ALfilterState LowPass; - ALfilterState HighPass; + BiquadState LowPass; + BiquadState HighPass; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; -- cgit v1.2.3 From 6d8062a2a78fdcb2f430874f6fbe2ec6e92bd1a9 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sat, 24 Mar 2018 13:43:56 +0100 Subject: EFX: Align some arrays used in intrinsics (#180) --- Alc/effects/chorus.c | 2 +- Alc/effects/echo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index eb0818e3..3710d936 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -227,7 +227,7 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c { const ALsizei todo = mini(256, SamplesToDo-base); ALint moddelays[2][256]; - ALfloat temps[2][256]; + alignas(16) ALfloat temps[2][256]; if(state->waveform == WF_Sinusoid) { diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 7d549768..a3a4e120 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -165,7 +165,7 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const y[1] = state->Filter.y[1]; for(base = 0;base < SamplesToDo;) { - ALfloat temps[2][128]; + alignas(16) ALfloat temps[2][128]; ALsizei td = mini(128, SamplesToDo-base); for(i = 0;i < td;i++) -- cgit v1.2.3 From 413d55aaa547b3f602781ba235a629f3040d3e8d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Mar 2018 07:02:27 -0700 Subject: Fix a couple comments about coordinate handedness --- Alc/effects/reverb.c | 6 +++--- examples/almultireverb.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 3c5e5e96..0d486e63 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1073,9 +1073,9 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) /* Normalize the panning vector according to the N3D scale, which has an * extra sqrt(3) term on the directional components. Converting from OpenAL * to B-Format also requires negating X (ACN 1) and Z (ACN 3). Note however - * that the reverb panning vectors use right-handed coordinates, unlike the - * rest of OpenAL which use left-handed. This is fixed by negating Z, which - * cancels out with the B-Format Z negation. + * that the reverb panning vectors use left-handed coordinates, unlike the + * rest of OpenAL which use right-handed. This is fixed by negating Z, + * which cancels out with the B-Format Z negation. */ mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); if(mag > 1.0f) diff --git a/examples/almultireverb.c b/examples/almultireverb.c index 44398db3..a2587585 100644 --- a/examples/almultireverb.c +++ b/examples/almultireverb.c @@ -281,7 +281,7 @@ static void UpdateListenerAndEffects(float timediff, const ALuint slots[2], cons /* Calculate local_dir, which represents the listener-relative point to the * adjacent zone (should also include orientation). Because EAX Reverb uses - * right-handed coordinates instead of left-handed like the rest of OpenAL, + * left-handed coordinates instead of right-handed like the rest of OpenAL, * negate Z for the local values. */ local_dir[0] = portal_pos[0] - listener_pos[0]; -- cgit v1.2.3 From 3f071a90a4313749b348a7d98284c005e5d87537 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Mar 2018 08:25:58 -0700 Subject: Use proc_pidpath to get the process path on macOS when available --- Alc/helpers.c | 24 ++++++++++++++++++++++++ CMakeLists.txt | 1 + config.h.in | 3 +++ 3 files changed, 28 insertions(+) diff --git a/Alc/helpers.c b/Alc/helpers.c index e5545492..f7adfba0 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -39,6 +39,9 @@ #ifdef HAVE_DIRENT_H #include #endif +#ifdef HAVE_PROC_PIDPATH +#include +#endif #ifdef __FreeBSD__ #include @@ -754,6 +757,27 @@ void GetProcBinary(al_string *path, al_string *fname) sysctl(mib, 3, (void*)pathname, &pathlen, NULL, 0); pathname[pathlen] = 0; } +#endif +#ifdef HAVE_PROC_PIDPATH + if(!pathname) + { + const pid_t pid = getpid(); + char procpath[PROC_PIDPATHINFO_MAXSIZE]; + int ret; + + ret = proc_pidpath(pid, procpath, sizeof(procpath)); + if(ret < 1) + { + WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno)); + free(pathname); + pathname = NULL; + } + else + { + pathlen = strlen(procpath); + pathname = strdup(procpath); + } + } #endif if(!pathname) { diff --git a/CMakeLists.txt b/CMakeLists.txt index 883c43d2..4f41f4c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -507,6 +507,7 @@ CHECK_SYMBOL_EXISTS(sysconf unistd.h HAVE_SYSCONF) CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) +CHECK_SYMBOL_EXISTS(proc_pidpath libproc.h HAVE_PROC_PIDPATH) CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F) diff --git a/config.h.in b/config.h.in index 5768e345..1ff64fe4 100644 --- a/config.h.in +++ b/config.h.in @@ -23,6 +23,9 @@ /* Define if we have the _aligned_malloc function */ #cmakedefine HAVE__ALIGNED_MALLOC +/* Define if we have the proc_pidpath function */ +#cmakedefine HAVE_PROC_PIDPATH + /* Define if we have the getopt function */ #cmakedefine HAVE_GETOPT -- cgit v1.2.3 From 3fc9d3a1bed16b9c601e14f9916896224668e103 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Sat, 24 Mar 2018 16:43:47 +0100 Subject: Also add SDL2's include path --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f41f4c3..df1dfe63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1138,6 +1138,7 @@ IF(SDL2_FOUND) SET(ALC_OBJS ${ALC_OBJS} Alc/backends/sdl2.c) SET(BACKENDS "${BACKENDS} SDL2,") SET(EXTRA_LIBS ${SDL2_LIBRARY} ${EXTRA_LIBS}) + SET(INC_PATHS ${INC_PATHS} ${SDL2_INCLUDE_DIR}) ENDIF() ENDIF() IF(ALSOFT_REQUIRE_SDL2 AND NOT SDL2_FOUND) -- cgit v1.2.3 From e5e3b0501504036ecc9c5a8a6478d7ac55447955 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Mar 2018 08:58:18 -0700 Subject: Fix capture device closing in the CoreAudio backend --- Alc/backends/coreaudio.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index eeb19dab..a8787f7b 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -331,7 +331,6 @@ typedef struct ALCcoreAudioCapture { static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device); static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self); static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name); -static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self); static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset) static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self); static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self); @@ -372,10 +371,32 @@ static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice * ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self); + self->audioUnit = 0; + self->audioConverter = NULL; + self->bufferList = NULL; + self->resampleBuffer = NULL; + self->ring = NULL; } static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self) { + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + free(self->resampleBuffer); + self->resampleBuffer = NULL; + + destroy_buffer_list(self->bufferList); + self->bufferList = NULL; + + if(self->audioConverter) + AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; + + if(self->audioUnit) + AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -651,30 +672,21 @@ error: ll_ringbuffer_free(self->ring); self->ring = NULL; free(self->resampleBuffer); + self->resampleBuffer = NULL; destroy_buffer_list(self->bufferList); + self->bufferList = NULL; if(self->audioConverter) AudioConverterDispose(self->audioConverter); + self->audioConverter = NULL; if(self->audioUnit) AudioComponentInstanceDispose(self->audioUnit); + self->audioUnit = 0; return ALC_INVALID_VALUE; } -static void ALCcoreAudioCapture_close(ALCcoreAudioCapture *self) -{ - ll_ringbuffer_free(self->ring); - self->ring = NULL; - - free(self->resampleBuffer); - - destroy_buffer_list(self->bufferList); - - AudioConverterDispose(self->audioConverter); - AudioComponentInstanceDispose(self->audioUnit); -} - static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self) { OSStatus err = AudioOutputUnitStart(self->audioUnit); -- cgit v1.2.3 From f757fbce4dc4b57cd3c8818957df125c25621c43 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 24 Mar 2018 14:18:29 -0700 Subject: Fix Hanning -> Hann window name --- Alc/effects/pshifter.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 7fe7246d..860a48a5 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -88,21 +88,21 @@ DECLARE_DEFAULT_ALLOCATORS(ALpshifterState) DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); -/* Define a Hanning window, used to filter the STFT input and output. */ -alignas(16) static ALfloat HanningWindow[STFT_SIZE]; +/* Define a Hann window, used to filter the STFT input and output. */ +alignas(16) static ALfloat HannWindow[STFT_SIZE]; -static void InitHanningWindow(void) +static void InitHannWindow(void) { ALsizei i; - /* Create lookup table of the Hanning window for the desired size, i.e. STFT_SIZE */ + /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */ for(i = 0;i < STFT_SIZE>>1;i++) { - ALdouble val = 1.0 - cos((ALdouble)i / (ALdouble)(STFT_SIZE-1) * (M_PI*2.0)); - HanningWindow[i] = HanningWindow[STFT_SIZE-(i+1)] = (ALfloat)val * 0.5f; + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); + HannWindow[i] = HannWindow[STFT_SIZE-(i+1)] = (ALfloat)(val * val); } } -static alonce_flag HanningInitOnce = AL_ONCE_FLAG_INIT; +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; /* Converts ALcomplex to ALphasor */ @@ -223,7 +223,7 @@ static void ALpshifterState_Construct(ALpshifterState *state) ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALpshifterState, ALeffectState, state); - alcall_once(&HanningInitOnce, InitHanningWindow); + alcall_once(&HannInitOnce, InitHannWindow); } static ALvoid ALpshifterState_Destruct(ALpshifterState *state) @@ -295,7 +295,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Real signal windowing and store in FFTbuffer */ for(k = 0;k < STFT_SIZE;k++) { - state->FFTbuffer[k].Real = state->InFIFO[k] * HanningWindow[k]; + state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k]; state->FFTbuffer[k].Imag = 0.0f; } @@ -385,8 +385,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* Windowing and add to output */ for(k = 0;k < STFT_SIZE;k++) - state->OutputAccum[k] += 2.0f * HanningWindow[k]*state->FFTbuffer[k].Real / - (STFT_HALF_SIZE * OVERSAMP); + state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real / + (0.5f * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; -- cgit v1.2.3 From f3672ab26b47763bcb8ef3f910062943319710a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Mar 2018 08:24:53 -0700 Subject: Annotate the B-Format rotation/conversion matrix --- Alc/ALu.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index c70a7162..c670fa5e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -684,9 +684,10 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const /* Local B-Format sources have their XYZ channels rotated according * to the orientation. */ + const ALfloat sqrt_2 = sqrtf(2.0f); + const ALfloat sqrt_3 = sqrtf(3.0f); ALfloat N[3], V[3], U[3]; aluMatrixf matrix; - ALfloat scale; if(Device->AvgSpeakerDist > 0.0f) { @@ -722,13 +723,16 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const aluCrossproduct(N, V, U); aluNormalize(U); - /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). */ - scale = 1.732050808f; + /* Build a rotate + conversion matrix (FuMa -> ACN+N3D). NOTE: This + * matrix is transposed, for the inputs to align on the rows and + * outputs on the columns. + */ aluMatrixfSet(&matrix, - 1.414213562f, 0.0f, 0.0f, 0.0f, - 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, - 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale, - 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale + // ACN0 ACN1 ACN2 ACN3 + sqrt_2, 0.0f, 0.0f, 0.0f, // Ambi W + 0.0f, -N[0]*sqrt_3, N[1]*sqrt_3, -N[2]*sqrt_3, // Ambi X + 0.0f, U[0]*sqrt_3, -U[1]*sqrt_3, U[2]*sqrt_3, // Ambi Y + 0.0f, -V[0]*sqrt_3, V[1]*sqrt_3, -V[2]*sqrt_3 // Ambi Z ); voice->Direct.Buffer = Device->FOAOut.Buffer; -- cgit v1.2.3 From 79eb2ea26e59febe52fb06807074cbb68ef103b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Mar 2018 12:24:43 -0700 Subject: Reduce the gain of front-panned sounds with plain stereo Now front-center sounds are attenuated by roughly -4.5dB instead of -3dB. This will help keep rear-panned sounds from attenuating too much while not making front-panned also attenuate too much. --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index ae8315f3..b49eb2e7 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -383,8 +383,8 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp static const ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 1.19573156e-1f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 1.19573156e-1f } }, + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.77350269e-2f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.77350269e-2f } }, }, QuadCfg[4] = { { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, -- cgit v1.2.3 From 2475d4652c3bd7782ce9a8016ea43dde80bf97f4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 25 Mar 2018 18:02:07 -0700 Subject: Clear mixing target parameters before setting them --- Alc/ALu.c | 93 ++++++++++++++++----------------------------------------------- 1 file changed, 23 insertions(+), 70 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index c670fa5e..f974de46 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -107,6 +107,13 @@ const aluMatrixf IdentityMatrixf = {{ }}; +static void ClearArray(ALfloat f[MAX_OUTPUT_CHANNELS]) +{ + size_t i; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + f[i] = 0.0f; +} + struct ChanMap { enum Channel channel; ALfloat angle; @@ -544,7 +551,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALsizei num_channels = 0; bool isbformat = false; ALfloat downmix_gain = 1.0f; - ALsizei c, i, j; + ALsizei c, i; switch(Buffer->FmtChannels) { @@ -611,6 +618,18 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const break; } + for(c = 0;c < num_channels;c++) + { + memset(&voice->Direct.Params[c].Hrtf.Target, 0, + sizeof(voice->Direct.Params[c].Hrtf.Target)); + ClearArray(voice->Direct.Params[c].Gains.Target); + } + for(i = 0;i < NumSends;i++) + { + for(c = 0;c < num_channels;c++) + ClearArray(voice->Send[i].Params[c].Gains.Target); + } + voice->Flags &= ~(VOICE_HAS_HRTF | VOICE_HAS_NFC); if(isbformat) { @@ -656,12 +675,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ ComputeDryPanGains(&Device->Dry, coeffs, DryGain*1.414213562f, voice->Direct.Params[0].Gains.Target); - for(c = 1;c < num_channels;c++) - { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; - } - for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; @@ -669,14 +682,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i]*1.414213562f, voice->Send[i].Params[0].Gains.Target ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[0].Gains.Target[j] = 0.0f; - for(c = 1;c < num_channels;c++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } } } else @@ -750,12 +755,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target ); } - else - { - for(c = 0;c < num_channels;c++) - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } } } } @@ -770,8 +769,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 0;c < num_channels;c++) { int idx; - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; if((idx=GetChannelIdxByName(&Device->RealOut, chans[c].channel)) != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } @@ -791,9 +788,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } } @@ -825,10 +819,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 1;c < num_channels;c++) { /* Skip LFE */ - if(chans[c].channel == LFE) - memset(&voice->Direct.Params[c].Hrtf.Target, 0, - sizeof(voice->Direct.Params[c].Hrtf.Target)); - else + if(chans[c].channel != LFE) voice->Direct.Params[c].Hrtf.Target = voice->Direct.Params[0].Hrtf.Target; } @@ -844,18 +835,12 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 0;c < num_channels;c++) { /* Skip LFE */ - if(chans[c].channel == LFE) - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - else + if(chans[c].channel != LFE) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, voice->Send[i].Params[c].Gains.Target ); } - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } else @@ -871,13 +856,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const if(chans[c].channel == LFE) { /* Skip LFE */ - memset(&voice->Direct.Params[c].Hrtf.Target, 0, - sizeof(voice->Direct.Params[c].Hrtf.Target)); - for(i = 0;i < NumSends;i++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } continue; } @@ -901,9 +879,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } } @@ -958,8 +933,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const /* Special-case LFE */ if(chans[c].channel == LFE) { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); @@ -980,21 +953,12 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 0;c < num_channels;c++) { /* Skip LFE */ - if(chans[c].channel == LFE) - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - else + if(chans[c].channel != LFE) ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i] * downmix_gain, voice->Send[i].Params[c].Gains.Target ); } - else - for(c = 0;c < num_channels;c++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } } } else @@ -1026,19 +990,11 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const /* Special-case LFE */ if(chans[c].channel == LFE) { - for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) - voice->Direct.Params[c].Gains.Target[j] = 0.0f; if(Device->Dry.Buffer == Device->RealOut.Buffer) { int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } - - for(i = 0;i < NumSends;i++) - { - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; - } continue; } @@ -1057,9 +1013,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, WetGain[i], voice->Send[i].Params[c].Gains.Target ); - else - for(j = 0;j < MAX_EFFECT_CHANNELS;j++) - voice->Send[i].Params[c].Gains.Target[j] = 0.0f; } } } -- cgit v1.2.3 From 964723691ac45943b6d9b62268ec7908cf27b6a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Mar 2018 06:04:11 -0700 Subject: Condense an if check --- Alc/ALu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index f974de46..fef50feb 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -768,9 +768,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const for(c = 0;c < num_channels;c++) { - int idx; - if((idx=GetChannelIdxByName(&Device->RealOut, chans[c].channel)) != -1) - voice->Direct.Params[c].Gains.Target[idx] = DryGain; + int idx = GetChannelIdxByName(&Device->RealOut, chans[c].channel); + if(idx != -1) voice->Direct.Params[c].Gains.Target[idx] = DryGain; } /* Auxiliary sends still use normal channel panning since they mix to -- cgit v1.2.3 From 788f5398b019a9c21e9c82906431c3d8261842cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 26 Mar 2018 10:14:27 -0700 Subject: Slightly relax the memory order for ref counters --- common/atomic.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/atomic.h b/common/atomic.h index 64b06cce..39daa1dc 100644 --- a/common/atomic.h +++ b/common/atomic.h @@ -413,11 +413,11 @@ typedef ATOMIC(uint) RefCount; inline void InitRef(RefCount *ptr, uint value) { ATOMIC_INIT(ptr, value); } inline uint ReadRef(RefCount *ptr) -{ return ATOMIC_LOAD_SEQ(ptr); } +{ return ATOMIC_LOAD(ptr, almemory_order_acquire); } inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD_SEQ(ptr, 1)+1; } +{ return ATOMIC_ADD(ptr, 1, almemory_order_acq_rel)+1; } inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB_SEQ(ptr, 1)-1; } +{ return ATOMIC_SUB(ptr, 1, almemory_order_acq_rel)-1; } /* WARNING: A livelock is theoretically possible if another thread keeps -- cgit v1.2.3 From d85ddf8aae5ef82fa95218bec2bbd0fd29b133e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Mar 2018 05:58:58 -0700 Subject: Rename NfcFilterUpdate* to NfcFilterProcess* for consistency --- Alc/filters/nfc.c | 8 ++++---- Alc/filters/nfc.h | 6 +++--- Alc/mixvoice.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c index b9006955..3b8696f7 100644 --- a/Alc/filters/nfc.c +++ b/Alc/filters/nfc.c @@ -221,7 +221,7 @@ void NfcFilterAdjust(NfcFilter *nfc, const float w0) } -void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { const float b0 = nfc->first.coeffs[0]; const float a0 = nfc->first.coeffs[1]; @@ -243,7 +243,7 @@ void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict nfc->first.history[0] = z1; } -void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { const float b0 = nfc->second.coeffs[0]; const float a00 = nfc->second.coeffs[1]; @@ -270,7 +270,7 @@ void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict nfc->second.history[1] = z2; } -void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) +void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { const float b0 = nfc->third.coeffs[0]; const float a00 = nfc->third.coeffs[1]; @@ -401,7 +401,7 @@ static void NfcFilterAdjust(NfcFilter *nfc, const float distance) } } -static float NfcFilterUpdate(const float in, NfcFilter *nfc) +static float NfcFilterProcess(const float in, NfcFilter *nfc) { int i; float out = in * nfc->coeffs[0]; diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index f0987d97..8c6cc6ae 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -38,12 +38,12 @@ void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1); void NfcFilterAdjust(NfcFilter *nfc, const float w0); /* Near-field control filter for first-order ambisonic channels (1-3). */ -void NfcFilterUpdate1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); /* Near-field control filter for second-order ambisonic channels (4-8). */ -void NfcFilterUpdate2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); /* Near-field control filter for third-order ambisonic channels (9-15). */ -void NfcFilterUpdate3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); +void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count); #endif /* FILTER_NFC_H */ diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index a9d12821..8a382ffd 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -564,7 +564,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize #define APPLY_NFC_MIX(order) \ if(voice->Direct.ChannelsPerOrder[order] > 0) \ { \ - NfcFilterUpdate##order(&parms->NFCtrlFilter, nfcsamples, samples, \ + NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples, \ DstBufferSize); \ MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \ voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \ -- cgit v1.2.3 From 5aecce5a0dfb7784bfa3cc72642255872e0a4061 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 27 Mar 2018 08:27:16 -0700 Subject: Store the ALbufferlistitem's composited/max sample length --- Alc/mixvoice.c | 32 +++--------- OpenAL32/Include/alSource.h | 1 + OpenAL32/alSource.c | 122 ++++++++++++++++---------------------------- 3 files changed, 50 insertions(+), 105 deletions(-) diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 8a382ffd..d01ca781 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -487,14 +487,12 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize while(tmpiter && SrcBufferSize > FilledAmt) { ALsizei SizeToDo = SrcBufferSize - FilledAmt; - ALsizei CompLen = 0; ALsizei i; for(i = 0;i < tmpiter->num_buffers;i++) { const ALbuffer *ALBuffer = tmpiter->buffers[i]; ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0; - CompLen = maxi(CompLen, DataSize); if(DataSize > pos) { @@ -506,11 +504,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize ALBuffer->FmtType, DataSize); } } - if(pos > CompLen) - pos -= CompLen; + if(pos > tmpiter->max_samples) + pos -= tmpiter->max_samples; else { - FilledAmt += CompLen - pos; + FilledAmt += tmpiter->max_samples - pos; pos = 0; } if(SrcBufferSize > FilledAmt) @@ -715,16 +713,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize else { /* Handle non-looping static source */ - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); - } - - if(DataPosInt >= CompLen) + if(DataPosInt >= BufferListItem->max_samples) { isplaying = false; BufferListItem = NULL; @@ -737,16 +726,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize else while(1) { /* Handle streaming source */ - ALsizei CompLen = 0; - ALsizei i; - - for(i = 0;i < BufferListItem->num_buffers;i++) - { - const ALbuffer *buffer = BufferListItem->buffers[i]; - if(buffer) CompLen = maxi(CompLen, buffer->SampleLen); - } - - if(CompLen > DataPosInt) + if(BufferListItem->max_samples > DataPosInt) break; buffers_done += BufferListItem->num_buffers; @@ -759,7 +739,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize break; } - DataPosInt -= CompLen; + DataPosInt -= BufferListItem->max_samples; } } while(isplaying && OutPos < SamplesToDo); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 5b9d66dc..5f07c09d 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -20,6 +20,7 @@ struct ALsource; typedef struct ALbufferlistitem { ATOMIC(struct ALbufferlistitem*) next; + ALsizei max_samples; ALsizei num_buffers; struct ALbuffer *buffers[]; } ALbufferlistitem; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index e3e40166..ed6bd8ee 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -835,6 +835,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p ALbufferlistitem *newlist = al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, 1)); ATOMIC_INIT(&newlist->next, NULL); + newlist->max_samples = buffer->SampleLen; newlist->num_buffers = 1; newlist->buffers[0] = buffer; IncrementRef(&buffer->ref); @@ -2421,27 +2422,16 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) for(i = 0;i < n;i++) { ALbufferlistitem *BufferList; - ALbuffer *buffer = NULL; bool start_fading = false; ALint vidx = -1; - ALsizei s; source = LookupSource(context, sources[i]); /* Check that there is a queue containing at least one valid, non zero - * length Buffer. + * length buffer. */ BufferList = source->queue; - while(BufferList) - { - ALsizei b; - for(b = 0;b < BufferList->num_buffers;b++) - { - buffer = BufferList->buffers[b]; - if(buffer && buffer->SampleLen > 0) break; - } - if(buffer && buffer->SampleLen > 0) break; + while(BufferList && BufferList->max_samples == 0) BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); - } /* If there's nothing to play, go right to stopped. */ if(UNLIKELY(!BufferList)) @@ -2484,9 +2474,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) break; } - /* Make sure this source isn't already active, and if not, look for an - * unused voice to put it in. - */ + /* Look for an unused voice to play this source with. */ assert(voice == NULL); for(j = 0;j < context->VoiceCount;j++) { @@ -2514,16 +2502,21 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_relaxed); - if(source->OffsetType != AL_NONE) - { - ApplyOffset(source, voice); + if(ApplyOffset(source, voice) != AL_FALSE) start_fading = ATOMIC_LOAD(&voice->position, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) != 0 || ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed) != BufferList; - } - voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - voice->SampleSize = BytesFromFmt(buffer->FmtType); + for(j = 0;j < BufferList->num_buffers;j++) + { + ALbuffer *buffer = BufferList->buffers[j]; + if(buffer) + { + voice->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + voice->SampleSize = BytesFromFmt(buffer->FmtType); + break; + } + } /* Clear previous samples. */ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); @@ -2536,8 +2529,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) voice->Flags = start_fading ? VOICE_IS_FADING : 0; if(source->SourceType == AL_STATIC) voice->Flags |= VOICE_IS_STATIC; memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*voice->NumChannels); - for(s = 0;s < device->NumAuxSends;s++) - memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*voice->NumChannels); + for(j = 0;j < device->NumAuxSends;j++) + memset(voice->Send[j].Params, 0, sizeof(voice->Send[j].Params[0])*voice->NumChannels); if(device->AvgSpeakerDist > 0.0f) { ALfloat w1 = SPEEDOFSOUNDMETRESPERSEC / @@ -2774,6 +2767,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = item; } ATOMIC_INIT(&BufferList->next, NULL); + BufferList->max_samples = buffer ? buffer->SampleLen : 0; BufferList->num_buffers = 1; BufferList->buffers[0] = buffer; if(!buffer) continue; @@ -2901,11 +2895,17 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if(i < head->num_buffers) { /* This head has some buffers left over, so move them to the front - * and update the count. + * and update the sample and buffer count. */ + ALsizei max_length = 0; ALsizei j = 0; while(i < head->num_buffers) - head->buffers[j++] = head->buffers[i++]; + { + ALbuffer *buffer = head->buffers[i++]; + if(buffer) max_length = maxi(max_length, buffer->SampleLen); + head->buffers[j++] = buffer; + } + head->max_samples = max_length; head->num_buffers = j; break; } @@ -3176,15 +3176,7 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALui const ALbufferlistitem *BufferList = Source->queue; while(BufferList && BufferList != Current) { - ALsizei max_len = 0; - ALsizei i; - - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) max_len = maxi(max_len, buffer->SampleLen); - } - readPos += (ALuint64)max_len << 32; + readPos += (ALuint64)BufferList->max_samples << 32; BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, almemory_order_relaxed); } @@ -3234,28 +3226,19 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint const ALbuffer *BufferFmt = NULL; while(BufferList && BufferList != Current) { - ALsizei max_len = 0; - ALsizei i; - - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) - { - if(!BufferFmt) BufferFmt = buffer; - max_len = maxi(max_len, buffer->SampleLen); - } - } - readPos += (ALuint64)max_len << FRACTIONBITS; + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; + readPos += (ALuint64)BufferList->max_samples << FRACTIONBITS; BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, almemory_order_relaxed); } while(BufferList && !BufferFmt) { - ALsizei i; - for(i = 0;i < BufferList->num_buffers && !BufferFmt;i++) - BufferFmt = BufferList->buffers[i]; + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, almemory_order_relaxed); } @@ -3310,21 +3293,13 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte while(BufferList != NULL) { - ALsizei max_len = 0; - ALsizei i; + ALsizei i = 0; + while(!BufferFmt && i < BufferList->num_buffers) + BufferFmt = BufferList->buffers[i++]; - readFin = readFin || (BufferList == Current); - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) - { - if(!BufferFmt) BufferFmt = buffer; - max_len = maxi(max_len, buffer->SampleLen); - } - } - totalBufferLen += max_len; - if(!readFin) readPos += max_len; + readFin |= (BufferList == Current); + totalBufferLen += BufferList->max_samples; + if(!readFin) readPos += BufferList->max_samples; BufferList = ATOMIC_LOAD(&CONST_CAST(ALbufferlistitem*,BufferList)->next, almemory_order_relaxed); @@ -3392,7 +3367,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *conte static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) { ALbufferlistitem *BufferList; - ALuint bufferLen, totalBufferLen; + ALuint totalBufferLen; ALuint offset = 0; ALsizei frac = 0; @@ -3404,17 +3379,7 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) BufferList = Source->queue; while(BufferList && totalBufferLen <= offset) { - ALsizei max_len = 0; - ALsizei i; - - for(i = 0;i < BufferList->num_buffers;i++) - { - ALbuffer *buffer = BufferList->buffers[i]; - if(buffer) max_len = maxi(max_len, buffer->SampleLen); - } - bufferLen = max_len; - - if(bufferLen > offset-totalBufferLen) + if((ALuint)BufferList->max_samples > offset-totalBufferLen) { /* Offset is in this buffer */ ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); @@ -3422,8 +3387,7 @@ static ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_release); return AL_TRUE; } - - totalBufferLen += bufferLen; + totalBufferLen += BufferList->max_samples; BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); } -- cgit v1.2.3 From 2b16ff3ca8411e27daf621e06a6e651309dbb6b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Mar 2018 06:28:46 -0700 Subject: Check all buffers to update a source with --- Alc/ALu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index fef50feb..add3602c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1523,8 +1523,11 @@ static void CalcSourceParams(ALvoice *voice, ALCcontext *context, bool force) BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); while(BufferListItem != NULL) { - const ALbuffer *buffer; - if(BufferListItem->num_buffers >= 1 && (buffer=BufferListItem->buffers[0]) != NULL) + const ALbuffer *buffer = NULL; + ALsizei i = 0; + while(!buffer && i < BufferListItem->num_buffers) + buffer = BufferListItem->buffers[i]; + if(LIKELY(buffer)) { if(props->SpatializeMode == SpatializeOn || (props->SpatializeMode == SpatializeAuto && buffer->FmtChannels == FmtMono)) -- cgit v1.2.3 From cae4b1a062b53dd25eba7caa41622be730106749 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 28 Mar 2018 14:34:58 -0700 Subject: Don't specify macros as arguments to CHECK_INCLUDE_FILE(S) --- CMakeLists.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df1dfe63..07454f15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -577,7 +577,12 @@ ENDIF() # Check if we have Windows headers -CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0502) +SET(OLD_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) +SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0502) +CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H) +SET(CMAKE_REQUIRED_DEFINITIONS ${OLD_REQUIRED_DEFINITIONS}) +UNSET(OLD_REQUIRED_DEFINITIONS) + IF(NOT HAVE_WINDOWS_H) CHECK_SYMBOL_EXISTS(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) IF(NOT HAVE_GETTIMEOFDAY) @@ -975,8 +980,11 @@ OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF) OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF) OPTION(ALSOFT_REQUIRE_WASAPI "Require WASAPI backend" OFF) IF(HAVE_WINDOWS_H) + SET(OLD_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) + SET(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0502) + # Check MMSystem backend - CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0502) + CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H) IF(HAVE_MMSYSTEM_H) CHECK_SHARED_FUNCTION_EXISTS(waveOutOpen "windows.h;mmsystem.h" winmm "" HAVE_LIBWINMM) IF(HAVE_LIBWINMM) @@ -1013,6 +1021,9 @@ IF(HAVE_WINDOWS_H) SET(ALC_OBJS ${ALC_OBJS} Alc/backends/wasapi.c) ENDIF() ENDIF() + + SET(CMAKE_REQUIRED_DEFINITIONS ${OLD_REQUIRED_DEFINITIONS}) + UNSET(OLD_REQUIRED_DEFINITIONS) ENDIF() IF(ALSOFT_REQUIRE_WINMM AND NOT HAVE_WINMM) MESSAGE(FATAL_ERROR "Failed to enabled required WinMM backend") -- cgit v1.2.3 From a7da29804d988290a50140b3ad8580cfa29261eb Mon Sep 17 00:00:00 2001 From: Henri Hyyryläinen Date: Fri, 30 Mar 2018 01:53:55 +0300 Subject: Added missing string include to alffplay --- examples/alffplay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 6f6773a4..3bba154e 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -19,6 +19,7 @@ #include #include #include +#include extern "C" { #include "libavcodec/avcodec.h" -- cgit v1.2.3 From 880d5550600a77fef23d8ade9cd8a9137564bea1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 11:18:16 -0700 Subject: Combine two loops --- Alc/bformatdec.c | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index ff0cd657..7ab315c3 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -34,43 +34,41 @@ void bandsplit_clear(BandSplitter *splitter) void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, const ALfloat *input, ALsizei count) { - ALfloat coeff, d, x; - ALfloat z1, z2; + ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; + ALfloat lp_z1, lp_z2, hp_z1; ALsizei i; - coeff = splitter->coeff*0.5f + 0.5f; - z1 = splitter->lp_z1; - z2 = splitter->lp_z2; + hp_coeff = splitter->coeff; + lp_coeff = splitter->coeff*0.5f + 0.5f; + lp_z1 = splitter->lp_z1; + lp_z2 = splitter->lp_z2; + hp_z1 = splitter->hp_z1; for(i = 0;i < count;i++) { - x = input[i]; + ALfloat in = input[i]; - d = (x - z1) * coeff; - x = z1 + d; - z1 = x + d; + /* Low-pass sample processing. */ + d = (in - lp_z1) * lp_coeff; + lp_y = lp_z1 + d; + lp_z1 = lp_y + d; - d = (x - z2) * coeff; - x = z2 + d; - z2 = x + d; + d = (lp_y - lp_z2) * lp_coeff; + lp_y = lp_z2 + d; + lp_z2 = lp_y + d; - lpout[i] = x; - } - splitter->lp_z1 = z1; - splitter->lp_z2 = z2; + lpout[i] = lp_y; - coeff = splitter->coeff; - z1 = splitter->hp_z1; - for(i = 0;i < count;i++) - { - x = input[i]; - - d = x - coeff*z1; - x = z1 + coeff*d; - z1 = d; + /* All-pass sample processing. */ + d = in - hp_coeff*hp_z1; + hp_y = hp_z1 + hp_coeff*d; + hp_z1 = d; - hpout[i] = x - lpout[i]; + /* High-pass generated from removing low-passed output. */ + hpout[i] = hp_y - lp_y; } - splitter->hp_z1 = z1; + splitter->lp_z1 = lp_z1; + splitter->lp_z2 = lp_z2; + splitter->hp_z1 = hp_z1; } -- cgit v1.2.3 From 852ad41176b089dcb808533aad9f2fd1384c11bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 12:11:37 -0700 Subject: Pass the azimuth and elevation to CalcPanningAndFilters --- Alc/ALu.c | 74 +++++++++++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index add3602c..bbac0d2f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -180,14 +180,16 @@ static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2 static ALfloat aluNormalize(ALfloat *vec) { ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); - if(length > 0.0f) + if(length > FLT_EPSILON) { ALfloat inv_length = 1.0f/length; vec[0] *= inv_length; vec[1] *= inv_length; vec[2] *= inv_length; + return length; } - return length; + vec[0] = vec[1] = vec[2] = 0.0f; + return 0.0f; } static void aluMatrixfFloat3(ALfloat *vec, ALfloat w, const aluMatrixf *mtx) @@ -532,13 +534,14 @@ static const struct ChanMap MonoMap[1] = { { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; -static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const ALfloat *Dir, - const ALfloat Spread, const ALfloat DryGain, - const ALfloat DryGainHF, const ALfloat DryGainLF, - const ALfloat *WetGain, const ALfloat *WetGainLF, - const ALfloat *WetGainHF, ALeffectslot **SendSlots, - const ALbuffer *Buffer, const struct ALvoiceProps *props, - const ALlistener *Listener, const ALCdevice *Device) +static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALfloat Elev, + const ALfloat Distance, const ALfloat Spread, + const ALfloat DryGain, const ALfloat DryGainHF, + const ALfloat DryGainLF, const ALfloat *WetGain, + const ALfloat *WetGainLF, const ALfloat *WetGainHF, + ALeffectslot **SendSlots, const ALbuffer *Buffer, + const struct ALvoiceProps *props, const ALlistener *Listener, + const ALCdevice *Device) { struct ChanMap StereoMap[2] = { { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, @@ -664,13 +667,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const } if(Device->Render_Mode == StereoPair) - { - ALfloat ev = asinf(Dir[1]); - ALfloat az = atan2f(Dir[0], -Dir[2]); - CalcAnglePairwiseCoeffs(az, ev, Spread, coeffs); - } + CalcAnglePairwiseCoeffs(Azi, Elev, Spread, coeffs); else - CalcDirectionCoeffs(Dir, Spread, coeffs); + CalcAngleCoeffs(Azi, Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ ComputeDryPanGains(&Device->Dry, coeffs, DryGain*1.414213562f, @@ -801,15 +800,11 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const if(Distance > FLT_EPSILON) { ALfloat coeffs[MAX_AMBI_COEFFS]; - ALfloat ev, az; - - ev = asinf(Dir[1]); - az = atan2f(Dir[0], -Dir[2]); /* Get the HRIR coefficients and delays just once, for the given * source direction. */ - GetHrtfCoeffs(Device->HrtfHandle, ev, az, Spread, + GetHrtfCoeffs(Device->HrtfHandle, Elev, Azi, Spread, voice->Direct.Params[0].Hrtf.Target.Coeffs, voice->Direct.Params[0].Hrtf.Target.Delay); voice->Direct.Params[0].Hrtf.Target.Gain = DryGain * downmix_gain; @@ -825,7 +820,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const /* Calculate the directional coefficients once, which apply to all * input channels of the source sends. */ - CalcDirectionCoeffs(Dir, Spread, coeffs); + CalcAngleCoeffs(Azi, Elev, Spread, coeffs); for(i = 0;i < NumSends;i++) { @@ -919,13 +914,9 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const * input channels. */ if(Device->Render_Mode == StereoPair) - { - ALfloat ev = asinf(Dir[1]); - ALfloat az = atan2f(Dir[0], -Dir[2]); - CalcAnglePairwiseCoeffs(az, ev, Spread, coeffs); - } + CalcAnglePairwiseCoeffs(Azi, Elev, Spread, coeffs); else - CalcDirectionCoeffs(Dir, Spread, coeffs); + CalcAngleCoeffs(Azi, Elev, Spread, coeffs); for(c = 0;c < num_channels;c++) { @@ -1072,7 +1063,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Distance, const static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *props, const ALbuffer *ALBuffer, const ALCcontext *ALContext) { - static const ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; const ALCdevice *Device = ALContext->Device; const ALlistener *Listener = ALContext->Listener; ALfloat DryGain, DryGainHF, DryGainLF; @@ -1130,7 +1120,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p WetGainLF[i] = props->Send[i].GainLF; } - CalcPanningAndFilters(voice, 0.0f, dir, 0.0f, DryGain, DryGainHF, DryGainLF, WetGain, + CalcPanningAndFilters(voice, 0.0f, 0.0f, 0.0f, 0.0f, DryGain, DryGainHF, DryGainLF, WetGain, WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } @@ -1151,7 +1141,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; bool directional; - ALfloat dir[3]; + ALfloat ev, az; ALfloat spread; ALfloat Pitch; ALint i; @@ -1240,7 +1230,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop Velocity.v[2] += lvelocity->v[2]; } - directional = aluNormalize(Direction.v) > FLT_EPSILON; + directional = aluNormalize(Direction.v) > 0.0f; SourceToListener.v[0] = -Position.v[0]; SourceToListener.v[1] = -Position.v[1]; SourceToListener.v[2] = -Position.v[2]; @@ -1476,29 +1466,29 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc12); voice->Resampler = SelectResampler(props->Resampler); - if(Distance > FLT_EPSILON) + if(Distance > 0.0f) { - dir[0] = -SourceToListener.v[0]; /* Clamp Y, in case rounding errors caused it to end up outside of * -1...+1. */ - dir[1] = clampf(-SourceToListener.v[1], -1.0f, 1.0f); - dir[2] = -SourceToListener.v[2] * ZScale; + ev = asinf(clampf(-SourceToListener.v[1], -1.0f, 1.0f)); + /* Double negation on Z cancels out; negate once for changing source- + * to-listener to listener-to-source, and again for right-handed coords + * with -Z in front. + */ + az = atan2f(-SourceToListener.v[0], SourceToListener.v[2]*ZScale); } else - { - dir[0] = 0.0f; - dir[1] = 0.0f; - dir[2] = -1.0f; - } + ev = az = 0.0f; + if(props->Radius > Distance) spread = F_TAU - Distance/props->Radius*F_PI; - else if(Distance > FLT_EPSILON) + else if(Distance > 0.0f) spread = asinf(props->Radius / Distance) * 2.0f; else spread = 0.0f; - CalcPanningAndFilters(voice, Distance, dir, spread, DryGain, DryGainHF, DryGainLF, WetGain, + CalcPanningAndFilters(voice, az, ev, Distance, spread, DryGain, DryGainHF, DryGainLF, WetGain, WetGainLF, WetGainHF, SendSlots, ALBuffer, props, Listener, Device); } -- cgit v1.2.3 From 4a8c3b50b649815af123a08689efd7d16f9a571b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 15:41:51 -0700 Subject: Apply the initial decay and air absorption after gain clamping --- Alc/ALu.c | 84 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index bbac0d2f..51150cd7 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1317,48 +1317,6 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop break; } - /* Distance-based air absorption */ - if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) - { - ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * - Listener->Params.MetersPerUnit; - if(props->AirAbsorptionFactor > 0.0f) - { - ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); - DryGainHF *= hfattn; - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= hfattn; - } - - if(props->WetGainAuto) - { - /* Apply a decay-time transformation to the wet path, based on the - * source distance in meters. The initial decay of the reverb - * effect is calculated and applied to the wet path. - */ - for(i = 0;i < NumSends;i++) - { - ALfloat gain, gainhf, gainlf; - - if(!(DecayDistance[i] > 0.0f)) - continue; - - gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); - WetGain[i] *= gain; - /* Yes, the wet path's air absorption is applied with - * WetGainAuto on, rather than WetGainHFAuto. - */ - if(gain > 0.0f) - { - gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); - WetGainHF[i] *= minf(gainhf / gain, 1.0f); - gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); - WetGainLF[i] *= minf(gainlf / gain, 1.0f); - } - } - } - } - /* Calculate directional soundcones */ if(directional && props->InnerAngle < 360.0f) { @@ -1414,6 +1372,48 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop WetGainLF[i] *= props->Send[i].GainLF; } + /* Distance-based air absorption and initial send decay. */ + if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f) + { + ALfloat meters_base = (ClampedDist-props->RefDistance) * props->RolloffFactor * + Listener->Params.MetersPerUnit; + if(props->AirAbsorptionFactor > 0.0f) + { + ALfloat hfattn = powf(AIRABSORBGAINHF, meters_base * props->AirAbsorptionFactor); + DryGainHF *= hfattn; + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= hfattn; + } + + if(props->WetGainAuto) + { + /* Apply a decay-time transformation to the wet path, based on the + * source distance in meters. The initial decay of the reverb + * effect is calculated and applied to the wet path. + */ + for(i = 0;i < NumSends;i++) + { + ALfloat gain, gainhf, gainlf; + + if(!(DecayDistance[i] > 0.0f)) + continue; + + gain = powf(REVERB_DECAY_GAIN, meters_base/DecayDistance[i]); + WetGain[i] *= gain; + /* Yes, the wet path's air absorption is applied with + * WetGainAuto on, rather than WetGainHFAuto. + */ + if(gain > 0.0f) + { + gainhf = powf(REVERB_DECAY_GAIN, meters_base/DecayHFDistance[i]); + WetGainHF[i] *= minf(gainhf / gain, 1.0f); + gainlf = powf(REVERB_DECAY_GAIN, meters_base/DecayLFDistance[i]); + WetGainLF[i] *= minf(gainlf / gain, 1.0f); + } + } + } + } + /* Initial source pitch */ Pitch = props->Pitch; -- cgit v1.2.3 From f48a1e3a314dcbaf8b96d44be17c8fb708d35ae8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 17:18:24 -0700 Subject: Add simple descriptions to some extension formats in alext.h --- include/AL/alext.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/include/AL/alext.h b/include/AL/alext.h index 1a76397b..cd7f2750 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -97,6 +97,31 @@ extern "C" { #ifndef AL_EXT_MCFORMATS #define AL_EXT_MCFORMATS 1 +/* Provides support for surround sound buffer formats with 8, 16, and 32-bit + * samples. + * + * QUAD8: Unsigned 8-bit, Quadraphonic (Front Left, Front Right, Rear Left, + * Rear Right). + * QUAD16: Signed 16-bit, Quadraphonic. + * QUAD32: 32-bit float, Quadraphonic. + * REAR8: Unsigned 8-bit, Rear Stereo (Rear Left, Rear Right). + * REAR16: Signed 16-bit, Rear Stereo. + * REAR32: 32-bit float, Rear Stereo. + * 51CHN8: Unsigned 8-bit, 5.1 Surround (Front Left, Front Right, Front Center, + * LFE, Side Left, Side Right). Note that some audio systems may label + * 5.1's Side channels as Rear or Surround; they are equivalent for the + * purposes of this extension. + * 51CHN16: Signed 16-bit, 5.1 Surround. + * 51CHN32: 32-bit float, 5.1 Surround. + * 61CHN8: Unsigned 8-bit, 6.1 Surround (Front Left, Front Right, Front Center, + * LFE, Rear Center, Side Left, Side Right). + * 61CHN16: Signed 16-bit, 6.1 Surround. + * 61CHN32: 32-bit float, 6.1 Surround. + * 71CHN8: Unsigned 8-bit, 7.1 Surround (Front Left, Front Right, Front Center, + * LFE, Rear Left, Rear Right, Side Left, Side Right). + * 71CHN16: Signed 16-bit, 7.1 Surround. + * 71CHN32: 32-bit float, 7.1 Surround. + */ #define AL_FORMAT_QUAD8 0x1204 #define AL_FORMAT_QUAD16 0x1205 #define AL_FORMAT_QUAD32 0x1206 @@ -395,6 +420,16 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); #ifndef AL_EXT_BFORMAT #define AL_EXT_BFORMAT 1 +/* Provides support for B-Format ambisonic buffers (first-order, FuMa scaling + * and layout). + * + * BFORMAT2D_8: Unsigned 8-bit, 3-channel non-periphonic (WXY). + * BFORMAT2D_16: Signed 16-bit, 3-channel non-periphonic (WXY). + * BFORMAT2D_FLOAT32: 32-bit float, 3-channel non-periphonic (WXY). + * BFORMAT3D_8: Unsigned 8-bit, 4-channel periphonic (WXYZ). + * BFORMAT3D_16: Signed 16-bit, 4-channel periphonic (WXYZ). + * BFORMAT3D_FLOAT32: 32-bit float, 4-channel periphonic (WXYZ). + */ #define AL_FORMAT_BFORMAT2D_8 0x20021 #define AL_FORMAT_BFORMAT2D_16 0x20022 #define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 -- cgit v1.2.3 From 61de399806f777dc111d30d0ed9ef820a83ede81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 18:03:01 -0700 Subject: Don't cache SDL2_LIBRARY_TEMP with CMake Otherwise it keeps prepending and appending the same extra libs and flags with each invocation. --- cmake/FindSDL2.cmake | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 70e607a8..e808d006 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -18,10 +18,10 @@ # module will automatically add the -framework Cocoa on your behalf. # # -# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# Additional Note: If you see an empty SDL2_CORE_LIBRARY in your configuration # and no SDL2_LIBRARY, it means CMake did not find your SDL2 library # (SDL2.dll, libsdl2.so, SDL2.framework, etc). -# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Set SDL2_CORE_LIBRARY to point to your SDL2 library, and configure again. # Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value # as appropriate. These values are used to generate the final SDL2_LIBRARY # variable, but when these values are unset, SDL2_LIBRARY does not get created. @@ -87,7 +87,7 @@ FIND_PATH(SDL2_INCLUDE_DIR SDL.h ) #MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") -FIND_LIBRARY(SDL2_LIBRARY_TEMP +FIND_LIBRARY(SDL2_CORE_LIBRARY NAMES SDL2 HINTS $ENV{SDL2DIR} @@ -98,8 +98,7 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP /opt/csw /opt ) - -#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") +#MESSAGE("SDL2_CORE_LIBRARY is ${SDL2_CORE_LIBRARY}") IF(NOT SDL2_BUILDING_LIBRARY) IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") @@ -137,7 +136,9 @@ IF(MINGW) ENDIF(MINGW) SET(SDL2_FOUND "NO") -IF(SDL2_LIBRARY_TEMP) +IF(SDL2_CORE_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2_CORE_LIBRARY}) + # For SDL2main IF(NOT SDL2_BUILDING_LIBRARY) IF(SDL2MAIN_LIBRARY) @@ -172,15 +173,12 @@ IF(SDL2_LIBRARY_TEMP) ENDIF(WIN32) # Set the final string here so the GUI reflects the final state. - SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") - # Set the temp variable to INTERNAL so it is not seen in the CMake GUI - SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP}) SET(SDL2_FOUND "YES") -ENDIF(SDL2_LIBRARY_TEMP) +ENDIF(SDL2_CORE_LIBRARY) INCLUDE(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) -- cgit v1.2.3 From a2c24ff946623b74df6ca7884f549a76911ebe8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 18:57:48 -0700 Subject: Specify Libs.private for the pkg-config file Only used when building the static lib for its dependencies, since the shared lib automatically handles its own dependencies. --- CMakeLists.txt | 13 ++++++++++++- openal.pc.in | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07454f15..69e5528c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1261,8 +1261,19 @@ SET(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") SET(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}") SET(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") SET(PACKAGE_VERSION "${LIB_VERSION}") +SET(PKG_CONFIG_CFLAGS ) +SET(PKG_CONFIG_PRIVATE_LIBS ) IF(LIBTYPE STREQUAL "STATIC") - SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS}) + SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC) + FOREACH(FLAG ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB}) + # If this is already a linker flag, or is a full path+file, add it + # as-is. Otherwise, it's a name intended to be dressed as -lname. + IF(FLAG MATCHES "^-.*" OR EXISTS "${FLAG}") + SET(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} ${FLAG}") + ELSE() + SET(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} -l${FLAG}") + ENDIF() + ENDFOREACH() ENDIF() # End configuration diff --git a/openal.pc.in b/openal.pc.in index 8bdd4f3b..dfa6f573 100644 --- a/openal.pc.in +++ b/openal.pc.in @@ -8,4 +8,5 @@ Description: OpenAL is a cross-platform 3D audio API Requires: @PKG_CONFIG_REQUIRES@ Version: @PACKAGE_VERSION@ Libs: -L${libdir} -l@LIBNAME@ @PKG_CONFIG_LIBS@ +Libs.private:@PKG_CONFIG_PRIVATE_LIBS@ Cflags: -I${includedir} -I${includedir}/AL @PKG_CONFIG_CFLAGS@ -- cgit v1.2.3 From 29ae74d4bbca28f9dc25949d0e2f0f14b4d5d805 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 29 Mar 2018 20:44:44 -0700 Subject: Fix lower elevation synthesis for stereo HRTFs --- utils/makehrtf.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 417b9944..28c33b87 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -2346,25 +2346,26 @@ static void SynthesizeHrirs(HrirDataT *hData) { uint channels = (hData->mChannelType == CT_STEREO) ? 2 : 1; uint n = hData->mIrPoints; - uint ti, fi, oi, ai, ei, i; + uint ti, fi, ai, ei, i; double lp[4], s0, s1; double of, b; uint a0, a1; double af; - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + const uint oi = hData->mFds[fi].mEvStart; + if(oi <= 0) continue; + + for(ti = 0;ti < channels;ti++) { - if(hData->mFds[fi].mEvStart <= 0) - continue; - oi = hData->mFds[fi].mEvStart; for(i = 0;i < n;i++) hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = 0.0; for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++) { for(i = 0;i < n;i++) - hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] += hData->mFds[fi].mEvs[oi].mAzs[ai].mIrs[ti][i] / hData->mFds[fi].mEvs[oi].mAzCount; + hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] += hData->mFds[fi].mEvs[oi].mAzs[ai].mIrs[ti][i] / + hData->mFds[fi].mEvs[oi].mAzCount; } for(ei = 1;ei < hData->mFds[fi].mEvStart;ei++) { @@ -2380,7 +2381,8 @@ static void SynthesizeHrirs(HrirDataT *hData) for(i = 0;i < n;i++) { s0 = hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i]; - s1 = Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mIrs[ti][i], hData->mFds[fi].mEvs[oi].mAzs[a1].mIrs[ti][i], af); + s1 = Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mIrs[ti][i], + hData->mFds[fi].mEvs[oi].mAzs[a1].mIrs[ti][i], af); s0 = Lerp(s0, s1, of); lp[0] = Lerp(s0, lp[0], b); lp[1] = Lerp(lp[0], lp[1], b); @@ -2404,8 +2406,8 @@ static void SynthesizeHrirs(HrirDataT *hData) lp[3] = Lerp(lp[2], lp[3], b); hData->mFds[fi].mEvs[0].mAzs[0].mIrs[ti][i] = lp[3]; } - hData->mFds[fi].mEvStart = 0; } + hData->mFds[fi].mEvStart = 0; } } -- cgit v1.2.3 From 91900b0599db9e49847053808c07233fd05ee478 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 30 Mar 2018 09:18:17 -0700 Subject: Fix misspellings of quadraphonic AL_LOKI_quadriphonic is left alone since that is what the extension is called and what code expects. All other instances have been fixed for consistency. --- alsoftrc.sample | 2 +- docs/ambisonics.txt | 2 +- presets/presets.txt | 4 ++-- utils/alsoft-config/mainwindow.cpp | 4 ++-- utils/alsoft-config/mainwindow.ui | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index cac9fd93..2b7093a9 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -286,7 +286,7 @@ nfc = true nfc-ref-delay = ## quad: -# Decoder configuration file for Quadrophonic channel output. See +# Decoder configuration file for Quadraphonic channel output. See # docs/ambdec.txt for a description of the file format. quad = diff --git a/docs/ambisonics.txt b/docs/ambisonics.txt index b50e76c2..2d94427e 100644 --- a/docs/ambisonics.txt +++ b/docs/ambisonics.txt @@ -17,7 +17,7 @@ fully 3D soundfield using as few as 4 channels (or even just 3, if you don't mind dropping down to 2 dimensions like many surround sound systems are). This representation is called B-Format. It was designed to handle audio independent of any specific speaker layout, so with a proper decoder the same recording can -be played back on a variety of speaker setups, from quadrophonic and hexagonal +be played back on a variety of speaker setups, from quadraphonic and hexagonal to cubic and other periphonic (with height) layouts. Although it was developed decades ago, various factors held ambisonics back diff --git a/presets/presets.txt b/presets/presets.txt index 94968720..541416e2 100644 --- a/presets/presets.txt +++ b/presets/presets.txt @@ -10,12 +10,12 @@ specified angles do not change the decoder behavior). Details of the individual presets are as follows. square.ambdec -Specifies a basic square speaker setup for Quadrophonic output, with identical +Specifies a basic square speaker setup for Quadraphonic output, with identical width and depth. Front speakers are placed at +45 and -45 degrees, and back speakers are placed at +135 and -135 degrees. rectangle.ambdec -Specifies a narrower speaker setup for Quadrophonic output, with a little less +Specifies a narrower speaker setup for Quadraphonic output, with a little less width but a little more depth over a basic square setup. Front speakers are placed at +30 and -30 degrees, providing a bit more compatibility for existing stereo content, with back speakers at +150 and -150 degrees. diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 94aa0750..dbd359d8 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -74,7 +74,7 @@ static const struct NameValuePair { { "Autodetect", "" }, { "Mono", "mono" }, { "Stereo", "stereo" }, - { "Quadrophonic", "quad" }, + { "Quadraphonic", "quad" }, { "5.1 Surround (Side)", "surround51" }, { "5.1 Surround (Rear)", "surround51rear" }, { "6.1 Surround", "surround61" }, @@ -1171,7 +1171,7 @@ void MainWindow::updatePeriodCountSlider() void MainWindow::selectQuadDecoderFile() -{ selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} +{ selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadraphonic Decoder");} void MainWindow::select51DecoderFile() { selectDecoderFile(ui->decoder51LineEdit, "Select 5.1 Surround Decoder");} void MainWindow::select61DecoderFile() diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index b4766d5a..ef886ba4 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -694,7 +694,7 @@ configuration file. - Quadrophonic: + Quadraphonic: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter -- cgit v1.2.3 From e288c3b44a1417a9c54f4f219f028430959ef198 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Mar 2018 20:44:14 -0700 Subject: Fix HRTF HOA coefficients ACN8 was accidentally put on ACN7. However, rather than adding the missing channel of silence, set up the coefficient map to only use the ambisonic channels that can contribute to output. --- Alc/panning.c | 58 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index b49eb2e7..cb4406a8 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -852,30 +852,31 @@ static void InitHrtfPanning(ALCdevice *device) { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f }, { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f }, }, AmbiMatrixHOA[][MAX_AMBI_COEFFS] = { - { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, - { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, - { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, 7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, 8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, -6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, 0.00000000e+00f, -8.66025404e-02f, 0.00000000e+00f, 1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, -6.12372435e-02f, -6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 8.66025404e-02f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f, -1.29099445e-01f }, + { 5.55555556e-02f, 6.12372435e-02f, 0.00000000e+00f, 6.12372435e-02f, 6.83467648e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, -5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, -5.00000000e-02f, -4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 5.00000000e-02f, -7.14285715e-02f, 5.00000000e-02f, 4.55645099e-02f, 0.00000000e+00f }, + { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, }; static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { 1.00000000e+00f, 5.77350269e-01f }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { 9.80580676e-01f, 7.59554525e-01f, 3.92232270e-01f }; + static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; ALsizei count = 4; @@ -889,7 +890,7 @@ static void InitHrtfPanning(ALCdevice *device) { AmbiMatrix = AmbiMatrixHOA; AmbiOrderHFGain = AmbiOrderHFGainHOA; - count = 9; + count = COUNTOF(IndexMap); } device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count)); @@ -897,7 +898,7 @@ static void InitHrtfPanning(ALCdevice *device) for(i = 0;i < count;i++) { device->Dry.Ambi.Map[i].Scale = 1.0f; - device->Dry.Ambi.Map[i].Index = i; + device->Dry.Ambi.Map[i].Index = IndexMap[i]; } device->Dry.CoeffCount = 0; device->Dry.NumChannels = count; @@ -930,7 +931,22 @@ static void InitHrtfPanning(ALCdevice *device) AmbiOrderHFGain ); - InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, true); + if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "decoder", "nfc", 1) && + device->HrtfHandle->distance > 0.0f) + { + /* NFC is only used when AvgSpeakerDist is greater than 0, and can only + * be used when rendering to an ambisonic buffer. + */ + device->AvgSpeakerDist = device->HrtfHandle->distance; + + i = 0; + device->Dry.NumChannelsPerOrder[i++] = 1; + device->Dry.NumChannelsPerOrder[i++] = 3; + if(device->AmbiUp) + device->Dry.NumChannelsPerOrder[i++] = 2; + while(i < MAX_AMBI_ORDER+1) + device->Dry.NumChannelsPerOrder[i++] = 0; + } } static void InitUhjPanning(ALCdevice *device) -- cgit v1.2.3 From 334bc4f551af15281a9109200f5ffb34f22c67c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 31 Mar 2018 23:11:48 -0700 Subject: Limit the near-field control distance to 10m. --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index cb4406a8..7ed27852 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -425,7 +425,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde /* NFC is only used when AvgSpeakerDist is greater than 0, and can only * be used when rendering to an ambisonic buffer. */ - device->AvgSpeakerDist = ctrl_dist; + device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); device->Dry.NumChannelsPerOrder[0] = 1; if(periphonic) @@ -937,7 +937,7 @@ static void InitHrtfPanning(ALCdevice *device) /* NFC is only used when AvgSpeakerDist is greater than 0, and can only * be used when rendering to an ambisonic buffer. */ - device->AvgSpeakerDist = device->HrtfHandle->distance; + device->AvgSpeakerDist = minf(device->HrtfHandle->distance, 10.0f); i = 0; device->Dry.NumChannelsPerOrder[i++] = 1; -- cgit v1.2.3 From 414b56edec5441211dc924fef365c54267c04f1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 1 Apr 2018 16:39:20 -0700 Subject: Initialize COM using the multithreaded apartment I honestly have no idea which is the correct (or better) mode to use given the confusing mess COM is, but CoInitialize uses single-threaded apartments which seems to be a problem for with at least a couple games in the STALKER series (the call fails, which causes us to drop back to the DSound backend). --- Alc/backends/wasapi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c index 8677afa9..50471f6b 100644 --- a/Alc/backends/wasapi.c +++ b/Alc/backends/wasapi.c @@ -388,7 +388,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) TRACE("Starting message thread\n"); - cohr = CoInitialize(NULL); + cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(FAILED(cohr)) { WARN("Failed to initialize COM: 0x%08lx\n", cohr); @@ -435,7 +435,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) hr = cohr = S_OK; if(++deviceCount == 1) - hr = cohr = CoInitialize(NULL); + hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) hr = V0(proxy,openProxy)(); if(FAILED(hr)) @@ -487,7 +487,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) hr = cohr = S_OK; if(++deviceCount == 1) - hr = cohr = CoInitialize(NULL); + hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) @@ -627,10 +627,10 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) BYTE *buffer; HRESULT hr; - hr = CoInitialize(NULL); + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(FAILED(hr)) { - ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); V0(device->Backend,lock)(); aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); V0(device->Backend,unlock)(); @@ -1321,10 +1321,10 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) size_t samplesmax = 0; HRESULT hr; - hr = CoInitialize(NULL); + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if(FAILED(hr)) { - ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr); V0(device->Backend,lock)(); aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr); V0(device->Backend,unlock)(); -- cgit v1.2.3 From 869637af2ee5882dbe5b0016d1091e9e0bc2a69a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 3 Apr 2018 10:15:35 -0700 Subject: Apply biquad and T60 filters using transposed direct form II --- Alc/effects/echo.c | 22 ++++++++-------------- Alc/effects/reverb.c | 23 +++++++++-------------- Alc/filters/defs.h | 30 ++++++++++++----------------- Alc/filters/filter.c | 53 ++++++++++++++++++++++++++++------------------------ Alc/mixvoice.c | 8 ++++---- 5 files changed, 62 insertions(+), 74 deletions(-) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index a3a4e120..282aa1d7 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -155,14 +155,12 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const const ALsizei tap2 = state->Tap[1].delay; ALfloat *restrict delaybuf = state->SampleBuffer; ALsizei offset = state->Offset; - ALfloat x[2], y[2], in, out; + ALfloat z1, z2, in, out; ALsizei base; ALsizei c, i; - x[0] = state->Filter.x[0]; - x[1] = state->Filter.x[1]; - y[0] = state->Filter.y[0]; - y[1] = state->Filter.y[1]; + z1 = state->Filter.z1; + z2 = state->Filter.z2; for(base = 0;base < SamplesToDo;) { alignas(16) ALfloat temps[2][128]; @@ -182,11 +180,9 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const * feedback attenuation. */ in = temps[1][i]; - out = in*state->Filter.b0 + - x[0]*state->Filter.b1 + x[1]*state->Filter.b2 - - y[0]*state->Filter.a1 - y[1]*state->Filter.a2; - x[1] = x[0]; x[0] = in; - y[1] = y[0]; y[0] = out; + out = in*state->Filter.b0 + z1; + z1 = in*state->Filter.b1 - out*state->Filter.a1 + z2; + z2 = in*state->Filter.b2 - out*state->Filter.a2; delaybuf[offset&mask] += out * state->FeedGain; offset++; @@ -198,10 +194,8 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const base += td; } - state->Filter.x[0] = x[0]; - state->Filter.x[1] = x[1]; - state->Filter.y[0] = y[0]; - state->Filter.y[1] = y[1]; + state->Filter.z1 = z1; + state->Filter.z2 = z2; state->Offset = offset; } diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0d486e63..831e4a3a 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -234,11 +234,9 @@ typedef struct T60Filter { ALfloat HFCoeffs[3]; ALfloat LFCoeffs[3]; - /* The HF and LF filters each keep a state of the last input and last - * output sample. - */ - ALfloat HFState[2]; - ALfloat LFState[2]; + /* The HF and LF filters each keep a delay component. */ + ALfloat HFState; + ALfloat LFState; } T60Filter; typedef struct EarlyReflections { @@ -407,10 +405,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.T60[i].HFCoeffs[j] = 0.0f; state->Late.T60[i].LFCoeffs[j] = 0.0f; } - state->Late.T60[i].HFState[0] = 0.0f; - state->Late.T60[i].HFState[1] = 0.0f; - state->Late.T60[i].LFState[0] = 0.0f; - state->Late.T60[i].LFState[1] = 0.0f; + state->Late.T60[i].HFState = 0.0f; + state->Late.T60[i].LFState = 0.0f; } for(i = 0;i < NUM_LINES;i++) @@ -1443,9 +1439,8 @@ DECL_TEMPLATE(Faded) static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict coeffs, ALfloat *restrict state) { - ALfloat out = coeffs[0]*in + coeffs[1]*state[0] + coeffs[2]*state[1]; - state[0] = in; - state[1] = out; + ALfloat out = coeffs[0]*in + *state; + *state = coeffs[1]*in + coeffs[2]*out; return out; } @@ -1456,8 +1451,8 @@ static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict ALsizei i; for(i = 0;i < NUM_LINES;i++) out[i] = FirstOrderFilter( - FirstOrderFilter(in[i], filter[i].HFCoeffs, filter[i].HFState), - filter[i].LFCoeffs, filter[i].LFState + FirstOrderFilter(in[i], filter[i].HFCoeffs, &filter[i].HFState), + filter[i].LFCoeffs, &filter[i].LFState ); } diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index c26427fb..8257cec7 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -31,10 +31,10 @@ typedef enum BiquadType { } BiquadType; typedef struct BiquadState { - ALfloat x[2]; /* History of two last input samples */ - ALfloat y[2]; /* History of two last output samples */ - ALfloat b0, b1, b2; /* Transfer function coefficients "b" */ - ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */ + ALfloat z1, z2; /* Last two delayed components for direct form II. */ + ALfloat b0, b1, b2; /* Transfer function coefficients "b" (numerator) */ + ALfloat a1, a2; /* Transfer function coefficients "a" (denominator; a0 is + * pre-applied). */ } BiquadState; /* Currently only a C-based filter process method is implemented. */ #define BiquadState_process BiquadState_processC @@ -63,10 +63,8 @@ inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) inline void BiquadState_clear(BiquadState *filter) { - filter->x[0] = 0.0f; - filter->x[1] = 0.0f; - filter->y[0] = 0.0f; - filter->y[1] = 0.0f; + filter->z1 = 0.0f; + filter->z2 = 0.0f; } /** @@ -97,21 +95,17 @@ inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); -inline void BiquadState_processPassthru(BiquadState *filter, const ALfloat *restrict src, ALsizei numsamples) +inline void BiquadState_processPassthru(BiquadState *filter, ALsizei numsamples) { - if(numsamples >= 2) + if(LIKELY(numsamples >= 2)) { - filter->x[1] = src[numsamples-2]; - filter->x[0] = src[numsamples-1]; - filter->y[1] = src[numsamples-2]; - filter->y[0] = src[numsamples-1]; + filter->z1 = 0.0f; + filter->z2 = 0.0f; } else if(numsamples == 1) { - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = src[0]; + filter->z1 = filter->z2; + filter->z2 = 0.0f; } } diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index 4d757be7..fe59977b 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -9,7 +9,7 @@ extern inline void BiquadState_clear(BiquadState *filter); extern inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src); -extern inline void BiquadState_processPassthru(BiquadState *filter, const ALfloat *restrict src, ALsizei numsamples); +extern inline void BiquadState_processPassthru(BiquadState *filter, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); @@ -96,38 +96,43 @@ void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, A void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { - ALsizei i; if(LIKELY(numsamples > 1)) { - ALfloat x0 = filter->x[0]; - ALfloat x1 = filter->x[1]; - ALfloat y0 = filter->y[0]; - ALfloat y1 = filter->y[1]; + const ALfloat a1 = filter->a1; + const ALfloat a2 = filter->a2; + const ALfloat b0 = filter->b0; + const ALfloat b1 = filter->b1; + const ALfloat b2 = filter->b2; + ALfloat z1 = filter->z1; + ALfloat z2 = filter->z2; + ALsizei i; + /* Processing loop is transposed direct form II. This requires less + * storage versus direct form I (only two delay components, instead of + * a four-sample history; the last two inputs and outputs), and works + * better for floating-point which favors summing similarly-sized + * values while being less bothered by overflow. + * + * See: http://www.earlevel.com/main/2003/02/28/biquads/ + */ for(i = 0;i < numsamples;i++) { - dst[i] = filter->b0* src[i] + - filter->b1*x0 + filter->b2*x1 - - filter->a1*y0 - filter->a2*y1; - y1 = y0; y0 = dst[i]; - x1 = x0; x0 = src[i]; + ALfloat input = src[i]; + ALfloat output = input*b0 + z1; + z1 = input*b1 - output*a1 + z2; + z2 = input*b2 - output*a2; + dst[i] = output; } - filter->x[0] = x0; - filter->x[1] = x1; - filter->y[0] = y0; - filter->y[1] = y1; + filter->z1 = z1; + filter->z2 = z2; } else if(numsamples == 1) { - dst[0] = filter->b0 * src[0] + - filter->b1 * filter->x[0] + - filter->b2 * filter->x[1] - - filter->a1 * filter->y[0] - - filter->a2 * filter->y[1]; - filter->x[1] = filter->x[0]; - filter->x[0] = src[0]; - filter->y[1] = filter->y[0]; - filter->y[0] = dst[0]; + ALfloat input = *src; + ALfloat output = input*filter->b0 + filter->z1; + filter->z1 = input*filter->b1 - output*filter->a1 + filter->z2; + filter->z2 = input*filter->b2 - output*filter->a2; + *dst = output; } } diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index d01ca781..82d1ce72 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -271,16 +271,16 @@ static const ALfloat *DoFilters(BiquadState *lpfilter, BiquadState *hpfilter, switch(type) { case AF_None: - BiquadState_processPassthru(lpfilter, src, numsamples); - BiquadState_processPassthru(hpfilter, src, numsamples); + BiquadState_processPassthru(lpfilter, numsamples); + BiquadState_processPassthru(hpfilter, numsamples); break; case AF_LowPass: BiquadState_process(lpfilter, dst, src, numsamples); - BiquadState_processPassthru(hpfilter, dst, numsamples); + BiquadState_processPassthru(hpfilter, numsamples); return dst; case AF_HighPass: - BiquadState_processPassthru(lpfilter, src, numsamples); + BiquadState_processPassthru(lpfilter, numsamples); BiquadState_process(hpfilter, dst, src, numsamples); return dst; -- cgit v1.2.3 From b1fe40586192dc15f92d0476c85e9f9daa2a31f0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 3 Apr 2018 11:21:15 -0700 Subject: Improve ordering of channel processing in makehrtf --- utils/makehrtf.c | 113 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index 28c33b87..e19c77c9 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -2194,16 +2194,16 @@ static void DiffuseFieldEqualize(const uint channels, const uint m, const double { uint ti, fi, ei, ai, i; - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) + { for(i = 0;i < m;i++) azd->mIrs[ti][i] /= dfa[(ti * m) + i]; } @@ -2232,16 +2232,16 @@ static void ReconstructHrirs(const HrirDataT *hData) count = pcdone = lastpc = 0; printf("%3d%% done.", pcdone); fflush(stdout); - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) + { MinimumPhase(n, azd->mIrs[ti], h); FftInverse(n, h, h); for(i = 0;i < hData->mIrPoints;i++) @@ -2270,18 +2270,16 @@ static void ResampleHrirs(const uint rate, HrirDataT *hData) ResamplerT rs; ResamplerSetup(&rs, hData->mIrRate, rate); - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = hData->mFds[fi].mEvStart;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) ResamplerRun(&rs, n, azd->mIrs[ti], n, azd->mIrs[ti]); - } } } } @@ -2313,13 +2311,14 @@ static void SynthesizeOnsets(HrirDataT *hData) uint ti, fi, oi, ai, ei, a0, a1; double t, of, af; - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + if(hData->mFds[fi].mEvStart <= 0) + continue; + oi = hData->mFds[fi].mEvStart; + + for(ti = 0;ti < channels;ti++) { - if(hData->mFds[fi].mEvStart <= 0) - continue; - oi = hData->mFds[fi].mEvStart; t = 0.0; for(ai = 0;ai < hData->mFds[fi].mEvs[oi].mAzCount;ai++) t += hData->mFds[fi].mEvs[oi].mAzs[ai].mDelays[ti]; @@ -2330,7 +2329,12 @@ static void SynthesizeOnsets(HrirDataT *hData) for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { CalcAzIndices(hData, fi, oi, hData->mFds[fi].mEvs[ei].mAzs[ai].mAzimuth, &a0, &a1, &af); - hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] = Lerp(hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti], Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mDelays[ti], hData->mFds[fi].mEvs[oi].mAzs[a1].mDelays[ti], af), of); + hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] = Lerp( + hData->mFds[fi].mEvs[0].mAzs[0].mDelays[ti], + Lerp(hData->mFds[fi].mEvs[oi].mAzs[a0].mDelays[ti], + hData->mFds[fi].mEvs[oi].mAzs[a1].mDelays[ti], af), + of + ); } } } @@ -2421,16 +2425,16 @@ static void NormalizeHrirs(const HrirDataT *hData) uint ti, fi, ei, ai, i; double maxLevel = 0.0; - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) + { for(i = 0;i < n;i++) maxLevel = fmax(fabs(azd->mIrs[ti][i]), maxLevel); } @@ -2438,16 +2442,16 @@ static void NormalizeHrirs(const HrirDataT *hData) } } maxLevel = 1.01 * maxLevel; - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) + { for(i = 0;i < n;i++) azd->mIrs[ti][i] /= maxLevel; } @@ -2481,16 +2485,16 @@ static void CalculateHrtds(const HeadModelT model, const double radius, HrirData if(model == HM_DATASET) { - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) + for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) { - for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) - { - HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + HrirAzT *azd = &hData->mFds[fi].mEvs[ei].mAzs[ai]; + for(ti = 0;ti < channels;ti++) + { t = azd->mDelays[ti] * radius / hData->mRadius; azd->mDelays[ti] = t; maxHrtd = fmax(t, maxHrtd); @@ -2502,18 +2506,18 @@ static void CalculateHrtds(const HeadModelT model, const double radius, HrirData } else { - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) + HrirEvT *evd = &hData->mFds[fi].mEvs[ei]; + + for(ai = 0;ai < evd->mAzCount;ai++) { - HrirEvT *evd = &hData->mFds[fi].mEvs[ei]; + HrirAzT *azd = &evd->mAzs[ai]; - for(ai = 0;ai < evd->mAzCount;ai++) + for(ti = 0;ti < channels;ti++) { - HrirAzT *azd = &evd->mAzs[ai]; - t = CalcLTD(evd->mElevation, azd->mAzimuth, radius, hData->mFds[fi].mDistance); azd->mDelays[ti] = t; maxHrtd = fmax(t, maxHrtd); @@ -2523,11 +2527,11 @@ static void CalculateHrtds(const HeadModelT model, const double radius, HrirData } } } - for(ti = 0;ti < channels;ti++) + for(fi = 0;fi < hData->mFdCount;fi++) { - for(fi = 0;fi < hData->mFdCount;fi++) + for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) { - for(ei = 0;ei < hData->mFds[fi].mEvCount;ei++) + for(ti = 0;ti < channels;ti++) { for(ai = 0;ai < hData->mFds[fi].mEvs[ei].mAzCount;ai++) hData->mFds[fi].mEvs[ei].mAzs[ai].mDelays[ti] -= minHrtd; @@ -2618,8 +2622,7 @@ static void FreeHrirData(HrirDataT *hData) { if(hData->mFds[0].mEvs[0].mAzs) { - if(hData->mFds[0].mEvs[0].mAzs[0].mIrs[0] != NULL) - free(hData->mFds[0].mEvs[0].mAzs[0].mIrs[0]); + free(hData->mFds[0].mEvs[0].mAzs[0].mIrs[0]); free(hData->mFds[0].mEvs[0].mAzs); } free(hData->mFds[0].mEvs); -- cgit v1.2.3 From 9c5307a48a58959a564be1999b119a87b7cdb8e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 4 Apr 2018 18:07:46 -0700 Subject: Rename BiquadState to BiquadFilter --- Alc/ALu.c | 24 ++++++++++++------------ Alc/effects/distortion.c | 19 +++++++++---------- Alc/effects/echo.c | 10 +++++----- Alc/effects/equalizer.c | 28 ++++++++++++++-------------- Alc/effects/modulator.c | 8 ++++---- Alc/effects/reverb.c | 24 ++++++++++++------------ Alc/filters/defs.h | 16 ++++++++-------- Alc/filters/filter.c | 10 +++++----- Alc/mixvoice.c | 18 +++++++++--------- OpenAL32/Include/alu.h | 8 ++++---- 10 files changed, 82 insertions(+), 83 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 51150cd7..8eda3094 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1017,20 +1017,20 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo voice->Direct.FilterType = AF_None; if(gainHF != 1.0f) voice->Direct.FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Direct.FilterType |= AF_HighPass; - BiquadState_setParams( + BiquadFilter_setParams( &voice->Direct.Params[0].LowPass, BiquadType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - BiquadState_setParams( + BiquadFilter_setParams( &voice->Direct.Params[0].HighPass, BiquadType_LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - BiquadState_copyParams(&voice->Direct.Params[c].LowPass, - &voice->Direct.Params[0].LowPass); - BiquadState_copyParams(&voice->Direct.Params[c].HighPass, - &voice->Direct.Params[0].HighPass); + BiquadFilter_copyParams(&voice->Direct.Params[c].LowPass, + &voice->Direct.Params[0].LowPass); + BiquadFilter_copyParams(&voice->Direct.Params[c].HighPass, + &voice->Direct.Params[0].HighPass); } } for(i = 0;i < NumSends;i++) @@ -1043,20 +1043,20 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo voice->Send[i].FilterType = AF_None; if(gainHF != 1.0f) voice->Send[i].FilterType |= AF_LowPass; if(gainLF != 1.0f) voice->Send[i].FilterType |= AF_HighPass; - BiquadState_setParams( + BiquadFilter_setParams( &voice->Send[i].Params[0].LowPass, BiquadType_HighShelf, gainHF, hfScale, calc_rcpQ_from_slope(gainHF, 1.0f) ); - BiquadState_setParams( + BiquadFilter_setParams( &voice->Send[i].Params[0].HighPass, BiquadType_LowShelf, gainLF, lfScale, calc_rcpQ_from_slope(gainLF, 1.0f) ); for(c = 1;c < num_channels;c++) { - BiquadState_copyParams(&voice->Send[i].Params[c].LowPass, - &voice->Send[i].Params[0].LowPass); - BiquadState_copyParams(&voice->Send[i].Params[c].HighPass, - &voice->Send[i].Params[0].HighPass); + BiquadFilter_copyParams(&voice->Send[i].Params[c].LowPass, + &voice->Send[i].Params[0].LowPass); + BiquadFilter_copyParams(&voice->Send[i].Params[c].HighPass, + &voice->Send[i].Params[0].HighPass); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index aa06a0a3..f4e9969c 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -37,8 +37,8 @@ typedef struct ALdistortionState { ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ - BiquadState lowpass; - BiquadState bandpass; + BiquadFilter lowpass; + BiquadFilter bandpass; ALfloat attenuation; ALfloat edge_coeff; @@ -58,9 +58,6 @@ static void ALdistortionState_Construct(ALdistortionState *state) { ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); SET_VTABLE2(ALdistortionState, ALeffectState, state); - - BiquadState_clear(&state->lowpass); - BiquadState_clear(&state->bandpass); } static ALvoid ALdistortionState_Destruct(ALdistortionState *state) @@ -68,8 +65,10 @@ static ALvoid ALdistortionState_Destruct(ALdistortionState *state) ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); } -static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device)) +static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device)) { + BiquadFilter_clear(&state->lowpass); + BiquadFilter_clear(&state->bandpass); return AL_TRUE; } @@ -93,14 +92,14 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex /* Multiply sampling frequency by the amount of oversampling done during * processing. */ - BiquadState_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, + BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); cutoff = props->Distortion.EQCenter; /* Convert bandwidth in Hz to octaves. */ bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f); - BiquadState_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, + BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f, cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) ); @@ -136,7 +135,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample * (which is fortunately first step of distortion). So combine three * operations into the one. */ - BiquadState_process(&state->lowpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo); /* Second step, do distortion using waveshaper function to emulate * signal processing during tube overdriving. Three steps of @@ -155,7 +154,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei Sample } /* Third step, do bandpass filtering of distorted signal. */ - BiquadState_process(&state->bandpass, buffer[1], buffer[0], todo); + BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo); todo >>= 2; for(k = 0;k < NumChannels;k++) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 282aa1d7..a98ed933 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -52,7 +52,7 @@ typedef struct ALechoState { ALfloat FeedGain; - BiquadState Filter; + BiquadFilter Filter; } ALechoState; static ALvoid ALechoState_Destruct(ALechoState *state); @@ -76,7 +76,7 @@ static void ALechoState_Construct(ALechoState *state) state->Tap[1].delay = 0; state->Offset = 0; - BiquadState_clear(&state->Filter); + BiquadFilter_clear(&state->Filter); } static ALvoid ALechoState_Destruct(ALechoState *state) @@ -135,9 +135,9 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, state->FeedGain = props->Echo.Feedback; gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */ - BiquadState_setParams(&state->Filter, BiquadType_HighShelf, - gainhf, LOWPASSFREQREF/frequency, - calc_rcpQ_from_slope(gainhf, 1.0f)); + BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf, + gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f) + ); /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 3174511a..8ff56fb5 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -81,7 +81,7 @@ typedef struct ALequalizerState { ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ - BiquadState filter[4]; + BiquadFilter filter[4]; } Chans[MAX_EFFECT_CHANNELS]; ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; @@ -114,7 +114,7 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevic for(i = 0; i < MAX_EFFECT_CHANNELS;i++) { for(j = 0;j < 4;j++) - BiquadState_clear(&state->Chans[i].filter[j]); + BiquadFilter_clear(&state->Chans[i].filter[j]); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; } @@ -140,13 +140,13 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext */ gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */ f0norm = props->Equalizer.LowCutoff/frequency; - BiquadState_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, + BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); gain = maxf(props->Equalizer.Mid1Gain, 0.0625f); f0norm = props->Equalizer.Mid1Center/frequency; - BiquadState_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, + BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid1Width ) @@ -154,7 +154,7 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(props->Equalizer.Mid2Gain, 0.0625f); f0norm = props->Equalizer.Mid2Center/frequency; - BiquadState_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, + BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking, gain, f0norm, calc_rcpQ_from_bandwidth( f0norm, props->Equalizer.Mid2Width ) @@ -162,17 +162,17 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f); f0norm = props->Equalizer.HighCutoff/frequency; - BiquadState_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, + BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf, gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f) ); /* Copy the filter coefficients for the other input channels. */ for(i = 1;i < MAX_EFFECT_CHANNELS;i++) { - BiquadState_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); - BiquadState_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); - BiquadState_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); - BiquadState_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); + BiquadFilter_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]); + BiquadFilter_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]); + BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); + BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); } } @@ -183,10 +183,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadState_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); - BiquadState_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); - BiquadState_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); - BiquadState_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo); + BiquadFilter_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo); MixSamples(temps[3], NumChannels, SamplesOut, state->Chans[c].CurrentGains, state->Chans[c].TargetGains, diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7deb648d..f97f7572 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -43,7 +43,7 @@ typedef struct ALmodulatorState { alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES]; struct { - BiquadState Filter; + BiquadFilter Filter; ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; @@ -117,7 +117,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevic ALsizei i, j; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - BiquadState_clear(&state->Chans[i].Filter); + BiquadFilter_clear(&state->Chans[i].Filter); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; } @@ -151,7 +151,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->Chans[0].Filter.a1 = -a; state->Chans[0].Filter.a2 = 0.0f; for(i = 1;i < MAX_EFFECT_CHANNELS;i++) - BiquadState_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); + BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; @@ -178,7 +178,7 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadState_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); + BiquadFilter_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); for(i = 0;i < td;i++) temps[1][i] = temps[0][i] * modsamples[i]; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 831e4a3a..9fc65a48 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -289,8 +289,8 @@ typedef struct ALreverbState { /* Master effect filters */ struct { - BiquadState Lp; - BiquadState Hp; + BiquadFilter Lp; + BiquadFilter Hp; } Filter[NUM_LINES]; /* Core delay line (early reflections and late reverb tap from this). */ @@ -347,8 +347,8 @@ static void ALreverbState_Construct(ALreverbState *state) for(i = 0;i < NUM_LINES;i++) { - BiquadState_clear(&state->Filter[i].Lp); - BiquadState_clear(&state->Filter[i].Hp); + BiquadFilter_clear(&state->Filter[i].Lp); + BiquadFilter_clear(&state->Filter[i].Hp); } state->Delay.Mask = 0; @@ -1156,16 +1156,16 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); - BiquadState_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, - calc_rcpQ_from_slope(gainhf, 1.0f)); + BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, + calc_rcpQ_from_slope(gainhf, 1.0f)); lf0norm = props->Reverb.LFReference / frequency; gainlf = maxf(props->Reverb.GainLF, 0.001f); - BiquadState_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, - calc_rcpQ_from_slope(gainlf, 1.0f)); + BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, + calc_rcpQ_from_slope(gainlf, 1.0f)); for(i = 1;i < NUM_LINES;i++) { - BiquadState_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); - BiquadState_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); + BiquadFilter_copyParams(&State->Filter[i].Lp, &State->Filter[0].Lp); + BiquadFilter_copyParams(&State->Filter[i].Hp, &State->Filter[0].Hp); } /* Update the main effect delay and associated taps. */ @@ -1547,8 +1547,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Band-pass the incoming samples. Use the early output lines for * temp storage. */ - BiquadState_process(&State->Filter[c].Lp, early[0], afmt[c], todo); - BiquadState_process(&State->Filter[c].Hp, early[1], early[0], todo); + BiquadFilter_process(&State->Filter[c].Lp, early[0], afmt[c], todo); + BiquadFilter_process(&State->Filter[c].Hp, early[1], early[0], todo); /* Feed the initial delay line. */ DelayLineIn(&State->Delay, State->Offset, c, early[1], todo); diff --git a/Alc/filters/defs.h b/Alc/filters/defs.h index 8257cec7..133a85eb 100644 --- a/Alc/filters/defs.h +++ b/Alc/filters/defs.h @@ -30,14 +30,14 @@ typedef enum BiquadType { BiquadType_BandPass, } BiquadType; -typedef struct BiquadState { +typedef struct BiquadFilter { ALfloat z1, z2; /* Last two delayed components for direct form II. */ ALfloat b0, b1, b2; /* Transfer function coefficients "b" (numerator) */ ALfloat a1, a2; /* Transfer function coefficients "a" (denominator; a0 is * pre-applied). */ -} BiquadState; +} BiquadFilter; /* Currently only a C-based filter process method is implemented. */ -#define BiquadState_process BiquadState_processC +#define BiquadFilter_process BiquadFilter_processC /** * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the @@ -61,7 +61,7 @@ inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth) return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); } -inline void BiquadState_clear(BiquadState *filter) +inline void BiquadFilter_clear(BiquadFilter *filter) { filter->z1 = 0.0f; filter->z2 = 0.0f; @@ -82,9 +82,9 @@ inline void BiquadState_clear(BiquadState *filter) * band. Can be generated from calc_rcpQ_from_slope or * calc_rcpQ_from_bandwidth depending on the available data. */ -void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); +void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ); -inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src) +inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src) { dst->b0 = src->b0; dst->b1 = src->b1; @@ -93,9 +93,9 @@ inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState dst->a2 = src->a2; } -void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); +void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples); -inline void BiquadState_processPassthru(BiquadState *filter, ALsizei numsamples) +inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples) { if(LIKELY(numsamples >= 2)) { diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index fe59977b..65fb08e7 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -7,14 +7,14 @@ #include "alMain.h" #include "defs.h" -extern inline void BiquadState_clear(BiquadState *filter); -extern inline void BiquadState_copyParams(BiquadState *restrict dst, const BiquadState *restrict src); -extern inline void BiquadState_processPassthru(BiquadState *filter, ALsizei numsamples); +extern inline void BiquadFilter_clear(BiquadFilter *filter); +extern inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src); +extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples); extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth); -void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) +void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ) { ALfloat alpha, sqrtgain_alpha_2; ALfloat w0, sin_w0, cos_w0; @@ -94,7 +94,7 @@ void BiquadState_setParams(BiquadState *filter, BiquadType type, ALfloat gain, A } -void BiquadState_processC(BiquadState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) +void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { if(LIKELY(numsamples > 1)) { diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 82d1ce72..2d935ce5 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -263,7 +263,7 @@ static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint } -static const ALfloat *DoFilters(BiquadState *lpfilter, BiquadState *hpfilter, +static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples, enum ActiveFilters type) { @@ -271,17 +271,17 @@ static const ALfloat *DoFilters(BiquadState *lpfilter, BiquadState *hpfilter, switch(type) { case AF_None: - BiquadState_processPassthru(lpfilter, numsamples); - BiquadState_processPassthru(hpfilter, numsamples); + BiquadFilter_passthru(lpfilter, numsamples); + BiquadFilter_passthru(hpfilter, numsamples); break; case AF_LowPass: - BiquadState_process(lpfilter, dst, src, numsamples); - BiquadState_processPassthru(hpfilter, numsamples); + BiquadFilter_process(lpfilter, dst, src, numsamples); + BiquadFilter_passthru(hpfilter, numsamples); return dst; case AF_HighPass: - BiquadState_processPassthru(lpfilter, numsamples); - BiquadState_process(hpfilter, dst, src, numsamples); + BiquadFilter_passthru(lpfilter, numsamples); + BiquadFilter_process(hpfilter, dst, src, numsamples); return dst; case AF_BandPass: @@ -290,8 +290,8 @@ static const ALfloat *DoFilters(BiquadState *lpfilter, BiquadState *hpfilter, ALfloat temp[256]; ALsizei todo = mini(256, numsamples-i); - BiquadState_process(lpfilter, temp, src+i, todo); - BiquadState_process(hpfilter, dst+i, temp, todo); + BiquadFilter_process(lpfilter, temp, src+i, todo); + BiquadFilter_process(hpfilter, dst+i, temp, todo); i += todo; } return dst; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index cf1560fc..b977613c 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -153,8 +153,8 @@ typedef struct MixHrtfParams { typedef struct DirectParams { - BiquadState LowPass; - BiquadState HighPass; + BiquadFilter LowPass; + BiquadFilter HighPass; NfcFilter NFCtrlFilter; @@ -171,8 +171,8 @@ typedef struct DirectParams { } DirectParams; typedef struct SendParams { - BiquadState LowPass; - BiquadState HighPass; + BiquadFilter LowPass; + BiquadFilter HighPass; struct { ALfloat Current[MAX_OUTPUT_CHANNELS]; -- cgit v1.2.3 From 5b82dd873326a97ab8398e47164bc39fdec27542 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 14 Apr 2018 13:02:21 -0700 Subject: Update .gitignore --- .gitignore | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 9aa081c6..de57ef22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -build -winbuild -win64build -include/SLES -include/sndio.h -include/sys +build*/ +winbuild/ +win64build/ openal-soft.kdev4 +.kdev4/ -- cgit v1.2.3 From 795ed65797016a286c38587f772d824afda493a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Apr 2018 19:01:38 -0700 Subject: Preliminary ChangeLog update --- ChangeLog | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/ChangeLog b/ChangeLog index 5300be12..7a730262 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,53 @@ +openal-soft-1.19.0: + + Implemented the ALC_SOFT_device_clock extension. + + Added support fot 24-bit, dual-ear HRTF data sets. The built-in data set + has been updated to 24-bit. + + Added a 24- to 48-point band-limited Sinc resampler. + + Added an SDL2 playback backend. Disabled by default to avoid a dependency + on SDL2. + + Improved the efficiency of the band-limited Sinc resampler. + + Improved the Sinc resampler's transition band to avoid over-attenuating + higher frequencies. + + Replaced the 4-point Sinc resampler with a more efficient cubic resampler. + + Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. + + Fixed compiling on NetBSD. + + Improved the performance and quality of the Chorus effect. + + Removed the reverb effect's modulation stage. Due to the lack of reference + for its strength. + + Improved AL call error logging with contextualized messages. + + Improved the efficiency of object ID lookups. + + Improved efficienty of internal voice/source synchronization. + + Fixed the reverb effect's density scale. + + Fixed the reverb effect's panning parameters. + + Increased the number of virtual channels for decoding Ambisonics to HRTF + output. + + Implemented the Pitch Shifter effect. + + Renamed the MMDevAPI backend to WASAPI. + + Fixed using the WASAPI backend with certain games, which caused odd COM + initialization errors. + + Improved the performance of some filter operations. + openal-soft-1.18.2: Fixed resetting the FPU rounding mode after certain function calls on -- cgit v1.2.3 From e619b641750a00e188a067376ffebdc8d24da126 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Apr 2018 18:51:01 -0700 Subject: Don't minimize the HRTF per-response delay The reverts both fa9ab9af7cb559ff9ecc1846f2996265bfbea1ec and 79604c3c0e0f3f71832a09348cc273a38882cc3e. As helpful as it was for the high frequencies, the overall response's gain suffered. --- Alc/hrtf.c | 14 +++++--------- Alc/panning.c | 4 ++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index e0323146..3523bf34 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -204,7 +204,6 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N BandSplitter splitter; ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; - ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length = 0; ALsizei i, c, b; @@ -229,6 +228,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Calculate indices for left and right channels. */ idx[c] = evoffset + azidx; + + min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } memset(temps, 0, sizeof(temps)); @@ -236,12 +237,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N for(c = 0;c < AmbiCount;c++) { const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize]; - const ALsizei res_delay = mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1]); - ALsizei ldelay = Hrtf->delays[idx[c]][0] - res_delay; - ALsizei rdelay = Hrtf->delays[idx[c]][1] - res_delay; - - min_delay = mini(min_delay, res_delay); - max_delay = maxi(max_delay, res_delay); + ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; + ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; max_length = maxi(max_length, mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) @@ -311,8 +308,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N max_length += MOD_IR_SIZE-1; max_length -= max_length%MOD_IR_SIZE; - TRACE("Skipped delay min: %d, max: %d, new FIR length: %d\n", min_delay, max_delay, - max_length); + TRACE("Skipped delay: %d, new FIR length: %d\n", min_delay, max_length); state->IrSize = max_length; #undef NUM_BANDS } diff --git a/Alc/panning.c b/Alc/panning.c index 7ed27852..774fa4b1 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -872,9 +872,9 @@ static void InitHrtfPanning(ALCdevice *device) { 5.55555556e-02f, 0.00000000e+00f, -1.23717915e-01f, 0.00000000e+00f, 0.00000000e+00f, 0.00000000e+00f }, }; static const ALfloat AmbiOrderHFGainFOA[MAX_AMBI_ORDER+1] = { - 1.00000000e+00f, 5.77350269e-01f + 3.00000000e+00f, 1.73205081e+00f }, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = { - 9.80580676e-01f, 7.59554525e-01f, 3.92232270e-01f + 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f }; static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; -- cgit v1.2.3 From 09194fd4886d81ca28f88760e8ae4efad368227e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Apr 2018 21:27:47 -0700 Subject: Accumulate the B-Format HRTF responses using doubles The final result is still truncated to single-precision float, but this should keep the responses more stable as it accumulates the various inputs. --- Alc/hrtf.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 3523bf34..fb2e0068 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -202,6 +202,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N */ #define NUM_BANDS 2 BandSplitter splitter; + ALdouble (*tmpres)[HRIR_LENGTH][2]; ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALfloat temps[3][HRIR_LENGTH]; @@ -232,6 +233,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } + tmpres = al_calloc(16, NumChannels * sizeof(*tmpres)); + memset(temps, 0, sizeof(temps)); bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate); for(c = 0;c < AmbiCount;c++) @@ -248,13 +251,14 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N { for(i = 0;i < NumChannels;++i) { - ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; + ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)floor(sqrt(i))] * + AmbiMatrix[c][i]; ALsizei lidx = ldelay, ridx = rdelay; ALsizei j = 0; while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) { - state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][i] * hfgain; - state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][i] * hfgain; + tmpres[i][lidx++][0] += fir[j][0] * mult; + tmpres[i][ridx++][1] += fir[j][1] * mult; j++; } } @@ -273,12 +277,11 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; for(b = 0;b < NUM_BANDS;b++) { + ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); ALsizei lidx = ldelay; ALsizei j = 0; while(lidx < HRIR_LENGTH) - state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][i] * - hfgain; - hfgain = 1.0f; + tmpres[i][lidx++][0] += temps[b][j++] * mult; } } @@ -294,12 +297,11 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; for(b = 0;b < NUM_BANDS;b++) { + ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); ALsizei ridx = rdelay; ALsizei j = 0; while(ridx < HRIR_LENGTH) - state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][i] * - hfgain; - hfgain = 1.0f; + tmpres[i][ridx++][1] += temps[b][j++] * mult; } } } @@ -308,6 +310,19 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N max_length += MOD_IR_SIZE-1; max_length -= max_length%MOD_IR_SIZE; + for(i = 0;i < NumChannels;++i) + { + int idx; + for(idx = 0;idx < HRIR_LENGTH;idx++) + { + state->Chan[i].Coeffs[idx][0] = (ALfloat)tmpres[i][idx][0]; + state->Chan[i].Coeffs[idx][1] = (ALfloat)tmpres[i][idx][1]; + } + } + + al_free(tmpres); + tmpres = NULL; + TRACE("Skipped delay: %d, new FIR length: %d\n", min_delay, max_length); state->IrSize = max_length; #undef NUM_BANDS -- cgit v1.2.3 From 150586d7fef722da17b96697ca0c1f78b2d10eb4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Apr 2018 22:50:50 -0700 Subject: Add an ASSUME macro that requires a true condition --- Alc/mixer/mixer_c.c | 2 ++ Alc/mixer/mixer_neon.c | 2 ++ Alc/mixer/mixer_sse.c | 2 ++ OpenAL32/Include/alMain.h | 17 +++++++++++++++++ 4 files changed, 23 insertions(+) diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index e40c2cad..ee667671 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -65,6 +65,8 @@ const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restric ALsizei j_f, pi, i; ALfloat pf, r; + ASSUME(m > 0); + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 7f8dd1d4..e8a85f71 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -78,6 +78,8 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, float32x4_t r4; ALfloat pf; + ASSUME(m > 0); + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index c9615c25..5c181c75 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -24,6 +24,8 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr ALfloat pf; __m128 r4; + ASSUME(m > 0); + src += state->bsinc.l; for(i = 0;i < dstlen;i++) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 783a90de..77144a29 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -42,11 +42,28 @@ #ifdef __GNUC__ +/* LIKELY optimizes the case where the condition is true. The condition is not + * required to be true, but it can result in more optimal code for the true + * path at the expense of a less optimal false path. + */ #define LIKELY(x) __builtin_expect(!!(x), !0) +/* The opposite of LIKELY, optimizing the case where the condition is false. */ #define UNLIKELY(x) __builtin_expect(!!(x), 0) +/* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes + * undefined behavior. It's essentially an assert without actually checking the + * condition at run-time, allowing for stronger optimizations than LIKELY. + */ +#define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0) + #else + #define LIKELY(x) (!!(x)) #define UNLIKELY(x) (!!(x)) +#ifdef _MSC_VER +#define ASSUME __assume +#else +#define ASSUME(x) ((void)0) +#endif #endif #ifndef UINT64_MAX -- cgit v1.2.3 From f96a8fe369e317a6203bec5e814761fe8a12531e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Apr 2018 20:39:52 -0700 Subject: Add some ASSUME statements that ensure mixing at least 1 sample --- Alc/mixer/hrtf_inc.c | 9 +++++++++ Alc/mixer/mixer_c.c | 3 +++ Alc/mixer/mixer_neon.c | 5 +++++ Alc/mixer/mixer_sse.c | 4 ++++ Alc/mixer/mixer_sse2.c | 2 ++ Alc/mixer/mixer_sse41.c | 2 ++ 6 files changed, 25 insertions(+) diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c index ad0daa63..d6bd8042 100644 --- a/Alc/mixer/hrtf_inc.c +++ b/Alc/mixer/hrtf_inc.c @@ -27,6 +27,9 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat left, right; ALsizei i; + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + LeftOut += OutPos; RightOut += OutPos; for(i = 0;i < BufferSize;i++) @@ -65,6 +68,9 @@ void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat left, right; ALsizei i; + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + LeftOut += OutPos; RightOut += OutPos; for(i = 0;i < BufferSize;i++) @@ -100,6 +106,9 @@ void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat insample; ALsizei i; + ASSUME(IrSize >= 4); + ASSUME(BufferSize > 0); + for(i = 0;i < BufferSize;i++) { Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index ee667671..2ec108d7 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -123,6 +123,7 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[ ALfloat gain, delta, step; ALsizei c; + ASSUME(BufferSize > 0); delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) @@ -160,6 +161,8 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict { ALsizei c, i; + ASSUME(BufferSize > 0); + for(c = 0;c < InChans;c++) { ALfloat gain = Gains[c]; diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index e8a85f71..03468ffe 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -23,6 +23,8 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), int32x4_t frac4; ALsizei i; + ASSUME(numsamples > 0); + InitiatePositionArrays(frac, increment, frac_, pos_, 4); frac4 = vld1q_s32(frac_); @@ -79,6 +81,7 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, ALfloat pf; ASSUME(m > 0); + ASSUME(dstlen > 0); src += state->bsinc.l; for(i = 0;i < dstlen;i++) @@ -167,6 +170,7 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe float32x4_t gain4; ALsizei c; + ASSUME(BufferSize > 0); data = ASSUME_ALIGNED(data, 16); OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); @@ -239,6 +243,7 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restr float32x4_t gain4; ALsizei c; + ASSUME(BufferSize > 0); data = ASSUME_ALIGNED(data, 16); OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 5c181c75..c4852ca5 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -25,6 +25,7 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr __m128 r4; ASSUME(m > 0); + ASSUME(dstlen > 0); src += state->bsinc.l; for(i = 0;i < dstlen;i++) @@ -139,6 +140,7 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer __m128 gain4; ALsizei c; + ASSUME(BufferSize > 0); delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) @@ -210,6 +212,8 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restri __m128 gain4; ALsizei c; + ASSUME(BufferSize > 0); + for(c = 0;c < InChans;c++) { ALsizei pos = 0; diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index 19d07719..4aeb6fc4 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -40,6 +40,8 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), ALint pos; ALsizei i; + ASSUME(numsamples > 0); + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c index 85fd0f5e..98a3ef74 100644 --- a/Alc/mixer/mixer_sse41.c +++ b/Alc/mixer/mixer_sse41.c @@ -41,6 +41,8 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), ALint pos; ALsizei i; + ASSUME(numsamples > 0); + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); -- cgit v1.2.3 From 525b6fe1689de5aff6d4d4c0ac1c3e931d66c1b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Apr 2018 12:22:39 -0700 Subject: Clear ALSA's PCM handle after closing it --- Alc/backends/alsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 9fc36582..e0fdc070 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -1146,6 +1146,7 @@ error2: ll_ringbuffer_free(self->ring); self->ring = NULL; snd_pcm_close(self->pcmHandle); + self->pcmHandle = NULL; return ALC_INVALID_VALUE; } -- cgit v1.2.3 From 90b8d639f117d7e24ce3dd2f51e4f624830e3e5b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Apr 2018 18:24:27 -0700 Subject: Remove unnecessary undefs --- Alc/mixer/mixer_c.c | 1 - Alc/mixer/mixer_neon.c | 1 - Alc/mixer/mixer_sse.c | 1 - 3 files changed, 3 deletions(-) diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 2ec108d7..05b7932d 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -113,7 +113,6 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtfBlend MixHrtfBlend_C #define MixDirectHrtf MixDirectHrtf_C #include "hrtf_inc.c" -#undef MixHrtf void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 03468ffe..1413d1c1 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -159,7 +159,6 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtfBlend MixHrtfBlend_Neon #define MixDirectHrtf MixDirectHrtf_Neon #include "hrtf_inc.c" -#undef MixHrtf void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index c4852ca5..81dc0a34 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -129,7 +129,6 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], #define MixHrtfBlend MixHrtfBlend_SSE #define MixDirectHrtf MixDirectHrtf_SSE #include "hrtf_inc.c" -#undef MixHrtf void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], -- cgit v1.2.3 From 400ab8766c02e76bce4c989768a9cd2f6e330f49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Apr 2018 21:55:20 -0700 Subject: Adjust the stereo panning front gain This gives it a (more) precise -4.5dB gain drop for front-center panned sounds. --- Alc/panning.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 774fa4b1..50e5b530 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -383,8 +383,8 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp static const ChannelMap MonoCfg[1] = { { FrontCenter, { 1.0f } }, }, StereoCfg[2] = { - { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.77350269e-2f } }, - { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.77350269e-2f } }, + { FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 5.52305643e-2f } }, + { FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.52305643e-2f } }, }, QuadCfg[4] = { { BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } }, { FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } }, -- cgit v1.2.3 From a55c93e1f59dfadda64a63e4c1b0881ca34dbad8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Apr 2018 01:54:43 -0700 Subject: Improve ASSUME for Clang For some reason, the { if(!x)__builtin_unreachable(); } construct does not provide the same optimization opportunity for Clang (even though the condition being false would trigger undefined behavior by reaching unreachable code, it still performs checks and such for the condition potentially being false). Using __builtin_assume seems to work better. --- OpenAL32/Include/alMain.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 77144a29..48d8fb4a 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -40,6 +40,11 @@ #define SZFMT "%zu" #endif +#ifdef __has_builtin +#define HAS_BUILTIN __has_builtin +#else +#define HAS_BUILTIN(x) (0) +#endif #ifdef __GNUC__ /* LIKELY optimizes the case where the condition is true. The condition is not @@ -53,7 +58,11 @@ * undefined behavior. It's essentially an assert without actually checking the * condition at run-time, allowing for stronger optimizations than LIKELY. */ +#if HAS_BUILTIN(__builtin_assume) +#define ASSUME __builtin_assume +#else #define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0) +#endif #else -- cgit v1.2.3 From 4ee26f4ca3dc952dc9d7fdf58b735396b798df9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Apr 2018 02:44:01 -0700 Subject: Add some more ASSUME statements --- Alc/hrtf.c | 1 + Alc/mixer/mixer_c.c | 2 ++ Alc/mixer/mixer_neon.c | 2 ++ Alc/mixer/mixer_sse.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index fb2e0068..fe71800b 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -173,6 +173,7 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, idx[2] *= Hrtf->irSize; idx[3] *= Hrtf->irSize; + ASSUME(Hrtf->irSize >= MIN_IR_SIZE && (Hrtf->irSize%MOD_IR_SIZE) == 0); coeffs = ASSUME_ALIGNED(coeffs, 16); /* Calculate the blended HRIR coefficients. */ coeffs[0][0] = PassthruCoeff * (1.0f-dirfact); diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 05b7932d..84485206 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -122,6 +122,7 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[ ALfloat gain, delta, step; ALsizei c; + ASSUME(OutChans > 0); ASSUME(BufferSize > 0); delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; @@ -160,6 +161,7 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict { ALsizei c, i; + ASSUME(InChans > 0); ASSUME(BufferSize > 0); for(c = 0;c < InChans;c++) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 1413d1c1..1a5e8ee7 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -169,6 +169,7 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe float32x4_t gain4; ALsizei c; + ASSUME(OutChans > 0); ASSUME(BufferSize > 0); data = ASSUME_ALIGNED(data, 16); OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); @@ -242,6 +243,7 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restr float32x4_t gain4; ALsizei c; + ASSUME(InChans > 0); ASSUME(BufferSize > 0); data = ASSUME_ALIGNED(data, 16); OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 81dc0a34..a178477f 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -139,6 +139,7 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer __m128 gain4; ALsizei c; + ASSUME(OutChans > 0); ASSUME(BufferSize > 0); delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; @@ -211,6 +212,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restri __m128 gain4; ALsizei c; + ASSUME(InChans > 0); ASSUME(BufferSize > 0); for(c = 0;c < InChans;c++) -- cgit v1.2.3 From ace8e648509a1afa587a4e6c778e37a2e854e496 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Apr 2018 21:07:20 -0700 Subject: Only use fast float-to-int workarounds for x87 At least SSE and ARM have opcodes that handle float-to-int conversions well enough. Also, Clang doesn't inline lrintf, incurring function call overhead for what should be a single opcode. --- OpenAL32/Include/alMain.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 48d8fb4a..78dd01c5 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -230,6 +230,21 @@ inline size_t RoundUp(size_t value, size_t r) * mode. */ inline ALint fastf2i(ALfloat f) { +#if (defined(__i386__) && !defined(__SSE_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP == 0)) +/* If using the x87 instruction set, try to use more efficient float-to-int + * operations. The fistp instruction converts to integer efficiently enough, + * but it isn't IEEE-754-compliant because it uses the current rounding mode + * instead of always truncating -- the compiler will generate costly control + * word changes with it to get correct behavior. If supported, lrintf converts + * to integer using the current rounding mode, i.e. using fistp without control + * word changes (if nothing even better is available). As long as the rounding + * mode is set to round-to-zero ahead of time, and the call gets inlined, this + * works fine. + * + * Other instruction sets, like SSE and ARM, have opcodes that inherently do + * the right thing, and don't suffer from the same excessive performance + * degredation from float-to-int conversions. + */ #ifdef HAVE_LRINTF return lrintf(f); #elif defined(_MSC_VER) && defined(_M_IX86) @@ -240,6 +255,9 @@ inline ALint fastf2i(ALfloat f) #else return (ALint)f; #endif +#else + return (ALint)f; +#endif } -- cgit v1.2.3 From 9575eebac43c4401a1e82215e10700a01dd8be55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Apr 2018 23:23:46 -0700 Subject: Move the bnad-splitter filters to a separate source --- Alc/ALu.c | 1 + Alc/bformatdec.c | 102 +--------------------------------------------- Alc/bformatdec.h | 34 ---------------- Alc/filters/splitter.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++ Alc/filters/splitter.h | 40 ++++++++++++++++++ Alc/hrtf.c | 2 +- Alc/panning.c | 1 + CMakeLists.txt | 1 + 8 files changed, 152 insertions(+), 136 deletions(-) create mode 100644 Alc/filters/splitter.c create mode 100644 Alc/filters/splitter.h diff --git a/Alc/ALu.c b/Alc/ALu.c index 8eda3094..d8301f2b 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -39,6 +39,7 @@ #include "bformatdec.h" #include "static_assert.h" #include "ringbuffer.h" +#include "filters/splitter.h" #include "mixer/defs.h" #include "fpu_modes.h" diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 7ab315c3..dcde7d70 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -3,6 +3,7 @@ #include "bformatdec.h" #include "ambdec.h" +#include "filters/splitter.h" #include "alu.h" #include "bool.h" @@ -10,107 +11,6 @@ #include "almalloc.h" -void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) -{ - ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); - if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; - else - splitter->coeff = cw * -0.5f; - - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; -} - -void bandsplit_clear(BandSplitter *splitter) -{ - splitter->lp_z1 = 0.0f; - splitter->lp_z2 = 0.0f; - splitter->hp_z1 = 0.0f; -} - -void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, - const ALfloat *input, ALsizei count) -{ - ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; - ALfloat lp_z1, lp_z2, hp_z1; - ALsizei i; - - hp_coeff = splitter->coeff; - lp_coeff = splitter->coeff*0.5f + 0.5f; - lp_z1 = splitter->lp_z1; - lp_z2 = splitter->lp_z2; - hp_z1 = splitter->hp_z1; - for(i = 0;i < count;i++) - { - ALfloat in = input[i]; - - /* Low-pass sample processing. */ - d = (in - lp_z1) * lp_coeff; - lp_y = lp_z1 + d; - lp_z1 = lp_y + d; - - d = (lp_y - lp_z2) * lp_coeff; - lp_y = lp_z2 + d; - lp_z2 = lp_y + d; - - lpout[i] = lp_y; - - /* All-pass sample processing. */ - d = in - hp_coeff*hp_z1; - hp_y = hp_z1 + hp_coeff*d; - hp_z1 = d; - - /* High-pass generated from removing low-passed output. */ - hpout[i] = hp_y - lp_y; - } - splitter->lp_z1 = lp_z1; - splitter->lp_z2 = lp_z2; - splitter->hp_z1 = hp_z1; -} - - -void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) -{ - ALfloat w = f0norm * F_TAU; - ALfloat cw = cosf(w); - if(cw > FLT_EPSILON) - splitter->coeff = (sinf(w) - 1.0f) / cw; - else - splitter->coeff = cw * -0.5f; - - splitter->z1 = 0.0f; -} - -void splitterap_clear(SplitterAllpass *splitter) -{ - splitter->z1 = 0.0f; -} - -void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count) -{ - ALfloat coeff, d, x; - ALfloat z1; - ALsizei i; - - coeff = splitter->coeff; - z1 = splitter->z1; - for(i = 0;i < count;i++) - { - x = samples[i]; - - d = x - coeff*z1; - x = z1 + coeff*d; - z1 = d; - - samples[i] = x; - } - splitter->z1 = z1; -} - - /* NOTE: These are scale factors as applied to Ambisonics content. Decoder * coefficients should be divided by these values to get proper N3D scalings. */ diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h index a6ca2209..2d7d1d62 100644 --- a/Alc/bformatdec.h +++ b/Alc/bformatdec.h @@ -54,38 +54,4 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo); - -/* Band splitter. Splits a signal into two phase-matching frequency bands. */ -typedef struct BandSplitter { - ALfloat coeff; - ALfloat lp_z1; - ALfloat lp_z2; - ALfloat hp_z1; -} BandSplitter; - -void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); -void bandsplit_clear(BandSplitter *splitter); -void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, - const ALfloat *input, ALsizei count); - -/* The all-pass portion of the band splitter. Applies the same phase shift - * without splitting the signal. - */ -typedef struct SplitterAllpass { - ALfloat coeff; - ALfloat z1; -} SplitterAllpass; - -void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); -void splitterap_clear(SplitterAllpass *splitter); -void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count); - - -typedef struct FrontStablizer { - SplitterAllpass APFilter[MAX_OUTPUT_CHANNELS]; - BandSplitter LFilter, RFilter; - alignas(16) ALfloat LSplit[2][BUFFERSIZE]; - alignas(16) ALfloat RSplit[2][BUFFERSIZE]; -} FrontStablizer; - #endif /* BFORMATDEC_H */ diff --git a/Alc/filters/splitter.c b/Alc/filters/splitter.c new file mode 100644 index 00000000..524bcc1d --- /dev/null +++ b/Alc/filters/splitter.c @@ -0,0 +1,107 @@ + +#include "config.h" + +#include "splitter.h" + +#include "math_defs.h" + + +void bandsplit_init(BandSplitter *splitter, ALfloat f0norm) +{ + ALfloat w = f0norm * F_TAU; + ALfloat cw = cosf(w); + if(cw > FLT_EPSILON) + splitter->coeff = (sinf(w) - 1.0f) / cw; + else + splitter->coeff = cw * -0.5f; + + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +void bandsplit_clear(BandSplitter *splitter) +{ + splitter->lp_z1 = 0.0f; + splitter->lp_z2 = 0.0f; + splitter->hp_z1 = 0.0f; +} + +void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, + const ALfloat *input, ALsizei count) +{ + ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d; + ALfloat lp_z1, lp_z2, hp_z1; + ALsizei i; + + hp_coeff = splitter->coeff; + lp_coeff = splitter->coeff*0.5f + 0.5f; + lp_z1 = splitter->lp_z1; + lp_z2 = splitter->lp_z2; + hp_z1 = splitter->hp_z1; + for(i = 0;i < count;i++) + { + ALfloat in = input[i]; + + /* Low-pass sample processing. */ + d = (in - lp_z1) * lp_coeff; + lp_y = lp_z1 + d; + lp_z1 = lp_y + d; + + d = (lp_y - lp_z2) * lp_coeff; + lp_y = lp_z2 + d; + lp_z2 = lp_y + d; + + lpout[i] = lp_y; + + /* All-pass sample processing. */ + d = in - hp_coeff*hp_z1; + hp_y = hp_z1 + hp_coeff*d; + hp_z1 = d; + + /* High-pass generated from removing low-passed output. */ + hpout[i] = hp_y - lp_y; + } + splitter->lp_z1 = lp_z1; + splitter->lp_z2 = lp_z2; + splitter->hp_z1 = hp_z1; +} + + +void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm) +{ + ALfloat w = f0norm * F_TAU; + ALfloat cw = cosf(w); + if(cw > FLT_EPSILON) + splitter->coeff = (sinf(w) - 1.0f) / cw; + else + splitter->coeff = cw * -0.5f; + + splitter->z1 = 0.0f; +} + +void splitterap_clear(SplitterAllpass *splitter) +{ + splitter->z1 = 0.0f; +} + +void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count) +{ + ALfloat coeff, d, x; + ALfloat z1; + ALsizei i; + + coeff = splitter->coeff; + z1 = splitter->z1; + for(i = 0;i < count;i++) + { + x = samples[i]; + + d = x - coeff*z1; + x = z1 + coeff*d; + z1 = d; + + samples[i] = x; + } + splitter->z1 = z1; +} diff --git a/Alc/filters/splitter.h b/Alc/filters/splitter.h new file mode 100644 index 00000000..a788bc3e --- /dev/null +++ b/Alc/filters/splitter.h @@ -0,0 +1,40 @@ +#ifndef FILTER_SPLITTER_H +#define FILTER_SPLITTER_H + +#include "alMain.h" + + +/* Band splitter. Splits a signal into two phase-matching frequency bands. */ +typedef struct BandSplitter { + ALfloat coeff; + ALfloat lp_z1; + ALfloat lp_z2; + ALfloat hp_z1; +} BandSplitter; + +void bandsplit_init(BandSplitter *splitter, ALfloat f0norm); +void bandsplit_clear(BandSplitter *splitter); +void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout, + const ALfloat *input, ALsizei count); + +/* The all-pass portion of the band splitter. Applies the same phase shift + * without splitting the signal. + */ +typedef struct SplitterAllpass { + ALfloat coeff; + ALfloat z1; +} SplitterAllpass; + +void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm); +void splitterap_clear(SplitterAllpass *splitter); +void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count); + + +typedef struct FrontStablizer { + SplitterAllpass APFilter[MAX_OUTPUT_CHANNELS]; + BandSplitter LFilter, RFilter; + alignas(16) ALfloat LSplit[2][BUFFERSIZE]; + alignas(16) ALfloat RSplit[2][BUFFERSIZE]; +} FrontStablizer; + +#endif /* FILTER_SPLITTER_H */ diff --git a/Alc/hrtf.c b/Alc/hrtf.c index fe71800b..8db04d46 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -28,9 +28,9 @@ #include "alMain.h" #include "alSource.h" #include "alu.h" -#include "bformatdec.h" #include "hrtf.h" #include "alconfig.h" +#include "filters/splitter.h" #include "compat.h" #include "almalloc.h" diff --git a/Alc/panning.c b/Alc/panning.c index 50e5b530..5ff37d0a 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -33,6 +33,7 @@ #include "bool.h" #include "ambdec.h" #include "bformatdec.h" +#include "filters/splitter.h" #include "uhjfilter.h" #include "bs2b.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 69e5528c..5087fc2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -736,6 +736,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/effects/reverb.c Alc/filters/filter.c Alc/filters/nfc.c + Alc/filters/splitter.c Alc/helpers.c Alc/hrtf.c Alc/uhjfilter.c -- cgit v1.2.3 From ea8b52ee2cd3d5aebbb60c8ae9ab4ae13aadf24d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Apr 2018 23:42:04 -0700 Subject: Include header files in CMake's source lists --- CMakeLists.txt | 145 ++++++++++++++++++++++++------------- utils/alsoft-config/CMakeLists.txt | 6 +- 2 files changed, 99 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5087fc2f..6a4f8ff4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -699,52 +699,96 @@ IF(NOT HAVE_STDINT_H) ENDIF() -SET(COMMON_OBJS common/almalloc.c - common/atomic.c - common/rwlock.c - common/threads.c - common/uintmap.c +SET(COMMON_OBJS + common/align.h + common/almalloc.c + common/almalloc.h + common/atomic.c + common/atomic.h + common/bool.h + common/math_defs.h + common/rwlock.c + common/rwlock.h + common/static_assert.h + common/threads.c + common/threads.h + common/uintmap.c + common/uintmap.h ) -SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c - OpenAL32/alBuffer.c - OpenAL32/alEffect.c - OpenAL32/alError.c - OpenAL32/alExtension.c - OpenAL32/alFilter.c - OpenAL32/alListener.c - OpenAL32/alSource.c - OpenAL32/alState.c - OpenAL32/event.c - OpenAL32/sample_cvt.c +SET(OPENAL_OBJS + OpenAL32/Include/bs2b.h + OpenAL32/Include/alMain.h + OpenAL32/Include/alu.h + + OpenAL32/Include/alAuxEffectSlot.h + OpenAL32/alAuxEffectSlot.c + OpenAL32/Include/alBuffer.h + OpenAL32/alBuffer.c + OpenAL32/Include/alEffect.h + OpenAL32/alEffect.c + OpenAL32/Include/alError.h + OpenAL32/alError.c + OpenAL32/alExtension.c + OpenAL32/Include/alFilter.h + OpenAL32/alFilter.c + OpenAL32/Include/alListener.h + OpenAL32/alListener.c + OpenAL32/Include/alSource.h + OpenAL32/alSource.c + OpenAL32/alState.c + OpenAL32/event.c + OpenAL32/Include/sample_cvt.h + OpenAL32/sample_cvt.c ) -SET(ALC_OBJS Alc/ALc.c - Alc/ALu.c - Alc/alconfig.c - Alc/bs2b.c - Alc/converter.c - Alc/mastering.c - Alc/ringbuffer.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/modulator.c - Alc/effects/null.c - Alc/effects/pshifter.c - Alc/effects/reverb.c - Alc/filters/filter.c - Alc/filters/nfc.c - Alc/filters/splitter.c - Alc/helpers.c - Alc/hrtf.c - Alc/uhjfilter.c - Alc/ambdec.c - Alc/bformatdec.c - Alc/panning.c - Alc/mixvoice.c - Alc/mixer/mixer_c.c +SET(ALC_OBJS + Alc/ALc.c + Alc/ALu.c + Alc/alconfig.c + Alc/alconfig.h + Alc/bs2b.c + Alc/converter.c + Alc/converter.h + Alc/inprogext.h + Alc/mastering.c + Alc/mastering.h + Alc/ringbuffer.c + Alc/ringbuffer.h + 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/modulator.c + Alc/effects/null.c + Alc/effects/pshifter.c + Alc/effects/reverb.c + Alc/filters/defs.h + Alc/filters/filter.c + Alc/filters/nfc.c + Alc/filters/nfc.h + Alc/filters/splitter.c + Alc/filters/splitter.h + Alc/helpers.c + Alc/alstring.h + Alc/compat.h + Alc/cpu_caps.h + Alc/fpu_modes.h + Alc/logging.h + Alc/vector.h + Alc/hrtf.c + Alc/hrtf.h + Alc/uhjfilter.c + Alc/uhjfilter.h + Alc/ambdec.c + Alc/ambdec.h + Alc/bformatdec.c + Alc/bformatdec.h + Alc/panning.c + Alc/polymorphism.h + Alc/mixvoice.c + Alc/mixer/defs.h + Alc/mixer/mixer_c.c ) @@ -884,10 +928,11 @@ ENDIF() SET(BACKENDS "") SET(ALC_OBJS ${ALC_OBJS} - Alc/backends/base.c - # Default backends, always available - Alc/backends/loopback.c - Alc/backends/null.c + Alc/backends/base.c + Alc/backends/base.h + # Default backends, always available + Alc/backends/loopback.c + Alc/backends/null.c ) # Check ALSA backend @@ -1320,7 +1365,7 @@ ELSE() ENDIF() IF(WIN32 AND ALSOFT_BUILD_ROUTER) - ADD_LIBRARY(OpenAL SHARED router/router.c router/alc.c router/al.c) + ADD_LIBRARY(OpenAL SHARED router/router.c router/router.h router/alc.c router/al.c) TARGET_COMPILE_DEFINITIONS(OpenAL PRIVATE AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES ${CPP_DEFS}) TARGET_COMPILE_OPTIONS(OpenAL PRIVATE ${C_FLAGS}) @@ -1478,7 +1523,7 @@ IF(ALSOFT_UTILS) SET(MAKEHRTF_SRCS utils/makehrtf.c) IF(NOT HAVE_GETOPT) - SET(MAKEHRTF_SRCS ${MAKEHRTF_SRCS} utils/getopt.c) + SET(MAKEHRTF_SRCS ${MAKEHRTF_SRCS} utils/getopt.c utils/getopt.h) ENDIF() ADD_EXECUTABLE(makehrtf ${MAKEHRTF_SRCS}) TARGET_COMPILE_DEFINITIONS(makehrtf PRIVATE ${CPP_DEFS}) diff --git a/utils/alsoft-config/CMakeLists.txt b/utils/alsoft-config/CMakeLists.txt index 4911b9d8..67cc44c7 100644 --- a/utils/alsoft-config/CMakeLists.txt +++ b/utils/alsoft-config/CMakeLists.txt @@ -4,8 +4,10 @@ option(ALSOFT_NO_QT5 "Use Qt4 instead of Qt5 for alsoft-config" FALSE) include_directories("${alsoft-config_BINARY_DIR}") -set(alsoft-config_SRCS main.cpp - mainwindow.cpp +set(alsoft-config_SRCS + main.cpp + mainwindow.cpp + mainwindow.h ) set(alsoft-config_UIS mainwindow.ui) set(alsoft-config_MOCS mainwindow.h) -- cgit v1.2.3 From b51d30f84db4d09574d61081b56af85e2836d0fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Apr 2018 02:38:09 -0700 Subject: Change some if checks to asserts since they must be true --- Alc/ALu.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d8301f2b..d6b15183 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -305,26 +305,24 @@ static void ProcessUhj(ALCdevice *device, ALsizei SamplesToDo) { int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - if(LIKELY(lidx != -1 && ridx != -1)) - { - /* Encode to stereo-compatible 2-channel UHJ output. */ - EncodeUhj2(device->Uhj_Encoder, - device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], - device->Dry.Buffer, SamplesToDo - ); - } + assert(lidx != -1 && ridx != -1); + + /* Encode to stereo-compatible 2-channel UHJ output. */ + EncodeUhj2(device->Uhj_Encoder, + device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx], + device->Dry.Buffer, SamplesToDo + ); } static void ProcessBs2b(ALCdevice *device, ALsizei SamplesToDo) { int lidx = GetChannelIdxByName(&device->RealOut, FrontLeft); int ridx = GetChannelIdxByName(&device->RealOut, FrontRight); - if(LIKELY(lidx != -1 && ridx != -1)) - { - /* Apply binaural/crossfeed filter */ - bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], - device->RealOut.Buffer[ridx], SamplesToDo); - } + assert(lidx != -1 && ridx != -1); + + /* Apply binaural/crossfeed filter */ + bs2b_cross_feed(device->Bs2b, device->RealOut.Buffer[lidx], + device->RealOut.Buffer[ridx], SamplesToDo); } void aluSelectPostProcess(ALCdevice *device) -- cgit v1.2.3 From e10595df31d70f631617db05765e7279fa4185ff Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Apr 2018 02:39:14 -0700 Subject: Pre-calculate the squares of the UHJ filter coefficients --- Alc/uhjfilter.c | 84 +++++++++++++++++++++------------------------------------ 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index fd2d6567..eef477e3 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -9,44 +9,32 @@ #define MAX_UPDATE_SAMPLES 128 -static const ALfloat Filter1Coeff[4] = { - 0.6923878f, 0.9360654322959f, 0.9882295226860f, 0.9987488452737f +static const ALfloat Filter1CoeffSqr[4] = { + 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f }; -static const ALfloat Filter2Coeff[4] = { - 0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f +static const ALfloat Filter2CoeffSqr[4] = { + 0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f }; static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo) { + ALfloat x0 = state->x[0]; + ALfloat x1 = state->x[1]; + ALfloat y0 = state->y[0]; + ALfloat y1 = state->y[1]; ALsizei i; - if(LIKELY(todo > 1)) + for(i = 0;i < todo;i++) { - ALfloat x0 = state->x[0]; - ALfloat x1 = state->x[1]; - ALfloat y0 = state->y[0]; - ALfloat y1 = state->y[1]; - - for(i = 0;i < todo;i++) - { - dst[i] = aa*(src[i] + y1) - x1; - y1 = y0; y0 = dst[i]; - x1 = x0; x0 = src[i]; - } - - state->x[0] = x0; - state->x[1] = x1; - state->y[0] = y0; - state->y[1] = y1; - } - else if(todo == 1) - { - dst[0] = aa*(src[0] + state->y[1]) - state->x[1]; - state->x[1] = state->x[0]; - state->x[0] = src[0]; - state->y[1] = state->y[0]; - state->y[0] = dst[0]; + dst[i] = aa*(src[i] + y1) - x1; + y1 = y0; y0 = dst[i]; + x1 = x0; x0 = src[i]; } + + state->x[0] = x0; + state->x[1] = x1; + state->y[0] = y0; + state->y[1] = y1; } @@ -76,6 +64,8 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R ALfloat temp[2][MAX_UPDATE_SAMPLES]; ALsizei base, i; + ASSUME(SamplesToDo > 0); + for(base = 0;base < SamplesToDo;) { ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); @@ -83,19 +73,15 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R /* D = 0.6554516*Y */ for(i = 0;i < todo;i++) temp[0][i] = 0.6554516f*InSamples[2][base+i]; - allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], - Filter1Coeff[0]*Filter1Coeff[0], todo); - allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], - Filter1Coeff[1]*Filter1Coeff[1], todo); - allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], - Filter1Coeff[2]*Filter1Coeff[2], todo); + allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); /* NOTE: Filter1 requires a 1 sample delay for the final output, so * take the last processed sample from the previous run as the first * output sample. */ D[0] = enc->Filter1_Y[3].y[0]; - allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], - Filter1Coeff[3]*Filter1Coeff[3], todo); + allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); for(i = 1;i < todo;i++) D[i] = temp[0][i-1]; @@ -103,14 +89,10 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R for(i = 0;i < todo;i++) temp[0][i] = -0.3420201f*InSamples[0][base+i] + 0.5098604f*InSamples[1][base+i]; - allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], - Filter2Coeff[0]*Filter2Coeff[0], todo); - allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], - Filter2Coeff[1]*Filter2Coeff[1], todo); - allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], - Filter2Coeff[2]*Filter2Coeff[2], todo); - allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], - Filter2Coeff[3]*Filter2Coeff[3], todo); + allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo); + allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo); + allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo); + allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo); for(i = 0;i < todo;i++) D[i] += temp[0][i]; @@ -118,15 +100,11 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R for(i = 0;i < todo;i++) temp[0][i] = 0.9396926f*InSamples[0][base+i] + 0.1855740f*InSamples[1][base+i]; - allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], - Filter1Coeff[0]*Filter1Coeff[0], todo); - allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], - Filter1Coeff[1]*Filter1Coeff[1], todo); - allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], - Filter1Coeff[2]*Filter1Coeff[2], todo); + allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); + allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); + allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); S[0] = enc->Filter1_WX[3].y[0]; - allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], - Filter1Coeff[3]*Filter1Coeff[3], todo); + allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); for(i = 1;i < todo;i++) S[i] = temp[0][i-1]; -- cgit v1.2.3 From b3ba90f5fa533450e5335dc102c3f96fb7708d8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Apr 2018 03:34:29 -0700 Subject: Use transposed direct form 2 for the UHJ all-pass filters This has one extra multiply, but avoids two moves and uses almost half as much memory for the encoder state. --- Alc/uhjfilter.c | 28 ++++++++++++++-------------- Alc/uhjfilter.h | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.c index eef477e3..42b0bc40 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.c @@ -18,23 +18,20 @@ static const ALfloat Filter2CoeffSqr[4] = { static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo) { - ALfloat x0 = state->x[0]; - ALfloat x1 = state->x[1]; - ALfloat y0 = state->y[0]; - ALfloat y1 = state->y[1]; + ALfloat z1 = state->z[0]; + ALfloat z2 = state->z[1]; ALsizei i; for(i = 0;i < todo;i++) { - dst[i] = aa*(src[i] + y1) - x1; - y1 = y0; y0 = dst[i]; - x1 = x0; x0 = src[i]; + ALfloat input = src[i]; + ALfloat output = input*aa + z1; + z1 = z2; z2 = output*aa - input; + dst[i] = output; } - state->x[0] = x0; - state->x[1] = x1; - state->y[0] = y0; - state->y[1] = y1; + state->z[0] = z1; + state->z[1] = z2; } @@ -69,6 +66,7 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R for(base = 0;base < SamplesToDo;) { ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES); + ASSUME(todo > 0); /* D = 0.6554516*Y */ for(i = 0;i < todo;i++) @@ -76,14 +74,15 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); + allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); /* NOTE: Filter1 requires a 1 sample delay for the final output, so * take the last processed sample from the previous run as the first * output sample. */ - D[0] = enc->Filter1_Y[3].y[0]; - allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + D[0] = enc->LastY; for(i = 1;i < todo;i++) D[i] = temp[0][i-1]; + enc->LastY = temp[0][i-1]; /* D += j(-0.3420201*W + 0.5098604*X) */ for(i = 0;i < todo;i++) @@ -103,10 +102,11 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo); allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo); allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo); - S[0] = enc->Filter1_WX[3].y[0]; allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo); + S[0] = enc->LastWX; for(i = 1;i < todo;i++) S[i] = temp[0][i-1]; + enc->LastWX = temp[0][i-1]; /* Left = (S + D)/2.0 */ for(i = 0;i < todo;i++) diff --git a/Alc/uhjfilter.h b/Alc/uhjfilter.h index 48c2fde6..e773e0a7 100644 --- a/Alc/uhjfilter.h +++ b/Alc/uhjfilter.h @@ -6,8 +6,7 @@ #include "alMain.h" typedef struct AllPassState { - ALfloat x[2]; /* Last two input samples */ - ALfloat y[2]; /* Last two output samples */ + ALfloat z[2]; } AllPassState; /* Encoding 2-channel UHJ from B-Format is done as: @@ -36,9 +35,10 @@ typedef struct AllPassState { */ typedef struct Uhj2Encoder { - AllPassState Filter1_WX[4]; AllPassState Filter1_Y[4]; AllPassState Filter2_WX[4]; + AllPassState Filter1_WX[4]; + ALfloat LastY, LastWX; } Uhj2Encoder; /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input -- cgit v1.2.3 From 510efae0668181676902de345bd1f44edfa0adfa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Apr 2018 00:17:07 -0700 Subject: Don't specialize biquad processing for a single sample --- Alc/filters/filter.c | 65 ++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/Alc/filters/filter.c b/Alc/filters/filter.c index 65fb08e7..2b370f89 100644 --- a/Alc/filters/filter.c +++ b/Alc/filters/filter.c @@ -96,43 +96,34 @@ void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples) { - if(LIKELY(numsamples > 1)) - { - const ALfloat a1 = filter->a1; - const ALfloat a2 = filter->a2; - const ALfloat b0 = filter->b0; - const ALfloat b1 = filter->b1; - const ALfloat b2 = filter->b2; - ALfloat z1 = filter->z1; - ALfloat z2 = filter->z2; - ALsizei i; - - /* Processing loop is transposed direct form II. This requires less - * storage versus direct form I (only two delay components, instead of - * a four-sample history; the last two inputs and outputs), and works - * better for floating-point which favors summing similarly-sized - * values while being less bothered by overflow. - * - * See: http://www.earlevel.com/main/2003/02/28/biquads/ - */ - for(i = 0;i < numsamples;i++) - { - ALfloat input = src[i]; - ALfloat output = input*b0 + z1; - z1 = input*b1 - output*a1 + z2; - z2 = input*b2 - output*a2; - dst[i] = output; - } - - filter->z1 = z1; - filter->z2 = z2; - } - else if(numsamples == 1) + const ALfloat a1 = filter->a1; + const ALfloat a2 = filter->a2; + const ALfloat b0 = filter->b0; + const ALfloat b1 = filter->b1; + const ALfloat b2 = filter->b2; + ALfloat z1 = filter->z1; + ALfloat z2 = filter->z2; + ALsizei i; + + ASSUME(numsamples > 0); + + /* Processing loop is Transposed Direct Form II. This requires less storage + * compared to Direct Form I (only two delay components, instead of a four- + * sample history; the last two inputs and outputs), and works better for + * floating-point which favors summing similarly-sized values while being + * less bothered by overflow. + * + * See: http://www.earlevel.com/main/2003/02/28/biquads/ + */ + for(i = 0;i < numsamples;i++) { - ALfloat input = *src; - ALfloat output = input*filter->b0 + filter->z1; - filter->z1 = input*filter->b1 - output*filter->a1 + filter->z2; - filter->z2 = input*filter->b2 - output*filter->a2; - *dst = output; + ALfloat input = src[i]; + ALfloat output = input*b0 + z1; + z1 = input*b1 - output*a1 + z2; + z2 = input*b2 - output*a2; + dst[i] = output; } + + filter->z1 = z1; + filter->z2 = z2; } -- cgit v1.2.3 From 8311b57ca6fb67641c386f867ddbcf43db73e222 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Apr 2018 00:18:02 -0700 Subject: Update ChangeLog --- ChangeLog | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7a730262..a7aec638 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,51 +2,49 @@ openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. - Added support fot 24-bit, dual-ear HRTF data sets. The built-in data set - has been updated to 24-bit. + Implemented the Pitch Shifter effect. - Added a 24- to 48-point band-limited Sinc resampler. + Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. - Added an SDL2 playback backend. Disabled by default to avoid a dependency - on SDL2. + Fixed compiling on NetBSD. - Improved the efficiency of the band-limited Sinc resampler. + Fixed the reverb effect's density scale and panning parameters. - Improved the Sinc resampler's transition band to avoid over-attenuating - higher frequencies. - - Replaced the 4-point Sinc resampler with a more efficient cubic resampler. + Fixed use of the WASAPI backend with certain games, which caused odd COM + initialization errors. - Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. + Increased the number of virtual channels for decoding Ambisonics to HRTF + output. - Fixed compiling on NetBSD. + Replaced the 4-point Sinc resampler with a more efficient cubic resampler. - Improved the performance and quality of the Chorus effect. + Renamed the MMDevAPI backend to WASAPI. - Removed the reverb effect's modulation stage. Due to the lack of reference - for its strength. + Added support fot 24-bit, dual-ear HRTF data sets. The built-in data set + has been updated to 24-bit. - Improved AL call error logging with contextualized messages. + Added a 24- to 48-point band-limited Sinc resampler. - Improved the efficiency of object ID lookups. + Added an SDL2 playback backend. Disabled by default to avoid a dependency + on SDL2. - Improved efficienty of internal voice/source synchronization. + Improved the performance and quality of the Chorus and Flanger effects. - Fixed the reverb effect's density scale. + Improved the efficiency of the band-limited Sinc resampler. - Fixed the reverb effect's panning parameters. + Improved the Sinc resampler's transition band to avoid over-attenuating + higher frequencies. - Increased the number of virtual channels for decoding Ambisonics to HRTF - output. + Improved the performance of some filter operations. - Implemented the Pitch Shifter effect. + Improved the efficiency of object ID lookups. - Renamed the MMDevAPI backend to WASAPI. + Improved the efficienty of internal voice/source synchronization. - Fixed using the WASAPI backend with certain games, which caused odd COM - initialization errors. + Improved AL call error logging with contextualized messages. - Improved the performance of some filter operations. + Removed the reverb effect's modulation stage. Due to the lack of reference + for its intended behavior and strength. openal-soft-1.18.2: -- cgit v1.2.3 From 1cc6983b96b02a97bce389d738c6214881577d4c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 24 Apr 2018 21:40:41 -0700 Subject: Use doubles for the pitch shifter's FFTs and processing --- Alc/effects/pshifter.c | 111 ++++++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 860a48a5..e8be0be7 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -38,18 +38,18 @@ #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) typedef struct ALcomplex { - ALfloat Real; - ALfloat Imag; + ALdouble Real; + ALdouble Imag; } ALcomplex; typedef struct ALphasor { - ALfloat Amplitude; - ALfloat Phase; + ALdouble Amplitude; + ALdouble Phase; } ALphasor; typedef struct ALFrequencyDomain { - ALfloat Amplitude; - ALfloat Frequency; + ALdouble Amplitude; + ALdouble Frequency; } ALfrequencyDomain; typedef struct ALpshifterState { @@ -63,9 +63,9 @@ typedef struct ALpshifterState { /*Effects buffers*/ ALfloat InFIFO[STFT_SIZE]; ALfloat OutFIFO[STFT_STEP]; - ALfloat LastPhase[STFT_HALF_SIZE+1]; - ALfloat SumPhase[STFT_HALF_SIZE+1]; - ALfloat OutputAccum[STFT_SIZE]; + ALdouble LastPhase[STFT_HALF_SIZE+1]; + ALdouble SumPhase[STFT_HALF_SIZE+1]; + ALdouble OutputAccum[STFT_SIZE]; ALcomplex FFTbuffer[STFT_SIZE]; @@ -89,7 +89,7 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState); /* Define a Hann window, used to filter the STFT input and output. */ -alignas(16) static ALfloat HannWindow[STFT_SIZE]; +alignas(16) static ALdouble HannWindow[STFT_SIZE]; static void InitHannWindow(void) { @@ -99,19 +99,44 @@ static void InitHannWindow(void) for(i = 0;i < STFT_SIZE>>1;i++) { ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1)); - HannWindow[i] = HannWindow[STFT_SIZE-(i+1)] = (ALfloat)(val * val); + HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val; } } static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; +/* Fast double-to-int conversion. Assumes the FPU is already in round-to-zero + * mode. */ +static inline ALint fastd2i(ALdouble d) +{ + /* NOTE: SSE2 is required for the efficient double-to-int opcodes on x86. + * Otherwise, we need to rely on x87's fistp opcode with it already in + * round-to-zero mode. x86-64 guarantees SSE2 support. + */ +#if (defined(__i386__) && !defined(__SSE2_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP < 2)) +#ifdef HAVE_LRINTF + return lrint(d); +#elif defined(_MSC_VER) && defined(_M_IX86) + ALint i; + __asm fld d + __asm fistp i + return i; +#else + return (ALint)d; +#endif +#else + return (ALint)d; +#endif +} + + /* Converts ALcomplex to ALphasor */ static inline ALphasor rect2polar(ALcomplex number) { ALphasor polar; - polar.Amplitude = sqrtf(number.Real*number.Real + number.Imag*number.Imag); - polar.Phase = atan2f(number.Imag , number.Real); + polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag); + polar.Phase = atan2(number.Imag, number.Real); return polar; } @@ -121,8 +146,8 @@ static inline ALcomplex polar2rect(ALphasor number) { ALcomplex cartesian; - cartesian.Real = number.Amplitude * cosf(number.Phase); - cartesian.Imag = number.Amplitude * sinf(number.Phase); + cartesian.Real = number.Amplitude * cos(number.Phase); + cartesian.Imag = number.Amplitude * sin(number.Phase); return cartesian; } @@ -166,11 +191,11 @@ static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers * (ALcomplex), FFTSize MUST BE power of two. */ -static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALfloat Sign) +static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) { ALsizei i, j, k, mask, step, step2; ALcomplex temp, u, w; - ALfloat arg; + ALdouble arg; /* Bit-reversal permutation applied to a sequence of FFTSize items */ for(i = 1;i < FFTSize-1;i++) @@ -195,13 +220,13 @@ static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALfloat Sign) for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) { step2 = step >> 1; - arg = F_PI / step2; + arg = M_PI / step2; - w.Real = cosf(arg); - w.Imag = sinf(arg) * Sign; + w.Real = cos(arg); + w.Imag = sin(arg) * Sign; - u.Real = 1.0f; - u.Imag = 0.0f; + u.Real = 1.0; + u.Imag = 0.0; for(j = 0;j < step2;j++) { @@ -272,8 +297,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/ */ - static const ALfloat expected = F_TAU / (ALfloat)OVERSAMP; - const ALfloat freq_per_bin = state->FreqPerBin; + static const ALdouble expected = M_PI*2.0 / OVERSAMP; + const ALdouble freq_per_bin = state->FreqPerBin; ALfloat *restrict bufferOut = state->BufferOut; ALsizei count = state->count; ALsizei i, j, k; @@ -296,12 +321,12 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD for(k = 0;k < STFT_SIZE;k++) { state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k]; - state->FFTbuffer[k].Imag = 0.0f; + state->FFTbuffer[k].Imag = 0.0; } /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - FFT(state->FFTbuffer, STFT_SIZE, -1.0f); + FFT(state->FFTbuffer, STFT_SIZE, -1.0); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. @@ -309,18 +334,18 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD for(k = 0;k < STFT_HALF_SIZE+1;k++) { ALphasor component; - ALfloat tmp; + ALdouble tmp; ALint qpd; /* Compute amplitude and phase */ component = rect2polar(state->FFTbuffer[k]); /* Compute phase difference and subtract expected phase difference */ - tmp = (component.Phase - state->LastPhase[k]) - (ALfloat)k*expected; + tmp = (component.Phase - state->LastPhase[k]) - k*expected; /* Map delta phase into +/- Pi interval */ - qpd = fastf2i(tmp / F_PI); - tmp -= F_PI * (ALfloat)(qpd + (qpd%2)); + qpd = fastd2i(tmp / M_PI); + tmp -= M_PI * (qpd + (qpd%2)); /* Get deviation from bin frequency from the +/- Pi interval */ tmp /= expected; @@ -329,8 +354,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD * for maintain the gain (because half of bins are used) and store * amplitude and true frequency in analysis buffer. */ - state->Analysis_buffer[k].Amplitude = 2.0f * component.Amplitude; - state->Analysis_buffer[k].Frequency = ((ALfloat)k + tmp) * freq_per_bin; + state->Analysis_buffer[k].Amplitude = 2.0 * component.Amplitude; + state->Analysis_buffer[k].Frequency = (k + tmp) * freq_per_bin; /* Store actual phase[k] for the calculations in the next frame*/ state->LastPhase[k] = component.Phase; @@ -340,8 +365,8 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* pitch shifting */ for(k = 0;k < STFT_HALF_SIZE+1;k++) { - state->Syntesis_buffer[k].Amplitude = 0.0f; - state->Syntesis_buffer[k].Frequency = 0.0f; + state->Syntesis_buffer[k].Amplitude = 0.0; + state->Syntesis_buffer[k].Frequency = 0.0; } for(k = 0;k < STFT_HALF_SIZE+1;k++) @@ -359,13 +384,13 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD for(k = 0;k < STFT_HALF_SIZE+1;k++) { ALphasor component; - ALfloat tmp; + ALdouble tmp; /* Compute bin deviation from scaled freq */ - tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - (ALfloat)k; + tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k; /* Calculate actual delta phase and accumulate it to get bin phase */ - state->SumPhase[k] += ((ALfloat)k + tmp) * expected; + state->SumPhase[k] += (k + tmp) * expected; component.Amplitude = state->Syntesis_buffer[k].Amplitude; component.Phase = state->SumPhase[k]; @@ -376,22 +401,22 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* zero negative frequencies for recontruct a real signal */ for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++) { - state->FFTbuffer[k].Real = 0.0f; - state->FFTbuffer[k].Imag = 0.0f; + state->FFTbuffer[k].Real = 0.0; + state->FFTbuffer[k].Imag = 0.0; } /* Apply iFFT to buffer data */ - FFT(state->FFTbuffer, STFT_SIZE, 1.0f); + FFT(state->FFTbuffer, STFT_SIZE, 1.0); /* Windowing and add to output */ for(k = 0;k < STFT_SIZE;k++) state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real / - (0.5f * STFT_HALF_SIZE * OVERSAMP); + (0.5 * STFT_HALF_SIZE * OVERSAMP); /* Shift accumulator, input & output FIFO */ - for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k]; for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0f; + for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0; for(k = 0;k < FIFO_LATENCY;k++) state->InFIFO[k] = state->InFIFO[k+STFT_STEP]; } -- cgit v1.2.3 From 1e0728af64696914ea12e2e97e7b534b2caa96f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Apr 2018 23:26:11 -0700 Subject: Transpose the band-splitter all-pass section --- Alc/filters/splitter.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Alc/filters/splitter.c b/Alc/filters/splitter.c index 524bcc1d..e99f4b95 100644 --- a/Alc/filters/splitter.c +++ b/Alc/filters/splitter.c @@ -34,6 +34,8 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat ALfloat lp_z1, lp_z2, hp_z1; ALsizei i; + ASSUME(count > 0); + hp_coeff = splitter->coeff; lp_coeff = splitter->coeff*0.5f + 0.5f; lp_z1 = splitter->lp_z1; @@ -55,9 +57,8 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat lpout[i] = lp_y; /* All-pass sample processing. */ - d = in - hp_coeff*hp_z1; - hp_y = hp_z1 + hp_coeff*d; - hp_z1 = d; + hp_y = in*hp_coeff + hp_z1; + hp_z1 = in - hp_y*hp_coeff; /* High-pass generated from removing low-passed output. */ hpout[i] = hp_y - lp_y; @@ -87,21 +88,22 @@ void splitterap_clear(SplitterAllpass *splitter) void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count) { - ALfloat coeff, d, x; + ALfloat coeff, in, out; ALfloat z1; ALsizei i; + ASSUME(count > 0); + coeff = splitter->coeff; z1 = splitter->z1; for(i = 0;i < count;i++) { - x = samples[i]; + in = samples[i]; - d = x - coeff*z1; - x = z1 + coeff*d; - z1 = d; + out = in*coeff + z1; + z1 = in - out*coeff; - samples[i] = x; + samples[i] = out; } splitter->z1 = z1; } -- cgit v1.2.3 From 492c75cb7bc61214cdac88c763e2309dc30a9497 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Apr 2018 00:41:02 -0700 Subject: Rename some variables for clarity --- Alc/filters/nfc.c | 60 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c index 3b8696f7..fa130081 100644 --- a/Alc/filters/nfc.c +++ b/Alc/filters/nfc.c @@ -2,6 +2,7 @@ #include "config.h" #include "nfc.h" +#include "alMain.h" #include @@ -223,19 +224,18 @@ void NfcFilterAdjust(NfcFilter *nfc, const float w0) void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float b0 = nfc->first.coeffs[0]; - const float a0 = nfc->first.coeffs[1]; + const float gain = nfc->first.coeffs[0]; + const float b1 = nfc->first.coeffs[1]; const float a1 = nfc->first.coeffs[2]; float z1 = nfc->first.history[0]; int i; + ASSUME(count > 0); + for(i = 0;i < count;i++) { - float out = src[i] * b0; - float y; - - y = out - (a1*z1); - out = y + (a0*z1); + float y = src[i]*gain - a1*z1; + float out = y + b1*z1; z1 += y; dst[i] = out; @@ -245,22 +245,21 @@ void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restric void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float b0 = nfc->second.coeffs[0]; - const float a00 = nfc->second.coeffs[1]; - const float a01 = nfc->second.coeffs[2]; - const float a10 = nfc->second.coeffs[3]; - const float a11 = nfc->second.coeffs[4]; + const float gain = nfc->second.coeffs[0]; + const float b1 = nfc->second.coeffs[1]; + const float b2 = nfc->second.coeffs[2]; + const float a1 = nfc->second.coeffs[3]; + const float a2 = nfc->second.coeffs[4]; float z1 = nfc->second.history[0]; float z2 = nfc->second.history[1]; int i; + ASSUME(count > 0); + for(i = 0;i < count;i++) { - float out = src[i] * b0; - float y; - - y = out - (a10*z1) - (a11*z2); - out = y + (a00*z1) + (a01*z2); + float y = src[i]*gain - a1*z1 - a2*z2; + float out = y + b1*z1 + b2*z2; z2 += z1; z1 += y; @@ -272,30 +271,29 @@ void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restric void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float b0 = nfc->third.coeffs[0]; - const float a00 = nfc->third.coeffs[1]; - const float a01 = nfc->third.coeffs[2]; - const float a02 = nfc->third.coeffs[3]; - const float a10 = nfc->third.coeffs[4]; - const float a11 = nfc->third.coeffs[5]; - const float a12 = nfc->third.coeffs[6]; + const float gain = nfc->third.coeffs[0]; + const float b1 = nfc->third.coeffs[1]; + const float b2 = nfc->third.coeffs[2]; + const float b3 = nfc->third.coeffs[3]; + const float a1 = nfc->third.coeffs[4]; + const float a2 = nfc->third.coeffs[5]; + const float a3 = nfc->third.coeffs[6]; float z1 = nfc->third.history[0]; float z2 = nfc->third.history[1]; float z3 = nfc->third.history[2]; int i; + ASSUME(count > 0); + for(i = 0;i < count;i++) { - float out = src[i] * b0; - float y; - - y = out - (a10*z1) - (a11*z2); - out = y + (a00*z1) + (a01*z2); + float y = src[i]*gain - a1*z1 - a2*z2; + float out = y + b1*z1 + b2*z2; z2 += z1; z1 += y; - y = out - (a12*z3); - out = y + (a02*z3); + y = out - a3*z3; + out = y + b3*z3; z3 += y; dst[i] = out; -- cgit v1.2.3 From ddd4751f87bebfc87967bc3359da9604b2f3c4c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Apr 2018 18:42:26 -0700 Subject: Increase the band-split IR for decoding ambisonics to HRTF --- Alc/hrtf.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 8db04d46..7e5f6e96 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -244,16 +244,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay; ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay; - max_length = maxi(max_length, - mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) - ); - if(NUM_BANDS == 1) { + max_length = maxi(max_length, + mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) + ); + for(i = 0;i < NumChannels;++i) { - ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)floor(sqrt(i))] * - AmbiMatrix[c][i]; + ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)sqrt(i)] * AmbiMatrix[c][i]; ALsizei lidx = ldelay, ridx = rdelay; ALsizei j = 0; while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize) @@ -266,6 +265,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } else { + /* Increase the IR size by 2/3rds to account for the tail generated + * by the band-split filter. + */ + const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH); + + max_length = maxi(max_length, + mini(maxi(ldelay, rdelay) + irsize, HRIR_LENGTH) + ); + /* Band-split left HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) @@ -275,7 +283,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Apply left ear response with delay. */ for(i = 0;i < NumChannels;++i) { - ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; + ALfloat hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; for(b = 0;b < NUM_BANDS;b++) { ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); @@ -295,7 +303,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N /* Apply right ear response with delay. */ for(i = 0;i < NumChannels;++i) { - ALfloat hfgain = AmbiOrderHFGain[(ALsizei)floor(sqrt(i))]; + ALfloat hfgain = AmbiOrderHFGain[(ALsizei)sqrt(i)]; for(b = 0;b < NUM_BANDS;b++) { ALdouble mult = AmbiMatrix[c][i] * (ALdouble)((b==0) ? hfgain : 1.0); -- cgit v1.2.3 From 54109043b82ca20fb0069d215930fb218f2e7c4f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Apr 2018 01:14:17 -0700 Subject: Remove some unnecessary floor calls --- Alc/hrtf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 7e5f6e96..affb6c27 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -217,16 +217,14 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALuint azcount; /* Calculate elevation index. */ - evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c].Elev) * - (Hrtf->evCount-1)/F_PI + 0.5f); + evidx = (ALsizei)((F_PI_2+AmbiPoints[c].Elev) * (Hrtf->evCount-1) / F_PI + 0.5f); evidx = clampi(evidx, 0, Hrtf->evCount-1); azcount = Hrtf->azCount[evidx]; evoffset = Hrtf->evOffset[evidx]; /* Calculate azimuth index for this elevation. */ - azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c].Azim) * - azcount/F_TAU + 0.5f) % azcount; + azidx = (ALsizei)((F_TAU+AmbiPoints[c].Azim) * azcount / F_TAU + 0.5f) % azcount; /* Calculate indices for left and right channels. */ idx[c] = evoffset + azidx; -- cgit v1.2.3 From e420752e82f8c1aad421d3928bda53841e975a0e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Apr 2018 18:52:40 -0700 Subject: Fix a comment about a float's mantissa --- Alc/ALu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d6b15183..92483aee 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1679,9 +1679,10 @@ static inline ALfloat Conv_ALfloat(ALfloat val) { return val; } static inline ALint Conv_ALint(ALfloat val) { - /* Floats only have a 24-bit mantissa, so [-16777216, +16777216] is the max - * integer range normalized floats can be safely converted to (a bit of the - * exponent helps out, effectively giving 25 bits). + /* Floats have a 23-bit mantissa. A bit of the exponent helps out along + * with the sign bit, giving 25 bits. So [-16777216, +16777216] is the max + * integer range normalized floats can be converted to before losing + * precision. */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; } -- cgit v1.2.3 From 242ed45f6576435e5eb8be08e5a5fa292d123113 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Apr 2018 22:08:12 -0700 Subject: Rename some struct members for clarity --- Alc/filters/nfc.c | 136 +++++++++++++++++++++++++++--------------------------- Alc/filters/nfc.h | 18 ++++---- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/Alc/filters/nfc.c b/Alc/filters/nfc.c index fa130081..8869d1d0 100644 --- a/Alc/filters/nfc.c +++ b/Alc/filters/nfc.c @@ -58,25 +58,25 @@ static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float float b_00, g_0; float r; - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[1] = (2.0f * b_00) / g_0; + nfc->gain *= g_0; + nfc->b1 = 2.0f * b_00 / g_0; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; b_00 = B[1][0] * r; g_0 = 1.0f + b_00; - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[1+1] = (2.0f * b_00) / g_0; + nfc->base_gain /= g_0; + nfc->gain /= g_0; + nfc->a1 = 2.0f * b_00 / g_0; } static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) @@ -88,8 +88,8 @@ static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0) b_00 = B[1][0] * r; g_0 = 1.0f + b_00; - nfc->coeffs[0] = nfc->g * g_0; - nfc->coeffs[1] = (2.0f * b_00) / g_0; + nfc->gain = nfc->base_gain * g_0; + nfc->b1 = 2.0f * b_00 / g_0; } @@ -98,8 +98,8 @@ static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float float b_10, b_11, g_1; float r; - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; @@ -107,9 +107,9 @@ static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->coeffs[0] *= g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; + nfc->gain *= g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; @@ -117,10 +117,10 @@ static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[2+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2+2] = (4.0f * b_11) / g_1; + nfc->base_gain /= g_1; + nfc->gain /= g_1; + nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->a2 = 4.0f * b_11 / g_1; } static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) @@ -133,9 +133,9 @@ static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0) b_11 = B[2][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->coeffs[0] = nfc->g * g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; } @@ -145,8 +145,8 @@ static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float float b_00, g_0; float r; - nfc->g = 1.0f; - nfc->coeffs[0] = 1.0f; + nfc->base_gain = 1.0f; + nfc->gain = 1.0f; /* Calculate bass-boost coefficients. */ r = 0.5f * w0; @@ -154,15 +154,15 @@ static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->coeffs[0] *= g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; + nfc->gain *= g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; b_00 = B[3][2] * r; g_0 = 1.0f + b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[2+1] = (2.0f * b_00) / g_0; + nfc->gain *= g_0; + nfc->b3 = 2.0f * b_00 / g_0; /* Calculate bass-cut coefficients. */ r = 0.5f * w1; @@ -170,17 +170,17 @@ static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->g /= g_1; - nfc->coeffs[0] /= g_1; - nfc->coeffs[3+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[3+2] = (4.0f * b_11) / g_1; - + nfc->base_gain /= g_1; + nfc->gain /= g_1; + nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->a2 = 4.0f * b_11 / g_1; + b_00 = B[3][2] * r; g_0 = 1.0f + b_00; - nfc->g /= g_0; - nfc->coeffs[0] /= g_0; - nfc->coeffs[3+2+1] = (2.0f * b_00) / g_0; + nfc->base_gain /= g_0; + nfc->gain /= g_0; + nfc->a3 = 2.0f * b_00 / g_0; } static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) @@ -194,15 +194,15 @@ static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0) b_11 = B[3][1] * r * r; g_1 = 1.0f + b_10 + b_11; - nfc->coeffs[0] = nfc->g * g_1; - nfc->coeffs[1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1; - nfc->coeffs[2] = (4.0f * b_11) / g_1; + nfc->gain = nfc->base_gain * g_1; + nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1; + nfc->b2 = 4.0f * b_11 / g_1; b_00 = B[3][2] * r; g_0 = 1.0f + b_00; - nfc->coeffs[0] *= g_0; - nfc->coeffs[2+1] = (2.0f * b_00) / g_0; + nfc->gain *= g_0; + nfc->b3 = 2.0f * b_00 / g_0; } @@ -224,10 +224,10 @@ void NfcFilterAdjust(NfcFilter *nfc, const float w0) void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float gain = nfc->first.coeffs[0]; - const float b1 = nfc->first.coeffs[1]; - const float a1 = nfc->first.coeffs[2]; - float z1 = nfc->first.history[0]; + const float gain = nfc->first.gain; + const float b1 = nfc->first.b1; + const float a1 = nfc->first.a1; + float z1 = nfc->first.z[0]; int i; ASSUME(count > 0); @@ -240,18 +240,18 @@ void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restric dst[i] = out; } - nfc->first.history[0] = z1; + nfc->first.z[0] = z1; } void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float gain = nfc->second.coeffs[0]; - const float b1 = nfc->second.coeffs[1]; - const float b2 = nfc->second.coeffs[2]; - const float a1 = nfc->second.coeffs[3]; - const float a2 = nfc->second.coeffs[4]; - float z1 = nfc->second.history[0]; - float z2 = nfc->second.history[1]; + const float gain = nfc->second.gain; + const float b1 = nfc->second.b1; + const float b2 = nfc->second.b2; + const float a1 = nfc->second.a1; + const float a2 = nfc->second.a2; + float z1 = nfc->second.z[0]; + float z2 = nfc->second.z[1]; int i; ASSUME(count > 0); @@ -265,22 +265,22 @@ void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restric dst[i] = out; } - nfc->second.history[0] = z1; - nfc->second.history[1] = z2; + nfc->second.z[0] = z1; + nfc->second.z[1] = z2; } void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count) { - const float gain = nfc->third.coeffs[0]; - const float b1 = nfc->third.coeffs[1]; - const float b2 = nfc->third.coeffs[2]; - const float b3 = nfc->third.coeffs[3]; - const float a1 = nfc->third.coeffs[4]; - const float a2 = nfc->third.coeffs[5]; - const float a3 = nfc->third.coeffs[6]; - float z1 = nfc->third.history[0]; - float z2 = nfc->third.history[1]; - float z3 = nfc->third.history[2]; + const float gain = nfc->third.gain; + const float b1 = nfc->third.b1; + const float b2 = nfc->third.b2; + const float b3 = nfc->third.b3; + const float a1 = nfc->third.a1; + const float a2 = nfc->third.a2; + const float a3 = nfc->third.a3; + float z1 = nfc->third.z[0]; + float z2 = nfc->third.z[1]; + float z3 = nfc->third.z[2]; int i; ASSUME(count > 0); @@ -298,9 +298,9 @@ void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restric dst[i] = out; } - nfc->third.history[0] = z1; - nfc->third.history[1] = z2; - nfc->third.history[2] = z3; + nfc->third.z[0] = z1; + nfc->third.z[1] = z2; + nfc->third.z[2] = z3; } #if 0 /* Original methods the above are derived from. */ diff --git a/Alc/filters/nfc.h b/Alc/filters/nfc.h index 8c6cc6ae..12a5a18f 100644 --- a/Alc/filters/nfc.h +++ b/Alc/filters/nfc.h @@ -2,19 +2,19 @@ #define FILTER_NFC_H struct NfcFilter1 { - float g; - float coeffs[1*2 + 1]; - float history[1]; + float base_gain, gain; + float b1, a1; + float z[1]; }; struct NfcFilter2 { - float g; - float coeffs[2*2 + 1]; - float history[2]; + float base_gain, gain; + float b1, b2, a1, a2; + float z[2]; }; struct NfcFilter3 { - float g; - float coeffs[3*2 + 1]; - float history[3]; + float base_gain, gain; + float b1, b2, b3, a1, a2, a3; + float z[3]; }; typedef struct NfcFilter { -- cgit v1.2.3 From 2385ab700cc0aa4aa3895a029e20ee76ffe4c736 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Apr 2018 14:02:33 -0700 Subject: Avoid potentially calling log10f(0) --- Alc/mastering.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 91267d83..1636c8d9 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -98,7 +98,7 @@ static void FollowEnvelope(Compressor *Comp, const ALsizei SamplesToDo) for(i = 0;i < SamplesToDo;i++) { - ALfloat env = maxf(-6.0f, log10f(Comp->Envelope[i])); + ALfloat env = log10f(maxf(Comp->Envelope[i], 0.000001f)); ALfloat slope = minf(1.0f, fabsf(env - last) / 4.5f); if(env > last) -- cgit v1.2.3 From e8aaa9cb136a048e1d12adf8d01a3869aee9182d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Apr 2018 18:03:33 -0700 Subject: An output device buffer is likely --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 92483aee..177509b6 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1831,7 +1831,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, SamplesToDo, device->RealOut.NumChannels); - if(OutBuffer) + if(LIKELY(OutBuffer)) { ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer; ALsizei Channels = device->RealOut.NumChannels; -- cgit v1.2.3 From 22413b82ca6bb4fc4e4112b500d9a7e1549bdd73 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 1 May 2018 20:00:30 -0700 Subject: Pass in the number of channels per order to InitNearFieldCtrl --- Alc/panning.c | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 5ff37d0a..7f9e74e2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -416,7 +416,8 @@ static const ChannelMap MonoCfg[1] = { { BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } }, }; -static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, bool periphonic) +static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, + const ALsizei *restrict chans_per_order) { const char *devname = alstr_get_cstr(device->DeviceName); ALsizei i; @@ -428,13 +429,8 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde */ device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); - device->Dry.NumChannelsPerOrder[0] = 1; - if(periphonic) - for(i = 1;i < order+1;i++) - device->Dry.NumChannelsPerOrder[i] = (i+1)*(i+1) - i*i; - else - for(i = 1;i < order+1;i++) - device->Dry.NumChannelsPerOrder[i] = (i*2+1) - ((i-1)*2+1); + for(i = 0;i < order+1;i++) + device->Dry.NumChannelsPerOrder[i] = chans_per_order[i]; for(;i < MAX_AMBI_ORDER+1;i++) device->Dry.NumChannelsPerOrder[i] = 0; } @@ -610,9 +606,12 @@ static void InitPanning(ALCdevice *device) if(ConfigValueFloat(devname, "decoder", "nfc-ref-delay", &nfc_delay) && nfc_delay > 0.0f) { + static const ALsizei chans_per_order[MAX_AMBI_ORDER+1] = { + 1, 3, 5, 7 + }; nfc_delay = clampf(nfc_delay, 0.001f, 1000.0f); InitNearFieldCtrl(device, nfc_delay * SPEEDOFSOUNDMETRESPERSEC, - device->AmbiOrder, true); + device->AmbiOrder, chans_per_order); } } else @@ -728,6 +727,8 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsizei speakermap[MAX_OUTPUT_CHANNELS]) { + static const ALsizei chans_per_order2d[MAX_AMBI_ORDER+1] = { 1, 2, 2, 2 }; + static const ALsizei chans_per_order3d[MAX_AMBI_ORDER+1] = { 1, 3, 5, 7 }; ALfloat avg_dist; ALsizei count; ALsizei i; @@ -804,7 +805,7 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz avg_dist /= (ALfloat)conf->NumSpeakers; InitNearFieldCtrl(device, avg_dist, (conf->ChanMask > 0x1ff) ? 3 : (conf->ChanMask > 0xf) ? 2 : 1, - !!(conf->ChanMask&AMBI_PERIPHONIC_MASK) + (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? chans_per_order3d : chans_per_order2d ); InitDistanceComp(device, conf, speakermap); @@ -878,6 +879,7 @@ static void InitHrtfPanning(ALCdevice *device) 2.40192231e+00f, 1.86052102e+00f, 9.60768923e-01f }; static const ALsizei IndexMap[6] = { 0, 1, 2, 3, 4, 8 }; + static const ALsizei ChansPerOrder[MAX_AMBI_ORDER+1] = { 1, 3, 2, 0 }; const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS] = AmbiMatrixFOA; const ALfloat *restrict AmbiOrderHFGain = AmbiOrderHFGainFOA; ALsizei count = 4; @@ -932,22 +934,8 @@ static void InitHrtfPanning(ALCdevice *device) AmbiOrderHFGain ); - if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "decoder", "nfc", 1) && - device->HrtfHandle->distance > 0.0f) - { - /* NFC is only used when AvgSpeakerDist is greater than 0, and can only - * be used when rendering to an ambisonic buffer. - */ - device->AvgSpeakerDist = minf(device->HrtfHandle->distance, 10.0f); - - i = 0; - device->Dry.NumChannelsPerOrder[i++] = 1; - device->Dry.NumChannelsPerOrder[i++] = 3; - if(device->AmbiUp) - device->Dry.NumChannelsPerOrder[i++] = 2; - while(i < MAX_AMBI_ORDER+1) - device->Dry.NumChannelsPerOrder[i++] = 0; - } + InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1, + ChansPerOrder); } static void InitUhjPanning(ALCdevice *device) -- cgit v1.2.3 From 85c03925fb79ee4c040e2f19242308476c2c6044 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 May 2018 20:59:53 -0700 Subject: Avoid duplication for getting the cpuid --- Alc/helpers.c | 79 ++++++++++++++++++----------------------------------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index f7adfba0..ae49ec14 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -136,6 +136,20 @@ extern inline int fallback_ctz64(ALuint64 value); #endif +#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef unsigned int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } +#define CAN_GET_CPUID +#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) +typedef int reg_type; +static inline void get_cpuid(int f, reg_type *regs) +{ (__cpuid)(regs, f); } +#define CAN_GET_CPUID +#endif + int CPUCapFlags = 0; void FillCPUCaps(int capfilter) @@ -144,58 +158,13 @@ void FillCPUCaps(int capfilter) /* FIXME: We really should get this for all available CPUs in case different * CPUs have different caps (is that possible on one machine?). */ -#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) - union { - unsigned int regs[4]; - char str[sizeof(unsigned int[4])]; - } cpuinf[3]; - - if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc = 0; - - if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - maxextfunc = cpuinf[0].regs[0]; - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004 && - __get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) && - __get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) && - __get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3])) - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - - if(maxfunc >= 1 && - __get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - { - if((cpuinf[0].regs[3]&(1<<25))) - { - caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<0))) - { - caps |= CPU_CAP_SSE3; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } - } - } -#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) +#ifdef CAN_GET_CPUID union { - int regs[4]; - char str[sizeof(int[4])]; - } cpuinf[3]; + reg_type regs[4]; + char str[sizeof(reg_type[4])]; + } cpuinf[3] = {{ { 0, 0, 0, 0 } }}; - (__cpuid)(cpuinf[0].regs, 0); + get_cpuid(0, cpuinf[0].regs); if(cpuinf[0].regs[0] == 0) ERR("Failed to get CPUID\n"); else @@ -203,7 +172,7 @@ void FillCPUCaps(int capfilter) unsigned int maxfunc = cpuinf[0].regs[0]; unsigned int maxextfunc; - (__cpuid)(cpuinf[0].regs, 0x80000000); + get_cpuid(0x80000000, cpuinf[0].regs); maxextfunc = cpuinf[0].regs[0]; TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); @@ -211,15 +180,15 @@ void FillCPUCaps(int capfilter) TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); if(maxextfunc >= 0x80000004) { - (__cpuid)(cpuinf[0].regs, 0x80000002); - (__cpuid)(cpuinf[1].regs, 0x80000003); - (__cpuid)(cpuinf[2].regs, 0x80000004); + get_cpuid(0x80000002, cpuinf[0].regs); + get_cpuid(0x80000003, cpuinf[1].regs); + get_cpuid(0x80000004, cpuinf[2].regs); TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); } if(maxfunc >= 1) { - (__cpuid)(cpuinf[0].regs, 1); + get_cpuid(1, cpuinf[0].regs); if((cpuinf[0].regs[3]&(1<<25))) { caps |= CPU_CAP_SSE; -- cgit v1.2.3 From a19296e3cfb8b6b9e617576aba20c7d40d77dff9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 2 May 2018 21:06:57 -0700 Subject: Avoid excessive if block depths --- Alc/helpers.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index ae49ec14..c4fb7a8c 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -190,19 +190,13 @@ void FillCPUCaps(int capfilter) { get_cpuid(1, cpuinf[0].regs); if((cpuinf[0].regs[3]&(1<<25))) - { caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<0))) - { - caps |= CPU_CAP_SSE3; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } + if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) + caps |= CPU_CAP_SSE2; + if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) + caps |= CPU_CAP_SSE3; + if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; } } #else -- cgit v1.2.3 From af90d89b6bea2f5fb7dae930ed6d6e420568f2a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 May 2018 17:06:55 -0700 Subject: Use a fixed-point scale for the pitch shifter frequency index --- Alc/effects/pshifter.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index e8be0be7..61857343 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -57,6 +57,7 @@ typedef struct ALpshifterState { /* Effect parameters */ ALsizei count; + ALsizei PitchShiftI; ALfloat PitchShift; ALfloat FreqPerBin; @@ -259,9 +260,10 @@ static ALvoid ALpshifterState_Destruct(ALpshifterState *state) static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device) { /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->PitchShift = 1.0f; - state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; + state->count = FIFO_LATENCY; + state->PitchShiftI = FRACTIONONE; + state->PitchShift = 1.0f; + state->FreqPerBin = device->Frequency / (ALfloat)STFT_SIZE; memset(state->InFIFO, 0, sizeof(state->InFIFO)); memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); @@ -282,10 +284,13 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; + float pitch; - state->PitchShift = powf(2.0f, + pitch = powf(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); + state->PitchShiftI = (ALsizei)(pitch*FRACTIONONE + 0.5f); + state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); @@ -371,7 +376,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD for(k = 0;k < STFT_HALF_SIZE+1;k++) { - j = fastf2i((ALfloat)k * state->PitchShift); + j = (k*state->PitchShiftI) >> FRACTIONBITS; if(j >= STFT_HALF_SIZE+1) break; state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude; -- cgit v1.2.3 From d8a659c6f2db425729a33b0649f467c14ef18a9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 May 2018 17:13:05 -0700 Subject: Avoid fastf2i in the converter init --- Alc/converter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/converter.c b/Alc/converter.c index 6e28b4a6..ef2eb9af 100644 --- a/Alc/converter.c +++ b/Alc/converter.c @@ -27,7 +27,8 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType /* Have to set the mixer FPU mode since that's what the resampler code expects. */ START_MIXER_MODE(); - step = fastf2i((ALfloat)mind((ALdouble)srcRate / dstRate, MAX_PITCH)*FRACTIONONE + 0.5f); + step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5, + MAX_PITCH * FRACTIONONE); converter->mIncrement = maxi(step, 1); if(converter->mIncrement == FRACTIONONE) converter->mResample = Resample_copy_C; -- cgit v1.2.3 From ac8dbd7a56e4ca0ccfbef61b89bdb55775abea6a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 May 2018 21:43:53 -0700 Subject: Add a specific function for truncating float-to-int conversions --- Alc/ALu.c | 11 +++-------- Alc/effects/chorus.c | 10 +++++----- Alc/effects/echo.c | 8 ++++---- Alc/effects/modulator.c | 3 +-- Alc/effects/reverb.c | 20 ++++++++++---------- Alc/helpers.c | 1 + Alc/hrtf.c | 20 +++++++++----------- OpenAL32/Include/alMain.h | 7 +++++++ 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 177509b6..0c930a29 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -352,25 +352,20 @@ void aluSelectPostProcess(ALCdevice *device) */ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *table) { - ALfloat sf; - ALsizei si; + ALfloat sf = 0.0f; + ALsizei si = BSINC_SCALE_COUNT-1; if(increment > FRACTIONONE) { sf = (ALfloat)FRACTIONONE / increment; sf = maxf(0.0f, (BSINC_SCALE_COUNT-1) * (sf-table->scaleBase) * table->scaleRange); - si = fastf2i(sf); + si = float2int(sf); /* The interpolation factor is fit to this diagonally-symmetric curve * to reduce the transition ripple caused by interpolating different * scales of the sinc function. */ sf = 1.0f - cosf(asinf(sf - si)); } - else - { - sf = 0.0f; - si = BSINC_SCALE_COUNT - 1; - } state->sf = sf; state->m = table->m[si]; diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index 3710d936..ffb2b572 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -98,7 +98,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY); ALsizei maxlen; - maxlen = NextPowerOf2(fastf2i(max_delay*2.0f*Device->Frequency) + 1); + maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u); if(maxlen <= 0) return AL_FALSE; if(maxlen != state->BufferLength) @@ -140,7 +140,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte /* The LFO depth is scaled to be relative to the sample delay. Clamp the * delay and depth to allow enough padding for resampling. */ - state->delay = maxi(fastf2i(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), + state->delay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f), mindelay); state->depth = minf(props->Chorus.Depth * state->delay, (ALfloat)(state->delay - mindelay)); @@ -167,10 +167,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte /* Calculate LFO coefficient (number of samples per cycle). Limit the * max range to avoid overflow when calculating the displacement. */ - ALsizei lfo_range = mini(fastf2i(frequency/rate + 0.5f), INT_MAX/360 - 180); + ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180))); - state->lfo_offset = fastf2i((ALfloat)state->lfo_offset/state->lfo_range* - lfo_range + 0.5f) % lfo_range; + state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range* + lfo_range + 0.5f) % lfo_range; state->lfo_range = lfo_range; switch(state->waveform) { diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index a98ed933..676b17e8 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -92,8 +92,8 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) // 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 = fastf2i(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + - fastf2i(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); + maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) + + float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f); maxlen = NextPowerOf2(maxlen); if(maxlen <= 0) return AL_FALSE; @@ -120,8 +120,8 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat gainhf, lrpan, spread; - state->Tap[0].delay = maxi(fastf2i(props->Echo.Delay*frequency + 0.5f), 1); - state->Tap[1].delay = fastf2i(props->Echo.LRDelay*frequency + 0.5f); + state->Tap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1); + state->Tap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f); state->Tap[1].delay += state->Tap[0].delay; spread = props->Echo.Spread; diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index f97f7572..7f1a2cad 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -137,8 +137,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->GetSamples = ModulateSquare; - state->step = fastf2i(props->Modulator.Frequency*WAVEFORM_FRACONE / - device->Frequency); + state->step = float2int(props->Modulator.Frequency*WAVEFORM_FRACONE/device->Frequency + 0.5f); state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); /* Custom filter coeffs, which match the old version instead of a low-shelf. */ diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9fc65a48..12e78bdf 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -463,7 +463,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const /* All line lengths are powers of 2, calculated from their lengths in * seconds, rounded up. */ - samples = fastf2i(ceilf(length*frequency)); + samples = float2int(ceilf(length*frequency)); samples = NextPowerOf2(samples + extra); /* All lines share a single sample buffer. */ @@ -565,9 +565,9 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev multiplier = CalcDelayLengthMult(AL_EAXREVERB_MAX_DENSITY); /* The late feed taps are set a fixed position past the latest delay tap. */ - State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * - frequency); + State->LateFeedTap = float2int((AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * + frequency); return AL_TRUE; } @@ -949,13 +949,13 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, for(i = 0;i < NUM_LINES;i++) { length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayTap[i][1] = fastf2i(length * frequency); + State->EarlyDelayTap[i][1] = float2int(length * frequency); length = EARLY_TAP_LENGTHS[i]*multiplier; State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime); length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; - State->LateDelayTap[i][1] = State->LateFeedTap + fastf2i(length * frequency); + State->LateDelayTap[i][1] = State->LateFeedTap + float2int(length * frequency); } } @@ -973,13 +973,13 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c length = EARLY_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Early->VecAp.Offset[i][1] = fastf2i(length * frequency); + Early->VecAp.Offset[i][1] = float2int(length * frequency); /* Calculate the length (in seconds) of each delay line. */ length = EARLY_LINE_LENGTHS[i] * multiplier; /* Calculate the delay offset for each delay line. */ - Early->Offset[i][1] = fastf2i(length * frequency); + Early->Offset[i][1] = float2int(length * frequency); /* Calculate the gain (coefficient) for each line. */ Early->Coeff[i] = CalcDecayCoeff(length, decayTime); @@ -1026,7 +1026,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = LATE_ALLPASS_LENGTHS[i] * multiplier; /* Calculate the delay offset for each all-pass line. */ - Late->VecAp.Offset[i][1] = fastf2i(length * frequency); + Late->VecAp.Offset[i][1] = float2int(length * frequency); /* Calculate the length (in seconds) of each delay line. This also * applies the echo transformation. As the EAX echo depth approaches @@ -1036,7 +1036,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth); /* Calculate the delay offset for each delay line. */ - Late->Offset[i][1] = fastf2i(length*frequency + 0.5f); + Late->Offset[i][1] = float2int(length*frequency + 0.5f); /* Approximate the absorption that the vector all-pass would exhibit * given the current diffusion so we don't have to process a full T60 diff --git a/Alc/helpers.c b/Alc/helpers.c index c4fb7a8c..c311ea2e 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -124,6 +124,7 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x extern inline ALuint NextPowerOf2(ALuint value); extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); +extern inline int float2int(float f); #ifndef __GNUC__ #if defined(HAVE_BITSCANFORWARD64_INTRINSIC) extern inline int msvc64_ctz64(ALuint64 v); diff --git a/Alc/hrtf.c b/Alc/hrtf.c index affb6c27..810530e5 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -74,31 +74,29 @@ static struct HrtfEntry *LoadedHrtfs = NULL; /* Calculate the elevation index given the polar elevation in radians. This - * will return an index between 0 and (evcount - 1). Assumes the FPU is in - * round-to-zero mode. + * will return an index between 0 and (evcount - 1). */ static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu) { ALsizei idx; ev = (F_PI_2+ev) * (evcount-1) / F_PI; - idx = mini(fastf2i(ev), evcount-1); + idx = float2int(ev); *mu = ev - idx; - return idx; + return mini(idx, evcount-1); } /* Calculate the azimuth index given the polar azimuth in radians. This will - * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to- - * zero mode. + * return an index between 0 and (azcount - 1). */ static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu) { ALsizei idx; az = (F_TAU+az) * azcount / F_TAU; - idx = fastf2i(az) % azcount; - *mu = az - floorf(az); - return idx; + idx = float2int(az); + *mu = az - idx; + return idx % azcount; } /* Calculates static HRIR coefficients and delays for the given polar elevation @@ -158,11 +156,11 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, blend[3] = ( emu) * ( amu[1]) * dirfact; /* Calculate the blended HRIR delays. */ - delays[0] = fastf2i( + delays[0] = float2int( Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + 0.5f ); - delays[1] = fastf2i( + delays[1] = float2int( Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f ); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 78dd01c5..1cf1e5e2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -260,6 +260,13 @@ inline ALint fastf2i(ALfloat f) #endif } +/* Converts float-to-int using standard behavior (truncation). */ +inline int float2int(float f) +{ + /* TODO: Make a more efficient method for x87. */ + return (ALint)f; +} + enum DevProbe { ALL_DEVICE_PROBE, -- cgit v1.2.3 From 75e2cb97f74aeed2e50e4355607f041414a43976 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 May 2018 02:05:26 -0700 Subject: Don't assume round-to-zero for fastf2i --- Alc/ALu.c | 6 +++--- Alc/fpu_modes.h | 17 +++++++-------- Alc/helpers.c | 53 +++++++---------------------------------------- OpenAL32/Include/alMain.h | 50 +++++++++++++++++++++++++------------------- 4 files changed, 47 insertions(+), 79 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 0c930a29..81914850 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1092,7 +1092,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + voice->Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); if(props->Resampler == BSinc24Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); else if(props->Resampler == BSinc12Resampler) @@ -1453,7 +1453,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop if(Pitch > (ALfloat)MAX_PITCH) voice->Step = MAX_PITCH<Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + voice->Step = maxi(fastf2i(Pitch * FRACTIONONE), 1); if(props->Resampler == BSinc24Resampler) BsincPrepare(voice->Step, &voice->ResampleState.bsinc, &bsinc24); else if(props->Resampler == BSinc12Resampler) @@ -1663,7 +1663,7 @@ static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_ ALuint rng0 = dither_rng(&seed); ALuint rng1 = dither_rng(&seed); val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - samples[i] = roundf(val) * invscale; + samples[i] = fastf2i(val) * invscale; } } *dither_seed = seed; diff --git a/Alc/fpu_modes.h b/Alc/fpu_modes.h index 750252fc..eb305967 100644 --- a/Alc/fpu_modes.h +++ b/Alc/fpu_modes.h @@ -7,16 +7,13 @@ typedef struct FPUCtl { -#ifdef HAVE_FENV_H - fenv_t flt_env; -#ifdef _WIN32 - int round_mode; -#endif -#else - int state; -#endif -#ifdef HAVE_SSE - int sse_state; +#if defined(__GNUC__) && defined(HAVE_SSE) + unsigned int sse_state; +#elif defined(HAVE___CONTROL87_2) + unsigned int state; + unsigned int sse_state; +#elif defined(HAVE__CONTROLFP) + unsigned int state; #endif } FPUCtl; void SetMixerFPUMode(FPUCtl *ctl); diff --git a/Alc/helpers.c b/Alc/helpers.c index c311ea2e..7bcb3f4a 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -269,81 +269,44 @@ void FillCPUCaps(int capfilter) void SetMixerFPUMode(FPUCtl *ctl) { -#ifdef HAVE_FENV_H - fegetenv(&ctl->flt_env); -#ifdef _WIN32 - /* HACK: A nasty bug in MinGW-W64 causes fegetenv and fesetenv to not save - * and restore the FPU rounding mode, so we have to do it manually. Don't - * know if this also applies to MSVC. - */ - ctl->round_mode = fegetround(); -#endif -#if defined(__GNUC__) && defined(HAVE_SSE) - /* FIXME: Some fegetenv implementations can get the SSE environment too? - * How to tell when it does? */ - 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 = ctl->sse_state; - sseState |= 0x6000; /* set round-to-zero */ + __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); + unsigned int sseState = ctl->sse_state; 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, _MCW_RC, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - { - __control87_2(0, 0, NULL, &ctl->sse_state); - __control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode); - } -#endif + __control87_2(0, 0, &ctl->state, &ctl->sse_state); + _control87(_DN_FLUSH, _MCW_DN); #elif defined(HAVE__CONTROLFP) ctl->state = _controlfp(0, 0); - (void)_controlfp(_RC_CHOP, _MCW_RC); + _controlfp(_DN_FLUSH, _MCW_DN); #endif } void RestoreFPUMode(const FPUCtl *ctl) { -#ifdef HAVE_FENV_H - fesetenv(&ctl->flt_env); -#ifdef _WIN32 - fesetround(ctl->round_mode); -#endif #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, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - __control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode); -#endif + __control87_2(ctl->state, _MCW_DN, &mode, NULL); + __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode); #elif defined(HAVE__CONTROLFP) - _controlfp(ctl->state, _MCW_RC); + _controlfp(ctl->state, _MCW_DN); #endif } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 1cf1e5e2..0cab5a17 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -226,36 +226,44 @@ inline size_t RoundUp(size_t value, size_t r) return value - (value%r); } -/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero - * mode. */ +/* Fast float-to-int conversion. No particular rounding mode is assumed; the + * IEEE-754 default is round-to-nearest with ties-to-even, though an app could + * change it on its own threads. On some systems, a truncating conversion may + * always be the fastest method. + */ inline ALint fastf2i(ALfloat f) { -#if (defined(__i386__) && !defined(__SSE_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP == 0)) -/* If using the x87 instruction set, try to use more efficient float-to-int - * operations. The fistp instruction converts to integer efficiently enough, - * but it isn't IEEE-754-compliant because it uses the current rounding mode - * instead of always truncating -- the compiler will generate costly control - * word changes with it to get correct behavior. If supported, lrintf converts - * to integer using the current rounding mode, i.e. using fistp without control - * word changes (if nothing even better is available). As long as the rounding - * mode is set to round-to-zero ahead of time, and the call gets inlined, this - * works fine. - * - * Other instruction sets, like SSE and ARM, have opcodes that inherently do - * the right thing, and don't suffer from the same excessive performance - * degredation from float-to-int conversions. - */ -#ifdef HAVE_LRINTF - return lrintf(f); -#elif defined(_MSC_VER) && defined(_M_IX86) +#if defined(_MSC_VER) && defined(_M_IX86_FP) ALint i; +#if _M_IX86_FP > 0 + __asm cvtss2si i, f +#else __asm fld f __asm fistp i +#endif return i; + +#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + + ALint i; +#ifdef __SSE_MATH__ + __asm__("cvtss2si %1, %0" : "=r"(i) : "x"(f)); #else - return (ALint)f; + __asm__("flds %1\n fistps %0" : "=m"(i) : "m"(f)); #endif + return i; + + /* On GCC when compiling with -fno-math-errno, lrintf can be inlined to + * some simple instructions. Clang does not inline it, always generating a + * libc call, while MSVC's implementation is horribly slow, so always fall + * back to a normal integer conversion for them. + */ +#elif defined(HAVE_LRINTF) && !defined(_MSC_VER) && !defined(__clang__) + + return lrintf(f); + #else + return (ALint)f; #endif } -- cgit v1.2.3 From b31a54e97217ca0b6737f4f8de82fd50e34f64c9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 May 2018 02:56:01 -0700 Subject: Try to fix 32-bit MSVC builds --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 0cab5a17..fa29069f 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -236,7 +236,7 @@ inline ALint fastf2i(ALfloat f) #if defined(_MSC_VER) && defined(_M_IX86_FP) ALint i; #if _M_IX86_FP > 0 - __asm cvtss2si i, f + __asm { cvtss2si i, f } #else __asm fld f __asm fistp i -- cgit v1.2.3 From 1fb6428ffa2fe7030c3ccdffbe985ff184af0829 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 May 2018 04:02:57 -0700 Subject: Another fix attempt for 32-bit MSVC --- OpenAL32/Include/alMain.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index fa29069f..e29d9c27 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -233,14 +233,14 @@ inline size_t RoundUp(size_t value, size_t r) */ inline ALint fastf2i(ALfloat f) { -#if defined(_MSC_VER) && defined(_M_IX86_FP) +#if defined(HAVE_INTRIN_H) && ((defined(_M_IX86_FP) && (_M_IX86_FP > 0)) || defined(_M_X64)) + return _mm_cvt_ss2si(_mm_set1_ps(f)); + +#elif defined(_MSC_VER) && defined(_M_IX86_FP) + ALint i; -#if _M_IX86_FP > 0 - __asm { cvtss2si i, f } -#else __asm fld f __asm fistp i -#endif return i; #elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) -- cgit v1.2.3 From be30e6bf8ff02536d092af3fe5bb847a57ee1fbf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 May 2018 04:53:50 -0700 Subject: Don't assume the FPU is round-to-zero in the pitch shifter --- Alc/effects/pshifter.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 61857343..bf36f5eb 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -106,28 +106,10 @@ static void InitHannWindow(void) static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; -/* Fast double-to-int conversion. Assumes the FPU is already in round-to-zero - * mode. */ -static inline ALint fastd2i(ALdouble d) +static inline ALint double2int(ALdouble d) { - /* NOTE: SSE2 is required for the efficient double-to-int opcodes on x86. - * Otherwise, we need to rely on x87's fistp opcode with it already in - * round-to-zero mode. x86-64 guarantees SSE2 support. - */ -#if (defined(__i386__) && !defined(__SSE2_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP < 2)) -#ifdef HAVE_LRINTF - return lrint(d); -#elif defined(_MSC_VER) && defined(_M_IX86) - ALint i; - __asm fld d - __asm fistp i - return i; -#else - return (ALint)d; -#endif -#else + /* TODO: Make a more efficient version for x87. */ return (ALint)d; -#endif } @@ -349,7 +331,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD tmp = (component.Phase - state->LastPhase[k]) - k*expected; /* Map delta phase into +/- Pi interval */ - qpd = fastd2i(tmp / M_PI); + qpd = double2int(tmp / M_PI); tmp -= M_PI * (qpd + (qpd%2)); /* Get deviation from bin frequency from the +/- Pi interval */ -- cgit v1.2.3 From 3867cad94de7e1ddc1538e25d77e30381bf4bb40 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 May 2018 06:48:20 -0700 Subject: Simplify calculating the HRTF B-Format IR length --- Alc/hrtf.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 810530e5..71ab7921 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -204,8 +204,9 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N ALdouble (*tmpres)[HRIR_LENGTH][2]; ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; ALsizei min_delay = HRTF_HISTORY_LENGTH; + ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; - ALsizei max_length = 0; + ALsizei max_length; ALsizei i, c, b; for(c = 0;c < AmbiCount;c++) @@ -228,6 +229,7 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N idx[c] = evoffset + azidx; min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); + max_delay = maxi(max_delay, maxi(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1])); } tmpres = al_calloc(16, NumChannels * sizeof(*tmpres)); @@ -242,10 +244,6 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N if(NUM_BANDS == 1) { - max_length = maxi(max_length, - mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH) - ); - for(i = 0;i < NumChannels;++i) { ALdouble mult = (ALdouble)AmbiOrderHFGain[(ALsizei)sqrt(i)] * AmbiMatrix[c][i]; @@ -261,15 +259,6 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } else { - /* Increase the IR size by 2/3rds to account for the tail generated - * by the band-split filter. - */ - const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH); - - max_length = maxi(max_length, - mini(maxi(ldelay, rdelay) + irsize, HRIR_LENGTH) - ); - /* Band-split left HRIR into low and high frequency responses. */ bandsplit_clear(&splitter); for(i = 0;i < Hrtf->irSize;i++) @@ -311,9 +300,6 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } } } - /* Round up to the next IR size multiple. */ - max_length += MOD_IR_SIZE-1; - max_length -= max_length%MOD_IR_SIZE; for(i = 0;i < NumChannels;++i) { @@ -324,11 +310,25 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N state->Chan[i].Coeffs[idx][1] = (ALfloat)tmpres[i][idx][1]; } } - al_free(tmpres); tmpres = NULL; - TRACE("Skipped delay: %d, new FIR length: %d\n", min_delay, max_length); + if(NUM_BANDS == 1) + max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH); + else + { + /* Increase the IR size by 2/3rds to account for the tail generated by + * the band-split filter. + */ + const ALsizei irsize = mini(Hrtf->irSize*5/3, HRIR_LENGTH); + max_length = mini(max_delay-min_delay + irsize, HRIR_LENGTH); + } + /* Round up to the next IR size multiple. */ + max_length += MOD_IR_SIZE-1; + max_length -= max_length%MOD_IR_SIZE; + + TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n", + min_delay, max_delay-min_delay, max_length); state->IrSize = max_length; #undef NUM_BANDS } -- cgit v1.2.3 From e787a241c0e96b890f2173ec71aa02b5b9411ec6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 May 2018 00:52:09 -0700 Subject: Add and use a method for fast float rounding Unlike fastf2i, this keeps the result as a float instead of converting to integer. --- Alc/ALu.c | 2 +- Alc/helpers.c | 1 + OpenAL32/Include/alMain.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 81914850..9d7fcdd5 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1663,7 +1663,7 @@ static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_ ALuint rng0 = dither_rng(&seed); ALuint rng1 = dither_rng(&seed); val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX)); - samples[i] = fastf2i(val) * invscale; + samples[i] = fast_roundf(val) * invscale; } } *dither_seed = seed; diff --git a/Alc/helpers.c b/Alc/helpers.c index 7bcb3f4a..e54f3fb2 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -125,6 +125,7 @@ extern inline ALuint NextPowerOf2(ALuint value); extern inline size_t RoundUp(size_t value, size_t r); extern inline ALint fastf2i(ALfloat f); extern inline int float2int(float f); +extern inline float fast_roundf(float f); #ifndef __GNUC__ #if defined(HAVE_BITSCANFORWARD64_INTRINSIC) extern inline int msvc64_ctz64(ALuint64 v); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index e29d9c27..59f96ab1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -275,6 +275,60 @@ inline int float2int(float f) return (ALint)f; } +/* Rounds a float to the nearest integral value, according to the current + * rounding mode. This is essentially an inlined version of rintf, although + * makes fewer promises (e.g. -0 or -0.25 rounded to 0 may result in +0). + */ +inline float fast_roundf(float f) +{ +#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE_MATH__) + + float out; + __asm__ __volatile__("frndint" : "=t"(out) : "0"(f)); + return out; + +#else + + /* Integral limit, where sub-integral precision is not available for + * floats. + */ + static const float ilim[2] = { + 8388608.0f /* 0x1.0p+23 */, + -8388608.0f /* -0x1.0p+23 */ + }; + uint32_t sign, expo; + union { + float f; + uint32_t i; + } conv; + + conv.f = f; + sign = (conv.i>>31)&0x01; + expo = (conv.i>>23)&0xff; + + if(UNLIKELY(expo >= 150/*+23*/)) + { + /* An exponent (base-2) of 23 or higher is incapable of sub-integral + * precision, so it's already an integral value. We don't need to worry + * about infinity or NaN here. + */ + return f; + } + /* Adding the integral limit to the value (with a matching sign) forces a + * result that has no sub-integral precision, and is consequently forced to + * round to an integral value. Removing the integral limit then restores + * the initial value rounded to the integral. The compiler should not + * optimize this out because of non-associative rules on floating-point + * math (as long as you don't use -fassociative-math, + * -funsafe-math-optimizations, -ffast-math, or -Ofast, in which case this + * may break). + */ + f += ilim[sign]; + return f - ilim[sign]; +#endif +} + enum DevProbe { ALL_DEVICE_PROBE, -- cgit v1.2.3 From f240952bcc6edc9a36a40bc82b97e19a551b4ddf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 May 2018 00:58:27 -0700 Subject: Fix non-SEE (32-bit) GCC builds --- OpenAL32/Include/alMain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 59f96ab1..147ce08e 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -249,7 +249,7 @@ inline ALint fastf2i(ALfloat f) #ifdef __SSE_MATH__ __asm__("cvtss2si %1, %0" : "=r"(i) : "x"(f)); #else - __asm__("flds %1\n fistps %0" : "=m"(i) : "m"(f)); + __asm__ __volatile__("fistpl %0" : "=m"(i) : "t"(f) : "st"); #endif return i; -- cgit v1.2.3 From 5c0673049c0b4ebf3ac15c834e8d222d8c7ae5a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 May 2018 03:31:58 -0700 Subject: Fix MSVC --- OpenAL32/Include/alMain.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 147ce08e..c02d6b47 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -297,10 +297,10 @@ inline float fast_roundf(float f) 8388608.0f /* 0x1.0p+23 */, -8388608.0f /* -0x1.0p+23 */ }; - uint32_t sign, expo; + ALuint sign, expo; union { - float f; - uint32_t i; + ALfloat f; + ALuint i; } conv; conv.f = f; -- cgit v1.2.3 From dd055fc8586a7409ba52ca399370a8bad7d99c64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 May 2018 21:36:23 -0700 Subject: Use fastf2i instead of manually rounding with float2int --- Alc/hrtf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 71ab7921..b0bd22d2 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -156,13 +156,13 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, blend[3] = ( emu) * ( amu[1]) * dirfact; /* Calculate the blended HRIR delays. */ - delays[0] = float2int( + delays[0] = fastf2i( Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] + - Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + 0.5f + Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] ); - delays[1] = float2int( + delays[1] = fastf2i( Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] + - Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f + Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] ); /* Calculate the sample offsets for the HRIR indices. */ -- cgit v1.2.3 From 1e04c4c6899ba6481ce9153a2c8a3a57bae33dd5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 May 2018 22:34:15 -0700 Subject: Make a faster float2int method for x87 targets --- OpenAL32/Include/alMain.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index c02d6b47..253b2870 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -271,8 +271,31 @@ inline ALint fastf2i(ALfloat f) /* Converts float-to-int using standard behavior (truncation). */ inline int float2int(float f) { - /* TODO: Make a more efficient method for x87. */ +#if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0) + ALint sign, shift, mant; + union { + ALfloat f; + ALint i; + } conv; + + conv.f = f; + sign = (conv.i>>31) | 1; + shift = ((conv.i>>23)&0xff) - (127+23); + + /* Over/underflow */ + if(UNLIKELY(shift >= 31 || shift < -23)) + return 0; + + mant = (conv.i&0x7fffff) | 0x800000; + if(LIKELY(shift < 0)) + return (mant >> -shift) * sign; + return (mant << shift) * sign; + +#else + return (ALint)f; +#endif } /* Rounds a float to the nearest integral value, according to the current -- cgit v1.2.3 From 5272caf7f4cf295d3fd7ca5d70b732c9aae5978f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 May 2018 00:20:31 -0700 Subject: More accurately convert between degrees and radians --- common/math_defs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/math_defs.h b/common/math_defs.h index 8ce93d0a..04d73f42 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -40,7 +40,7 @@ static inline float cbrtf(float f) } #endif -#define DEG2RAD(x) ((float)(x) * (F_PI/180.0f)) -#define RAD2DEG(x) ((float)(x) * (180.0f/F_PI)) +#define DEG2RAD(x) ((float)(x) * (float)(M_PI/180.0)) +#define RAD2DEG(x) ((float)(x) * (float)(180.0/M_PI)) #endif /* AL_MATH_DEFS_H */ -- cgit v1.2.3 From df9faba68972bf3d4aafeae5fc61d5af1b525efe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 May 2018 05:28:06 -0700 Subject: Use more accurate elevations for virtual HRTF speaker positions --- Alc/panning.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index 7f9e74e2..aaf3f2ca 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -816,10 +816,10 @@ static void InitHrtfPanning(ALCdevice *device) /* NOTE: azimuth goes clockwise. */ static const struct AngularPoint AmbiPoints[] = { { DEG2RAD( 90.0f), DEG2RAD( 0.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( 135.0f) }, - { DEG2RAD( 35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD( 35.0f), DEG2RAD( -45.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( 45.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( 135.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD(-135.0f) }, + { DEG2RAD( 35.2643897f), DEG2RAD( -45.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 0.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 45.0f) }, { DEG2RAD( 0.0f), DEG2RAD( 90.0f) }, @@ -828,10 +828,10 @@ static void InitHrtfPanning(ALCdevice *device) { DEG2RAD( 0.0f), DEG2RAD(-135.0f) }, { DEG2RAD( 0.0f), DEG2RAD( -90.0f) }, { DEG2RAD( 0.0f), DEG2RAD( -45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 45.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( 135.0f) }, - { DEG2RAD(-35.0f), DEG2RAD(-135.0f) }, - { DEG2RAD(-35.0f), DEG2RAD( -45.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( 45.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( 135.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD(-135.0f) }, + { DEG2RAD(-35.2643897f), DEG2RAD( -45.0f) }, { DEG2RAD(-90.0f), DEG2RAD( 0.0f) }, }; static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = { -- cgit v1.2.3 From 43dccc880703d6e07e86a32e38c5c4cac235016f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 May 2018 18:00:43 -0700 Subject: Add a faster double-to-int converter for x87 builds --- Alc/effects/pshifter.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index bf36f5eb..7411f705 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -108,8 +108,32 @@ static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; static inline ALint double2int(ALdouble d) { - /* TODO: Make a more efficient version for x87. */ +#if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \ + !defined(__SSE2_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) + ALint sign, shift; + ALint64 mant; + union { + ALdouble d; + ALint64 i64; + } conv; + + conv.d = d; + sign = (conv.i64>>63) | 1; + shift = ((conv.i64>>52)&0x7ff) - (1023+52); + + /* Over/underflow */ + if(UNLIKELY(shift >= 63 || shift < -52)) + return 0; + + mant = (conv.i64&U64(0xfffffffffffff)) | U64(0x10000000000000); + if(LIKELY(shift < 0)) + return (ALint)(mant >> -shift) * sign; + return (ALint)(mant << shift) * sign; + +#else + return (ALint)d; +#endif } -- cgit v1.2.3 From 4ee04cd444e770fb12adf607c9711f7d892f76bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 14 May 2018 23:41:29 -0700 Subject: Use a step counter for gain stepping This should provide more stable stepping, preventing floating-point errors from accumulating on each step/sample. --- Alc/mixer/hrtf_inc.c | 39 ++++++++++++++++------------- Alc/mixer/mixer_c.c | 7 ++++-- Alc/mixer/mixer_neon.c | 66 +++++++++++++++++++++++++++++--------------------- Alc/mixer/mixer_sse.c | 64 ++++++++++++++++++++++++++---------------------- 4 files changed, 100 insertions(+), 76 deletions(-) diff --git a/Alc/mixer/hrtf_inc.c b/Alc/mixer/hrtf_inc.c index d6bd8042..3ef22f24 100644 --- a/Alc/mixer/hrtf_inc.c +++ b/Alc/mixer/hrtf_inc.c @@ -22,8 +22,9 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, { const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16); const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] }; - ALfloat gainstep = hrtfparams->GainStep; - ALfloat gain = hrtfparams->Gain; + const ALfloat gainstep = hrtfparams->GainStep; + const ALfloat gain = hrtfparams->Gain; + ALfloat g, stepcount = 0.0f; ALfloat left, right; ALsizei i; @@ -35,8 +36,10 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, for(i = 0;i < BufferSize;i++) { hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain; - right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain; + + g = gain + gainstep*stepcount; + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g; hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f; hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f; @@ -45,10 +48,10 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - gain += gainstep; + stepcount += 1.0f; Offset++; } - hrtfparams->Gain = gain; + hrtfparams->Gain = gain + gainstep*stepcount; } void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, @@ -59,12 +62,13 @@ void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, { const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16); const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] }; - ALfloat oldGain = oldparams->Gain; - ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; + const ALfloat oldGain = oldparams->Gain; + const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize; const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16); const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] }; - ALfloat newGain = newparams->Gain; - ALfloat newGainStep = newparams->GainStep; + const ALfloat newGain = newparams->Gain; + const ALfloat newGainStep = newparams->GainStep; + ALfloat g, stepcount = 0.0f; ALfloat left, right; ALsizei i; @@ -80,22 +84,23 @@ void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++); - left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain; - right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain; + g = oldGain + oldGainStep*stepcount; + left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right); - left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain; - right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain; + g = newGain + newGainStep*stepcount; + left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g; + right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right); *(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0]; *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1]; - oldGain += oldGainStep; - newGain += newGainStep; + stepcount += 1.0f; Offset++; } - newparams->Gain = newGain; + newparams->Gain = newGain + newGainStep*stepcount; } void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut, diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 84485206..25149e00 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -134,13 +134,16 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[ if(fabsf(step) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + ALfloat step_count = 0.0f; for(;pos < minsize;pos++) { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; + OutBuffer[c][OutPos+pos] += data[pos] * (gain + step*step_count); + step_count += 1.0f; } if(pos == Counter) gain = TargetGains[c]; + else + gain += step*step_count; CurrentGains[c] = gain; } diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 1a5e8ee7..b6181b42 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -165,8 +165,7 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { - ALfloat gain, delta, step; - float32x4_t gain4; + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; ALsizei c; ASSUME(OutChans > 0); @@ -174,47 +173,54 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe data = ASSUME_ALIGNED(data, 16); OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; - for(c = 0;c < OutChans;c++) { ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; + ALfloat gain = CurrentGains[c]; + const ALfloat step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + ALfloat step_count = 0.0f; /* Mix with applying gain steps in aligned multiples of 4. */ - if(minsize-pos > 3) + if(LIKELY(minsize > 3)) { - float32x4_t step4; - gain4 = vsetq_lane_f32(gain, gain4, 0); - gain4 = vsetq_lane_f32(gain + step, gain4, 1); - gain4 = vsetq_lane_f32(gain + step + step, gain4, 2); - gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3); - step4 = vdupq_n_f32(step + step + step + step); + const float32x4_t four4 = vdupq_n_f32(4.0f); + const float32x4_t step4 = vdupq_n_f32(step); + const float32x4_t gain4 = vdupq_n_f32(gain); + float32x4_t step_count4 = vsetq_lane_f32(0.0f, + vsetq_lane_f32(1.0f, + vsetq_lane_f32(2.0f, + vsetq_lane_f32(3.0f, vdupq_n_f32(0.0f), 3), + 2), 1), 0 + ); + ALsizei todo = minsize >> 2; + do { const float32x4_t val4 = vld1q_f32(&data[pos]); float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - gain4 = vaddq_f32(gain4, step4); + dry4 = vmlaq_f32(dry4, val4, vmlaq_f32(gain4, step4, step_count4)); + step_count4 = vaddq_f32(step_count4, four4); vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); pos += 4; - } while(minsize-pos > 3); - /* NOTE: gain4 now represents the next four gains after the - * last four mixed samples, so the lowest element represents - * the next gain to apply. + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. */ - gain = vgetq_lane_f32(gain4, 0); + step_count = vgetq_lane_f32(step_count4, 0); } /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ for(;pos < minsize;pos++) { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; + OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; } if(pos == Counter) gain = TargetGains[c]; + else + gain += step*step_count; CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ @@ -225,13 +231,17 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; - gain4 = vdupq_n_f32(gain); - for(;BufferSize-pos > 3;pos += 4) + if(LIKELY(BufferSize-pos > 3)) { - const float32x4_t val4 = vld1q_f32(&data[pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + ALsizei todo = (BufferSize-pos) >> 2; + const float32x4_t gain4 = vdupq_n_f32(gain); + do { + const float32x4_t val4 = vld1q_f32(&data[pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(--todo); } for(;pos < BufferSize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index a178477f..fa79eb4d 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -135,55 +135,57 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { - ALfloat gain, delta, step; - __m128 gain4; + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; ALsizei c; ASSUME(OutChans > 0); ASSUME(BufferSize > 0); - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) { ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; + ALfloat gain = CurrentGains[c]; + const ALfloat step = (TargetGains[c] - gain) * delta; + if(fabsf(step) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + ALfloat step_count = 0.0f; /* Mix with applying gain steps in aligned multiples of 4. */ - if(minsize-pos > 3) + if(LIKELY(minsize > 3)) { - __m128 step4; - gain4 = _mm_setr_ps( - gain, - gain + step, - gain + step + step, - gain + step + step + step - ); - step4 = _mm_set1_ps(step + step + step + step); + const __m128 four4 = _mm_set1_ps(4.0f); + const __m128 step4 = _mm_set1_ps(step); + const __m128 gain4 = _mm_set1_ps(gain); + __m128 step_count4 = _mm_setr_ps(0.0f, 1.0f, 2.0f, 3.0f); + ALsizei todo = minsize >> 2; do { const __m128 val4 = _mm_load_ps(&data[pos]); __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - gain4 = _mm_add_ps(gain4, step4); +#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) + /* dry += val * (gain + step*step_count) */ + dry4 = MLA4(dry4, val4, MLA4(gain4, step4, step_count4)); +#undef MLA4 _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + step_count4 = _mm_add_ps(step_count4, four4); pos += 4; - } while(minsize-pos > 3); - /* NOTE: gain4 now represents the next four gains after the - * last four mixed samples, so the lowest element represents - * the next gain to apply. + } while(--todo); + /* NOTE: step_count4 now represents the next four counts after + * the last four mixed samples, so the lowest element + * represents the next step count to apply. */ - gain = _mm_cvtss_f32(gain4); + step_count = _mm_cvtss_f32(step_count4); } /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ for(;pos < minsize;pos++) { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain += step; + OutBuffer[c][OutPos+pos] += data[pos]*(gain + step*step_count); + step_count += 1.0f; } if(pos == Counter) gain = TargetGains[c]; + else + gain += step*step_count; CurrentGains[c] = gain; /* Mix until pos is aligned with 4 or the mix is done. */ @@ -194,13 +196,17 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; - gain4 = _mm_set1_ps(gain); - for(;BufferSize-pos > 3;pos += 4) + if(LIKELY(BufferSize-pos > 3)) { - const __m128 val4 = _mm_load_ps(&data[pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + ALsizei todo = (BufferSize-pos) >> 2; + const __m128 gain4 = _mm_set1_ps(gain); + do { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); + pos += 4; + } while(--todo); } for(;pos < BufferSize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; -- cgit v1.2.3 From 4ac488991265ce212109e7b419f18399d3b75ee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 00:53:12 -0700 Subject: Avoid unnecessary function-like macros --- OpenAL32/Include/alMain.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 253b2870..14deb227 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -121,9 +121,9 @@ typedef ALuint64SOFT ALuint64; #ifdef __GNUC__ #if SIZEOF_LONG == 8 -#define CTZ64(x) __builtin_ctzl(x) +#define CTZ64 __builtin_ctzl #else -#define CTZ64(x) __builtin_ctzll(x) +#define CTZ64 __builtin_ctzll #endif #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC) @@ -134,7 +134,7 @@ inline int msvc64_ctz64(ALuint64 v) _BitScanForward64(&idx, v); return (int)idx; } -#define CTZ64(x) msvc64_ctz64(x) +#define CTZ64 msvc64_ctz64 #elif defined(HAVE_BITSCANFORWARD_INTRINSIC) @@ -148,7 +148,7 @@ inline int msvc_ctz64(ALuint64 v) } return (int)idx; } -#define CTZ64(x) msvc_ctz64(x) +#define CTZ64 msvc_ctz64 #else @@ -171,7 +171,7 @@ inline int fallback_ctz64(ALuint64 value) { return fallback_popcnt64(~value & (value - 1)); } -#define CTZ64(x) fallback_ctz64(x) +#define CTZ64 fallback_ctz64 #endif static const union { -- cgit v1.2.3 From 197e88cdcc62ac1c9e8be2240c52c4f108ac27b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 01:20:39 -0700 Subject: Avoid using unsigned values for signed --- Alc/effects/pshifter.c | 2 +- OpenAL32/Include/alMain.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 7411f705..9c2bb2e9 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -125,7 +125,7 @@ static inline ALint double2int(ALdouble d) if(UNLIKELY(shift >= 63 || shift < -52)) return 0; - mant = (conv.i64&U64(0xfffffffffffff)) | U64(0x10000000000000); + mant = (conv.i64&I64(0xfffffffffffff)) | I64(0x10000000000000); if(LIKELY(shift < 0)) return (ALint)(mant >> -shift) * sign; return (ALint)(mant << shift) * sign; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 14deb227..886f3ab1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -115,6 +115,16 @@ typedef ALuint64SOFT ALuint64; #endif #endif +#ifndef I64 +#if defined(_MSC_VER) +#define I64(x) ((ALint64)(x##i64)) +#elif SIZEOF_LONG == 8 +#define I64(x) ((ALint64)(x##l)) +#elif SIZEOF_LONG_LONG == 8 +#define I64(x) ((ALint64)(x##ll)) +#endif +#endif + /* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result * is *UNDEFINED* if the value is 0. */ -- cgit v1.2.3 From 2b9064cb6e4ec08b00619f5d61fd81d2a4f2c4f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 18:31:41 -0700 Subject: Move the ALcomplex and FFT functions to a separate file --- Alc/effects/pshifter.c | 107 ++++--------------------------------------------- CMakeLists.txt | 2 + common/alcomplex.c | 62 ++++++++++++++++++++++++++++ common/alcomplex.h | 62 ++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 99 deletions(-) create mode 100644 common/alcomplex.c create mode 100644 common/alcomplex.h diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index 9c2bb2e9..f27c413c 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -29,6 +29,8 @@ #include "alu.h" #include "filters/defs.h" +#include "alcomplex.h" + #define STFT_SIZE 1024 #define STFT_HALF_SIZE (STFT_SIZE>>1) @@ -37,10 +39,6 @@ #define STFT_STEP (STFT_SIZE / OVERSAMP) #define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1)) -typedef struct ALcomplex { - ALdouble Real; - ALdouble Imag; -} ALcomplex; typedef struct ALphasor { ALdouble Amplitude; @@ -52,6 +50,7 @@ typedef struct ALFrequencyDomain { ALdouble Frequency; } ALfrequencyDomain; + typedef struct ALpshifterState { DERIVE_FROM_TYPE(ALeffectState); @@ -149,7 +148,7 @@ static inline ALphasor rect2polar(ALcomplex number) } /* Converts ALphasor to ALcomplex */ -static inline ALcomplex polar2rect(ALphasor number) +static inline ALcomplex polar2rect(ALphasor number) { ALcomplex cartesian; @@ -159,96 +158,6 @@ static inline ALcomplex polar2rect(ALphasor number) return cartesian; } -/* Addition of two complex numbers (ALcomplex format) */ -static inline ALcomplex complex_add(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real + b.Real; - result.Imag = a.Imag + b.Imag; - - return result; -} - -/* Subtraction of two complex numbers (ALcomplex format) */ -static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real - b.Real; - result.Imag = a.Imag - b.Imag; - - return result; -} - -/* Multiplication of two complex numbers (ALcomplex format) */ -static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real*b.Real - a.Imag*b.Imag; - result.Imag = a.Imag*b.Real + a.Real*b.Imag; - - return result; -} - -/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is - * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the - * Discrete Fourier Transform (DFT) of the time domain data stored in - * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers - * (ALcomplex), FFTSize MUST BE power of two. - */ -static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) -{ - ALsizei i, j, k, mask, step, step2; - ALcomplex temp, u, w; - ALdouble arg; - - /* Bit-reversal permutation applied to a sequence of FFTSize items */ - for(i = 1;i < FFTSize-1;i++) - { - for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1) - { - if((i&mask) != 0) - j++; - j <<= 1; - } - j >>= 1; - - if(i < j) - { - temp = FFTBuffer[i]; - FFTBuffer[i] = FFTBuffer[j]; - FFTBuffer[j] = temp; - } - } - - /* Iterative form of Danielson–Lanczos lemma */ - for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) - { - step2 = step >> 1; - arg = M_PI / step2; - - w.Real = cos(arg); - w.Imag = sin(arg) * Sign; - - u.Real = 1.0; - u.Imag = 0.0; - - for(j = 0;j < step2;j++) - { - for(k = j;k < FFTSize;k+=step) - { - temp = complex_mult(FFTBuffer[k+step2], u); - FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp); - FFTBuffer[k] = complex_add(FFTBuffer[k], temp); - } - - u = complex_mult(u, w); - } - } -} - static void ALpshifterState_Construct(ALpshifterState *state) { @@ -295,8 +204,8 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c pitch = powf(2.0f, (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f ); - state->PitchShiftI = (ALsizei)(pitch*FRACTIONONE + 0.5f); - state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); + state->PitchShiftI = fastf2i(pitch*FRACTIONONE); + state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); @@ -337,7 +246,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD /* ANALYSIS */ /* Apply FFT to FFTbuffer data */ - FFT(state->FFTbuffer, STFT_SIZE, -1.0); + complex_fft(state->FFTbuffer, STFT_SIZE, -1.0); /* Analyze the obtained data. Since the real FFT is symmetric, only * STFT_HALF_SIZE+1 samples are needed. @@ -417,7 +326,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD } /* Apply iFFT to buffer data */ - FFT(state->FFTbuffer, STFT_SIZE, 1.0); + complex_fft(state->FFTbuffer, STFT_SIZE, 1.0); /* Windowing and add to output */ for(k = 0;k < STFT_SIZE;k++) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a4f8ff4..cd3ecbed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -700,6 +700,8 @@ ENDIF() SET(COMMON_OBJS + common/alcomplex.c + common/alcomplex.h common/align.h common/almalloc.c common/almalloc.h diff --git a/common/alcomplex.c b/common/alcomplex.c new file mode 100644 index 00000000..c1a312e3 --- /dev/null +++ b/common/alcomplex.c @@ -0,0 +1,62 @@ + +#include "config.h" + +#include "alcomplex.h" + +#include + + +extern inline ALcomplex complex_add(ALcomplex a, ALcomplex b); +extern inline ALcomplex complex_sub(ALcomplex a, ALcomplex b); +extern inline ALcomplex complex_mult(ALcomplex a, ALcomplex b); + +void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) +{ + ALsizei i, j, k, mask, step, step2; + ALcomplex temp, u, w; + ALdouble arg; + + /* Bit-reversal permutation applied to a sequence of FFTSize items */ + for(i = 1;i < FFTSize-1;i++) + { + for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1) + { + if((i&mask) != 0) + j++; + j <<= 1; + } + j >>= 1; + + if(i < j) + { + temp = FFTBuffer[i]; + FFTBuffer[i] = FFTBuffer[j]; + FFTBuffer[j] = temp; + } + } + + /* Iterative form of Danielson–Lanczos lemma */ + for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) + { + step2 = step >> 1; + arg = M_PI / step2; + + w.Real = cos(arg); + w.Imag = sin(arg) * Sign; + + u.Real = 1.0; + u.Imag = 0.0; + + for(j = 0;j < step2;j++) + { + for(k = j;k < FFTSize;k+=step) + { + temp = complex_mult(FFTBuffer[k+step2], u); + FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp); + FFTBuffer[k] = complex_add(FFTBuffer[k], temp); + } + + u = complex_mult(u, w); + } + } +} diff --git a/common/alcomplex.h b/common/alcomplex.h new file mode 100644 index 00000000..cf4683fa --- /dev/null +++ b/common/alcomplex.h @@ -0,0 +1,62 @@ +#ifndef ALCOMPLEX_H +#define ALCOMPLEX_H + +#include "AL/al.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALcomplex { + ALdouble Real; + ALdouble Imag; +} ALcomplex; + +/** Addition of two complex numbers. */ +inline ALcomplex complex_add(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real + b.Real; + result.Imag = a.Imag + b.Imag; + + return result; +} + +/** Subtraction of two complex numbers. */ +inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real - b.Real; + result.Imag = a.Imag - b.Imag; + + return result; +} + +/** Multiplication of two complex numbers. */ +inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) +{ + ALcomplex result; + + result.Real = a.Real*b.Real - a.Imag*b.Imag; + result.Imag = a.Imag*b.Real + a.Real*b.Imag; + + return result; +} + +/** + * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is + * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the + * Discrete Fourier Transform (DFT) of the time domain data stored in + * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers, FFTSize + * MUST BE power of two. + */ +void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* ALCOMPLEX_H */ -- cgit v1.2.3 From e42489b3e9e88311b35e738098d71906fa4bfd8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 18:50:32 -0700 Subject: Include math_defs.h to ensure M_PI is defined --- common/alcomplex.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/alcomplex.c b/common/alcomplex.c index c1a312e3..d68277e3 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -2,8 +2,7 @@ #include "config.h" #include "alcomplex.h" - -#include +#include "math_defs.h" extern inline ALcomplex complex_add(ALcomplex a, ALcomplex b); -- cgit v1.2.3 From 6534aa0c2796e53f11ce8b15a4c5c39f6f801191 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 21:46:22 -0700 Subject: Undefine the correct macros --- Alc/hrtf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index b0bd22d2..376c849f 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -1030,12 +1030,12 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename) /* Check if this entry has already been added to the list. */ #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); +#undef MATCH_ENTRY if(iter != VECTOR_END(*list)) { TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); return; } -#undef MATCH_FNAME break; } @@ -1109,12 +1109,12 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam { #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf) VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY); +#undef MATCH_ENTRY if(iter != VECTOR_END(*list)) { TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename)); return; } -#undef MATCH_FNAME break; } -- cgit v1.2.3 From 72e39ba1c93e14f57dc342d0e70f5fb272a6d686 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 22:11:10 -0700 Subject: Fix a function comment --- Alc/hrtf.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Alc/hrtf.h b/Alc/hrtf.h index cb6dfddc..aaffa904 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -81,8 +81,9 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, /** * Produces HRTF filter coefficients for decoding B-Format, given a set of - * virtual speaker positions and HF/LF matrices for decoding to them. The - * returned coefficients are ordered and scaled according to the matrices. + * virtual speaker positions, a matching decoding matrix, and per-order high- + * frequency gains for the decoder. The calculated impulse responses are + * ordered and scaled according to the matrix input. */ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain); -- cgit v1.2.3 From 588a6bcb4f79e4be1cae651dbbc14356d039c91b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 May 2018 23:14:23 -0700 Subject: Simplify counting for SIMD MixRow functions --- Alc/mixer/mixer_neon.c | 19 ++++++++++--------- Alc/mixer/mixer_sse.c | 17 ++++++++++------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index b6181b42..0af977e6 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -250,13 +250,10 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { - float32x4_t gain4; ALsizei c; ASSUME(InChans > 0); ASSUME(BufferSize > 0); - data = ASSUME_ALIGNED(data, 16); - OutBuffer = ASSUME_ALIGNED(OutBuffer, 16); for(c = 0;c < InChans;c++) { @@ -265,13 +262,17 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restr if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; - gain4 = vdupq_n_f32(gain); - for(;BufferSize-pos > 3;pos += 4) + if(LIKELY(BufferSize > 3)) { - const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); - float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); - dry4 = vmlaq_f32(dry4, val4, gain4); - vst1q_f32(&OutBuffer[pos], dry4); + ALsizei todo = BufferSize >> 2; + float32x4_t gain4 = vdupq_n_f32(gain); + do { + const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]); + float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]); + dry4 = vmlaq_f32(dry4, val4, gain4); + vst1q_f32(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); } for(;pos < BufferSize;pos++) OutBuffer[pos] += data[c][InPos+pos]*gain; diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index fa79eb4d..5b4208f9 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -215,7 +215,6 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize) { - __m128 gain4; ALsizei c; ASSUME(InChans > 0); @@ -228,13 +227,17 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restri if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; - gain4 = _mm_set1_ps(gain); - for(;BufferSize-pos > 3;pos += 4) + if(LIKELY(BufferSize > 3)) { - const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[pos], dry4); + ALsizei todo = BufferSize >> 2; + const __m128 gain4 = _mm_set1_ps(gain); + do { + const __m128 val4 = _mm_load_ps(&data[c][InPos+pos]); + __m128 dry4 = _mm_load_ps(&OutBuffer[pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); + _mm_store_ps(&OutBuffer[pos], dry4); + pos += 4; + } while(--todo); } for(;pos < BufferSize;pos++) OutBuffer[pos] += data[c][InPos+pos]*gain; -- cgit v1.2.3 From 0cd375f03c2ab9cc9033dd03481badaa26cc390f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 May 2018 03:52:40 -0700 Subject: Add a function to calculate coefficients from X, Y, Z components --- Alc/panning.c | 9 +++------ OpenAL32/Include/alu.h | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Alc/panning.c b/Alc/panning.c index aaf3f2ca..4a7c592b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -38,6 +38,7 @@ #include "bs2b.h" +extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); extern inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); @@ -67,13 +68,9 @@ static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = { }; -void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat coeffs[MAX_AMBI_COEFFS]) { - /* Convert from OpenAL coords to Ambisonics. */ - ALfloat x = -dir[2]; - ALfloat y = -dir[0]; - ALfloat z = dir[1]; - /* Zeroth-order */ coeffs[0] = 1.0f; /* ACN 0 = 1 */ /* First-order */ diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index b977613c..c09caa65 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -430,14 +430,35 @@ void aluInitEffectPanning(struct ALeffectslot *slot); void aluSelectPostProcess(ALCdevice *device); +/** + * Calculates ambisonic encoder coefficients using the X, Y, and Z direction + * components, which must represent a normalized (unit length) vector, and the + * spread is the angular width of the sound (0...tau). + * + * NOTE: The components use ambisonic coordinates. As a result: + * + * Ambisonic Y = OpenAL -X + * Ambisonic Z = OpenAL Y + * Ambisonic X = OpenAL -Z + * + * The components are ordered such that OpenAL's X, Y, and Z are the first, + * second, and third parameters respectively -- simply negate X and Z. + */ +void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread, + ALfloat coeffs[MAX_AMBI_COEFFS]); + /** * CalcDirectionCoeffs * - * Calculates ambisonic coefficients based on a direction vector. The vector - * must be normalized (unit length), and the spread is the angular width of the - * sound (0...tau). + * Calculates ambisonic coefficients based on an OpenAL direction vector. The + * vector must be normalized (unit length), and the spread is the angular width + * of the sound (0...tau). */ -void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) +{ + /* Convert from OpenAL coords to Ambisonics. */ + CalcAmbiCoeffs(-dir[0], dir[1], -dir[2], spread, coeffs); +} /** * CalcAngleCoeffs @@ -448,12 +469,11 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MA */ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) { - ALfloat dir[3] = { - sinf(azimuth) * cosf(elevation), - sinf(elevation), - -cosf(azimuth) * cosf(elevation) - }; - CalcDirectionCoeffs(dir, spread, coeffs); + ALfloat x = -sinf(azimuth) * cosf(elevation); + ALfloat y = sinf(elevation); + ALfloat z = cosf(azimuth) * cosf(elevation); + + CalcAmbiCoeffs(x, y, z, spread, coeffs); } /** -- cgit v1.2.3 From cd2fd126c4024f43730a7c857fca223b35fe0a5b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 May 2018 03:54:32 -0700 Subject: Add an alffplay option to play stereo streams with wide angles --- examples/alffplay.cpp | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 3bba154e..5ee1da63 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -75,6 +75,10 @@ typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); namespace { +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + using nanoseconds = std::chrono::nanoseconds; using microseconds = std::chrono::microseconds; using milliseconds = std::chrono::milliseconds; @@ -84,6 +88,7 @@ using seconds_d64 = std::chrono::duration; const std::string AppName("alffplay"); bool EnableDirectOut = false; +bool EnableWideStereo = false; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT; @@ -699,7 +704,7 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui return; } - std::cout<< "---- AL Event on AudioState "< Date: Fri, 18 May 2018 18:59:27 -0700 Subject: Accumulate ambisonic upsampler gains using double-precision --- Alc/bformatdec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index dcde7d70..58898083 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -450,11 +450,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat { for(j = 0;j < device->Dry.NumChannels;j++) { - ALfloat gain=0.0f; + ALdouble gain = 0.0; for(k = 0;k < COUNTOF(Ambi3DDecoder);k++) - gain += Ambi3DDecoder[k][i] * encgains[k][j]; - ambiup->Gains[i][j][HF_BAND] = gain * Ambi3DDecoderHFScale[i]; - ambiup->Gains[i][j][LF_BAND] = gain; + gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j]; + ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]); + ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain; } } } -- cgit v1.2.3 From 7501c8b48317ee2c09bf928fc1d4bf52c98dce5f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 May 2018 08:18:08 -0700 Subject: Simplify counting for the bsinc FIR loop --- Alc/mixer/mixer_neon.c | 12 ++++++++---- Alc/mixer/mixer_sse.c | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 0af977e6..9aa279a2 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -101,16 +101,20 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, // Apply the scale and phase interpolated filter. r4 = vdupq_n_f32(0.0f); { + const ALsizei count = m >> 2; const float32x4_t pf4 = vdupq_n_f32(pf); - for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++) + + ASSUME(count > 0); + + for(j = 0;j < count;j++) { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const float32x4_t f4 = vmlaq_f32( - vmlaq_f32(*fil, sf4, *scd), - pf4, vmlaq_f32(*phd, sf4, *spd) + vmlaq_f32(fil[j], sf4, scd[j]), + pf4, vmlaq_f32(phd[j], sf4, spd[j]) ); /* r += f*src */ - r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j])); + r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4])); } } r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)), diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 5b4208f9..d7d54993 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -45,17 +45,21 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr // Apply the scale and phase interpolated filter. r4 = _mm_setzero_ps(); { + const ALsizei count = m >> 2; const __m128 pf4 = _mm_set1_ps(pf); + + ASSUME(count > 0); + #define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z)) - for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++) + for(j = 0;j < count;j++) { /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */ const __m128 f4 = MLA4( - MLA4(*fil, sf4, *scd), - pf4, MLA4(*phd, sf4, *spd) + MLA4(fil[j], sf4, scd[j]), + pf4, MLA4(phd[j], sf4, spd[j]) ); /* r += f*src */ - r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j])); + r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j*4])); } #undef MLA4 } -- cgit v1.2.3 From dd51ba396babac675846f14d9159e32c1c864cb8 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:21:50 +0200 Subject: Common: Implement discrete Hilbert transform --- common/alcomplex.c | 35 +++++++++++++++++++++++++++++++++++ common/alcomplex.h | 9 +++++++++ 2 files changed, 44 insertions(+) diff --git a/common/alcomplex.c b/common/alcomplex.c index d68277e3..8a0786e9 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -59,3 +59,38 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) } } } + +/*Discrete Hilbert Transform (analytic signal form)*/ +void hilbert(ALsizei size, ALcomplex *InOutBuffer ) +{ + ALsizei k; + const ALdouble inverse_size = 1.0/(ALfloat)size; + + for ( k = 0; k < size;k++ ) + InOutBuffer[k].Imag = 0.0; + + complex_fft( InOutBuffer, size, 1.0 ); + + for( k = 0; k < size; k++ ) + { + if( k == 0 || k == size/2 ) + { + InOutBuffer[k].Real *= inverse_size; + InOutBuffer[k].Imag *= inverse_size; + } + + else if ( k >=1 && k < size/2 ) + { + InOutBuffer[k].Real *= 2.0*inverse_size; + InOutBuffer[k].Imag *= 2.0*inverse_size; + } + + else + { + InOutBuffer[k].Real = 0.0; + InOutBuffer[k].Imag = 0.0; + } + } + + complex_fft( InOutBuffer, size,-1.0 ); +} diff --git a/common/alcomplex.h b/common/alcomplex.h index cf4683fa..cfd164b6 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -55,6 +55,15 @@ inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) */ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); +/** + *Calculate the complex helical sequence (or discrete-time analytical signal) + *of the given input using the discrete Hilbert transform (In-place algorithm). + *Fills InOutBuffer[0...size-1] with the discrete-time analytical signal stored + *in InOutBuffer[0...size-1]. InOutBuffer is an array of complex numbers, + *size MUST BE power of two. + */ +void hilbert(ALsizei size, ALcomplex *InOutBuffer ); + #ifdef __cplusplus } // extern "C" #endif -- cgit v1.2.3 From d3a81f4f28484b246084a5ec5cac5619adcfa819 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:23:03 +0200 Subject: EFX: Frequency Shifter implementation Add frequency shifter effect using discrete Hilbert transform. Only mono signal processing by now (LEFT_DIRECTION). --- Alc/ALc.c | 6 +- Alc/effects/fshifter.c | 323 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/Include/alEffect.h | 10 +- OpenAL32/alAuxEffectSlot.c | 1 + OpenAL32/alEffect.c | 7 + 7 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 Alc/effects/fshifter.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 597cc890..1d001a55 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -550,8 +550,8 @@ static const struct { DECL(AL_EFFECT_ECHO), DECL(AL_EFFECT_FLANGER), DECL(AL_EFFECT_PITCH_SHIFTER), -#if 0 DECL(AL_EFFECT_FREQUENCY_SHIFTER), +#if 0 DECL(AL_EFFECT_VOCAL_MORPHER), #endif DECL(AL_EFFECT_RING_MODULATOR), @@ -632,6 +632,10 @@ static const struct { DECL(AL_FLANGER_FEEDBACK), DECL(AL_FLANGER_DELAY), + DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), + DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), + DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), + DECL(AL_RING_MODULATOR_FREQUENCY), DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c new file mode 100644 index 00000000..2d1b64fe --- /dev/null +++ b/Alc/effects/fshifter.c @@ -0,0 +1,323 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + + +typedef struct ALfshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect parameters */ + ALsizei count; + ALdouble frac_freq; + ALdouble inc; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex Analytic[HIL_SIZE]; + ALcomplex Outdata[BUFFERSIZE]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + +} ALfshifterState; + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state); +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + +/* Define a Hann window, used to filter the HIL input and output. */ +alignas(16) static ALdouble HannWindow[HIL_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(i = 0;i < HIL_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; + } +} + +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + +static void ALfshifterState_Construct(ALfshifterState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALfshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->frac_freq = 0.0; + state->inc = 0.0; + state->ld_sign = -1.0; + + memset(state->InFIFO , 0, HIL_SIZE*sizeof(ALfloat)); + memset(state->OutFIFO , 0, HIL_SIZE*sizeof(ALcomplex)); + memset(state->OutputAccum, 0, 2*HIL_SIZE*sizeof(ALcomplex)); + memset(state->Analytic , 0, HIL_SIZE*sizeof(ALcomplex)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + + state->frac_freq = props->Fshifter.Frequency/device->Frequency; + + switch (props->Fshifter.Left_direction) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + state->ld_sign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + state->ld_sign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + state->frac_freq = 0.0; + break; + } + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALsizei i,k; + ALfloat *restrict BufferOut = state->BufferOut; + + for (i = 0; i < SamplesToDo; i++){ + + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; + + state->count++; + + /* Check whether FIFO buffer is filled */ + if (state->count >= HIL_SIZE ) + { + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for (k = 0; k < HIL_SIZE;k++) + { + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0f; + } + /*Processing signal by Discrete Hilbert Transform (analytical signal)*/ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k=0; k < HIL_SIZE; k++) + { + state->OutputAccum[k].Real += 2.0f*HannWindow[k]*state->Analytic[k].Real / OVERSAMP; + state->OutputAccum[k].Imag += 2.0f*HannWindow[k]*state->Analytic[k].Imag / OVERSAMP; + } + for (k = 0; k < HIL_STEP; k++) + { + state->OutFIFO[k] = state->OutputAccum[k]; + } + + /* shift accumulator */ + memmove(state->OutputAccum, state->OutputAccum + HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); + + /* move input FIFO */ + for (k = 0; k < FIFO_LATENCY; k++) state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + } + } + /*Process frequency shifter using the analytic signal obtained*/ + for ( k = 0; k < SamplesToDo; k++, state->inc += state->frac_freq ) + { + ALdouble phase; + + if( state->inc >= 1.0 ) state->inc -= 1.0; + + phase = (2.0*M_PI*state->inc); + + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->ld_sign*state->Outdata[k].Imag*sin(phase)); + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); + +} + +typedef struct FshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} FshifterStateFactory; + +static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +{ + ALfshifterState *state; + + NEW_OBJ0(state, ALfshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); + +EffectStateFactory *FshifterStateFactory_getFactory(void) +{ + static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &FshifterFactory); +} + +void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = (ALfloat) val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} + +void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALfshifter_setParamf(effect, context, param, vals[0]); +} + +void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.Left_direction = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.Right_direction = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALfshifter_setParami(effect, context, param, vals[0]); +} + +void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = (ALint)props->Fshifter.Left_direction; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = (ALint)props->Fshifter.Right_direction; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALfshifter_getParami(effect, context, param, vals); +} + +void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = (ALfloat)props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } + +} + +void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALfshifter_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALfshifter); diff --git a/CMakeLists.txt b/CMakeLists.txt index cd3ecbed..a6024bf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -761,6 +761,7 @@ SET(ALC_OBJS Alc/effects/distortion.c Alc/effects/echo.c Alc/effects/equalizer.c + Alc/effects/fshifter.c Alc/effects/modulator.c Alc/effects/null.c Alc/effects/pshifter.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index bb9aef59..c1eae443 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -166,6 +166,7 @@ EffectStateFactory *DistortionStateFactory_getFactory(void); EffectStateFactory *EchoStateFactory_getFactory(void); EffectStateFactory *EqualizerStateFactory_getFactory(void); EffectStateFactory *FlangerStateFactory_getFactory(void); +EffectStateFactory *FshifterStateFactory_getFactory(void); EffectStateFactory *ModulatorStateFactory_getFactory(void); EffectStateFactory *PshifterStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 50b64ee1..206c495b 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -18,6 +18,7 @@ enum { ECHO_EFFECT, EQUALIZER_EFFECT, FLANGER_EFFECT, + FSHIFTER_EFFECT, MODULATOR_EFFECT, PSHIFTER_EFFECT, DEDICATED_EFFECT, @@ -33,7 +34,7 @@ struct EffectList { int type; ALenum val; }; -#define EFFECTLIST_SIZE 12 +#define EFFECTLIST_SIZE 13 extern const struct EffectList EffectList[EFFECTLIST_SIZE]; @@ -65,6 +66,7 @@ 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 ALfshifter_vtable; extern const struct ALeffectVtable ALmodulator_vtable; extern const struct ALeffectVtable ALnull_vtable; extern const struct ALeffectVtable ALpshifter_vtable; @@ -145,6 +147,12 @@ typedef union ALeffectProps { ALfloat HighGain; } Equalizer; + struct { + ALfloat Frequency; + ALint Left_direction; + ALint Right_direction; + } Fshifter; + struct { ALfloat Frequency; ALfloat HighPassCutoff; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index d04fc4a7..6f6ef163 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -54,6 +54,7 @@ static const struct { { AL_EFFECT_ECHO, EchoStateFactory_getFactory }, { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory }, { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory }, + { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory }, { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory }, { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory}, { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory }, diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index e7dc6ace..a69bf70c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -44,6 +44,7 @@ const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "echo", ECHO_EFFECT, AL_EFFECT_ECHO }, { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER }, { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER }, + { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER }, { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR }, { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER }, { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, @@ -584,6 +585,12 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY; effect->vtab = &ALflanger_vtable; break; + case AL_EFFECT_FREQUENCY_SHIFTER: + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.Left_direction = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.Right_direction = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->vtab = &ALfshifter_vtable; + break; case AL_EFFECT_RING_MODULATOR: effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; -- cgit v1.2.3 From da6f32a1c0fd89e19a09f24f03cae23df65ac91e Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 17:27:37 +0200 Subject: Alsoft-config: Add frequency shifter effect --- alsoftrc.sample | 2 +- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 2b7093a9..04dd72f6 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -220,7 +220,7 @@ # 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,chorus,compressor, -# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter +# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter,fshifter #excludefx = ## default-reverb: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index dbd359d8..07b5992b 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -378,6 +378,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableFrequencyShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enablePitchShifterCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -844,6 +845,7 @@ void MainWindow::loadConfig(const QString &fname) ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive)); ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive)); ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); + ui->enableFrequencyShifterCheck->setChecked(!excludefx.contains("fshifter", Qt::CaseInsensitive)); ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); ui->enablePitchShifterCheck->setChecked(!excludefx.contains("pshifter", Qt::CaseInsensitive)); @@ -1056,6 +1058,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("equalizer"); if(!ui->enableFlangerCheck->isChecked()) strlist.append("flanger"); + if(!ui->enableFrequencyShifterCheck->isChecked()) + strlist.append("fshifter"); if(!ui->enableModulatorCheck->isChecked()) strlist.append("modulator"); if(!ui->enableDedicatedCheck->isChecked()) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index ef886ba4..bc112157 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -2124,6 +2124,22 @@ added by the ALC_EXT_DEDICATED extension. true + + + + 320 + 180 + 131 + 21 + + + + Frequency Shifter + + + true + + -- cgit v1.2.3 From 97c165b9518bfdad0fc0506820f32f706488c75e Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 20 May 2018 18:44:24 +0200 Subject: Add correct cast --- common/alcomplex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/alcomplex.c b/common/alcomplex.c index 8a0786e9..9cf9d9bd 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -64,7 +64,7 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) void hilbert(ALsizei size, ALcomplex *InOutBuffer ) { ALsizei k; - const ALdouble inverse_size = 1.0/(ALfloat)size; + const ALdouble inverse_size = 1.0/(ALdouble)size; for ( k = 0; k < size;k++ ) InOutBuffer[k].Imag = 0.0; -- cgit v1.2.3 From a235259b5e7788b6e5f77b15ca0f26370914fbc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 06:16:03 -0700 Subject: Further clarify a comment about float precision --- Alc/ALu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 9d7fcdd5..3c36cbc6 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1674,9 +1674,9 @@ static inline ALfloat Conv_ALfloat(ALfloat val) { return val; } static inline ALint Conv_ALint(ALfloat val) { - /* Floats have a 23-bit mantissa. A bit of the exponent helps out along - * with the sign bit, giving 25 bits. So [-16777216, +16777216] is the max - * integer range normalized floats can be converted to before losing + /* Floats have a 23-bit mantissa. There is an implied 1 bit in the mantissa + * along with the sign bit, giving 25 bits total, so [-16777216, +16777216] + * is the max value a normalized float can be scaled to before losing * precision. */ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7; -- cgit v1.2.3 From 720ec2beea665c6098753e13713b165fc3729162 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 17:51:57 -0700 Subject: Use the __BYTE_ORDER__ macro when available --- OpenAL32/Include/alMain.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 886f3ab1..093f7950 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -184,11 +184,15 @@ inline int fallback_ctz64(ALuint64 value) #define CTZ64 fallback_ctz64 #endif +#if defined(__BYTE_ORDER__) && defined(__LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __LITTLE_ENDIAN__) +#else static const union { ALuint u; ALubyte b[sizeof(ALuint)]; } EndianTest = { 1 }; #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) +#endif #define COUNTOF(x) (sizeof(x) / sizeof(0[x])) -- cgit v1.2.3 From 4e315353c82adf7c65fed52e2d99c355e52fc821 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 May 2018 23:25:56 -0700 Subject: Add a method to queue multiple buffer layers onto a source --- Alc/inprogext.h | 8 ++++ OpenAL32/alSource.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/Alc/inprogext.h b/Alc/inprogext.h index 619b604f..3025abe2 100644 --- a/Alc/inprogext.h +++ b/Alc/inprogext.h @@ -72,6 +72,14 @@ AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values); #endif #endif +#ifndef AL_SOFT_buffer_layers +#define AL_SOFT_buffer_layers +typedef void (AL_APIENTRY*LPALSOURCEQUEUEBUFFERLAYERSSOFT)(ALuint src, ALsizei nb, const ALuint *buffers); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers); +#endif +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index ed6bd8ee..5ce439c7 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2826,6 +2826,121 @@ done: ALCcontext_DecRef(context); } +AL_API void AL_APIENTRY alSourceQueueBufferLayersSOFT(ALuint src, ALsizei nb, const ALuint *buffers) +{ + ALCdevice *device; + ALCcontext *context; + ALbufferlistitem *BufferListStart; + ALbufferlistitem *BufferList; + ALbuffer *BufferFmt = NULL; + ALsource *source; + ALsizei i; + + if(nb == 0) + return; + + context = GetContextRef(); + if(!context) return; + + device = context->Device; + + LockSourceList(context); + if(!(nb >= 0 && nb < 16)) + SETERR_GOTO(context, AL_INVALID_VALUE, done, "Queueing %d buffer layers", nb); + if((source=LookupSource(context, src)) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid source ID %u", src); + + if(source->SourceType == AL_STATIC) + { + /* Can't queue on a Static Source */ + SETERR_GOTO(context, AL_INVALID_OPERATION, done, "Queueing onto static source %u", src); + } + + /* Check for a valid Buffer, for its frequency and format */ + BufferList = source->queue; + while(BufferList) + { + for(i = 0;i < BufferList->num_buffers;i++) + { + if((BufferFmt=BufferList->buffers[i]) != NULL) + break; + } + if(BufferFmt) break; + BufferList = ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed); + } + + LockBufferList(device); + BufferListStart = al_calloc(DEF_ALIGN, FAM_SIZE(ALbufferlistitem, buffers, nb)); + BufferList = BufferListStart; + ATOMIC_INIT(&BufferList->next, NULL); + BufferList->max_samples = 0; + BufferList->num_buffers = 0; + for(i = 0;i < nb;i++) + { + ALbuffer *buffer = NULL; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) + SETERR_GOTO(context, AL_INVALID_NAME, buffer_error, "Queueing invalid buffer ID %u", + buffers[i]); + + BufferList->buffers[BufferList->num_buffers++] = buffer; + if(!buffer) continue; + + IncrementRef(&buffer->ref); + + BufferList->max_samples = maxi(BufferList->max_samples, buffer->SampleLen); + + if(buffer->MappedAccess != 0 && !(buffer->MappedAccess&AL_MAP_PERSISTENT_BIT_SOFT)) + SETERR_GOTO(context, AL_INVALID_OPERATION, buffer_error, + "Queueing non-persistently mapped buffer %u", buffer->id); + + if(BufferFmt == NULL) + BufferFmt = buffer; + else if(BufferFmt->Frequency != buffer->Frequency || + BufferFmt->FmtChannels != buffer->FmtChannels || + BufferFmt->OriginalType != buffer->OriginalType) + { + alSetError(context, AL_INVALID_OPERATION, "Queueing buffer with mismatched format"); + + buffer_error: + /* A buffer failed (invalid ID or format), so unlock and release + * each buffer we had. */ + while(BufferListStart) + { + ALbufferlistitem *next = ATOMIC_LOAD(&BufferListStart->next, + almemory_order_relaxed); + for(i = 0;i < BufferListStart->num_buffers;i++) + { + if((buffer=BufferListStart->buffers[i]) != NULL) + DecrementRef(&buffer->ref); + } + al_free(BufferListStart); + BufferListStart = next; + } + UnlockBufferList(device); + goto done; + } + } + /* All buffers good. */ + UnlockBufferList(device); + + /* Source is now streaming */ + source->SourceType = AL_STREAMING; + + if(!(BufferList=source->queue)) + source->queue = BufferListStart; + else + { + ALbufferlistitem *next; + while((next=ATOMIC_LOAD(&BufferList->next, almemory_order_relaxed)) != NULL) + BufferList = next; + ATOMIC_STORE(&BufferList->next, BufferListStart, almemory_order_release); + } + +done: + UnlockSourceList(context); + ALCcontext_DecRef(context); +} + AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) { ALCcontext *context; -- cgit v1.2.3 From ecdc58c1c9c4dcd1d7f685d423f7712a48f8a983 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 05:59:03 -0700 Subject: Fix formatting and line endings --- Alc/effects/fshifter.c | 649 +++++++++++++++++++++++++------------------------ 1 file changed, 326 insertions(+), 323 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 2d1b64fe..16710ac2 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -1,323 +1,326 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2018 by Raul Herraiz. - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alAuxEffectSlot.h" -#include "alError.h" -#include "alu.h" -#include "filters/defs.h" - -#include "alcomplex.h" - -#define HIL_SIZE 1024 -#define OVERSAMP (1<<2) - -#define HIL_STEP (HIL_SIZE / OVERSAMP) -#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) - - -typedef struct ALfshifterState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect parameters */ - ALsizei count; - ALdouble frac_freq; - ALdouble inc; - ALdouble ld_sign; - - /*Effects buffers*/ - ALfloat InFIFO[HIL_SIZE]; - ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[2*HIL_SIZE]; - ALcomplex Analytic[HIL_SIZE]; - ALcomplex Outdata[BUFFERSIZE]; - - alignas(16) ALfloat BufferOut[BUFFERSIZE]; - - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - -} ALfshifterState; - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state); -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); - -/* Define a Hann window, used to filter the HIL input and output. */ -alignas(16) static ALdouble HannWindow[HIL_SIZE]; - -static void InitHannWindow(void) -{ - ALsizei i; - - /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ - for(i = 0;i < HIL_SIZE>>1;i++) - { - ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); - HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; - } -} - -static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; - -static void ALfshifterState_Construct(ALfshifterState *state) -{ - ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALfshifterState, ALeffectState, state); - - alcall_once(&HannInitOnce, InitHannWindow); -} - -static ALvoid ALfshifterState_Destruct(ALfshifterState *state) -{ - ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); -} - -static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device) -{ - /* (Re-)initializing parameters and clear the buffers. */ - state->count = FIFO_LATENCY; - state->frac_freq = 0.0; - state->inc = 0.0; - state->ld_sign = -1.0; - - memset(state->InFIFO , 0, HIL_SIZE*sizeof(ALfloat)); - memset(state->OutFIFO , 0, HIL_SIZE*sizeof(ALcomplex)); - memset(state->OutputAccum, 0, 2*HIL_SIZE*sizeof(ALcomplex)); - memset(state->Analytic , 0, HIL_SIZE*sizeof(ALcomplex)); - - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); - - return AL_TRUE; -} - -static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) -{ - const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; - - state->frac_freq = props->Fshifter.Frequency/device->Frequency; - - switch (props->Fshifter.Left_direction) - { - case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: - state->ld_sign = -1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; - break; - - case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->frac_freq = 0.0; - break; - } - - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); -} - -static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -{ - ALsizei i,k; - ALfloat *restrict BufferOut = state->BufferOut; - - for (i = 0; i < SamplesToDo; i++){ - - /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; - - state->count++; - - /* Check whether FIFO buffer is filled */ - if (state->count >= HIL_SIZE ) - { - state->count = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for (k = 0; k < HIL_SIZE;k++) - { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0f; - } - /*Processing signal by Discrete Hilbert Transform (analytical signal)*/ - hilbert(HIL_SIZE, state->Analytic); - - /* Windowing and add to output accumulator */ - for(k=0; k < HIL_SIZE; k++) - { - state->OutputAccum[k].Real += 2.0f*HannWindow[k]*state->Analytic[k].Real / OVERSAMP; - state->OutputAccum[k].Imag += 2.0f*HannWindow[k]*state->Analytic[k].Imag / OVERSAMP; - } - for (k = 0; k < HIL_STEP; k++) - { - state->OutFIFO[k] = state->OutputAccum[k]; - } - - /* shift accumulator */ - memmove(state->OutputAccum, state->OutputAccum + HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); - - /* move input FIFO */ - for (k = 0; k < FIFO_LATENCY; k++) state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; - } - } - /*Process frequency shifter using the analytic signal obtained*/ - for ( k = 0; k < SamplesToDo; k++, state->inc += state->frac_freq ) - { - ALdouble phase; - - if( state->inc >= 1.0 ) state->inc -= 1.0; - - phase = (2.0*M_PI*state->inc); - - BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->ld_sign*state->Outdata[k].Imag*sin(phase)); - } - - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, - maxi(SamplesToDo, 512), 0, SamplesToDo); - -} - -typedef struct FshifterStateFactory { - DERIVE_FROM_TYPE(EffectStateFactory); -} FshifterStateFactory; - -static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) -{ - ALfshifterState *state; - - NEW_OBJ0(state, ALfshifterState)(); - if(!state) return NULL; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); - -EffectStateFactory *FshifterStateFactory_getFactory(void) -{ - static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; - - return STATIC_CAST(EffectStateFactory, &FshifterFactory); -} - -void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = (ALfloat) val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } -} - -void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALfshifter_setParamf(effect, context, param, vals[0]); -} - -void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.Left_direction = val; - break; - - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) - SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.Right_direction = val; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALfshifter_setParami(effect, context, param, vals[0]); -} - -void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = (ALint)props->Fshifter.Left_direction; - break; - case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = (ALint)props->Fshifter.Right_direction; - break; - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); - } -} -void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALfshifter_getParami(effect, context, param, vals); -} - -void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = (ALfloat)props->Fshifter.Frequency; - break; - - default: - alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); - } - -} - -void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALfshifter_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALfshifter); +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#include "alcomplex.h" + +#define HIL_SIZE 1024 +#define OVERSAMP (1<<2) + +#define HIL_STEP (HIL_SIZE / OVERSAMP) +#define FIFO_LATENCY (HIL_STEP * (OVERSAMP-1)) + + +typedef struct ALfshifterState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect parameters */ + ALsizei count; + ALdouble frac_freq; + ALdouble inc; + ALdouble ld_sign; + + /*Effects buffers*/ + ALfloat InFIFO[HIL_SIZE]; + ALcomplex OutFIFO[HIL_SIZE]; + ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex Analytic[HIL_SIZE]; + ALcomplex Outdata[BUFFERSIZE]; + + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +} ALfshifterState; + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state); +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *device); +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALfshifterState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALfshifterState); + +/* Define a Hann window, used to filter the HIL input and output. */ +alignas(16) static ALdouble HannWindow[HIL_SIZE]; + +static void InitHannWindow(void) +{ + ALsizei i; + + /* Create lookup table of the Hann window for the desired size, i.e. HIL_SIZE */ + for(i = 0;i < HIL_SIZE>>1;i++) + { + ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(HIL_SIZE-1)); + HannWindow[i] = HannWindow[HIL_SIZE-1-i] = val * val; + } +} + +static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT; + +static void ALfshifterState_Construct(ALfshifterState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALfshifterState, ALeffectState, state); + + alcall_once(&HannInitOnce, InitHannWindow); +} + +static ALvoid ALfshifterState_Destruct(ALfshifterState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice *UNUSED(device)) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->count = FIFO_LATENCY; + state->frac_freq = 0.0; + state->inc = 0.0; + state->ld_sign = 1.0; + + memset(state->InFIFO, 0, sizeof(state->InFIFO)); + memset(state->OutFIFO, 0, sizeof(state->OutFIFO)); + memset(state->OutputAccum, 0, sizeof(state->OutputAccum)); + memset(state->Analytic, 0, sizeof(state->Analytic)); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + + state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; + + switch(props->Fshifter.Left_direction) + { + case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: + state->ld_sign = -1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_UP: + state->ld_sign = 1.0; + break; + + case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: + state->inc = 0.0; + state->frac_freq = 0.0; + break; + } + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat *restrict BufferOut = state->BufferOut; + ALsizei i, k; + + for(i = 0; i < SamplesToDo;i++) + { + /* Fill FIFO buffer with samples data */ + state->InFIFO[state->count] = SamplesIn[0][i]; + state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; + state->count++; + + /* Check whether FIFO buffer is filled */ + if(state->count >= HIL_SIZE) + { + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) + { + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0; + } + + /* Processing signal by Discrete Hilbert Transform (analytical + * signal). + */ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + { + state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; + state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; + } + for(k = 0;k < HIL_STEP;k++) + state->OutFIFO[k] = state->OutputAccum[k]; + + /* Shift accumulator */ + memmove(state->OutputAccum, state->OutputAccum+HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); + + /* Move input FIFO */ + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + } + } + + /* Process frequency shifter using the analytic signal obtained. */ + for(k = 0;k < SamplesToDo;k++) + { + ALdouble phase; + + if(state->inc >= 1.0) + state->inc -= 1.0; + + phase = 2.0*M_PI * state->inc; + BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + + state->ld_sign*state->Outdata[k].Imag*sin(phase)); + + state->inc += state->frac_freq; + } + + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + maxi(SamplesToDo, 512), 0, SamplesToDo); +} + +typedef struct FshifterStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} FshifterStateFactory; + +static ALeffectState *FshifterStateFactory_create(FshifterStateFactory *UNUSED(factory)) +{ + ALfshifterState *state; + + NEW_OBJ0(state, ALfshifterState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(FshifterStateFactory); + +EffectStateFactory *FshifterStateFactory_getFactory(void) +{ + static FshifterStateFactory FshifterFactory = { { GET_VTABLE2(FshifterStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &FshifterFactory); +} + +void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); + props->Fshifter.Frequency = (ALfloat) val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } +} + +void ALfshifter_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALfshifter_setParamf(effect, context, param, vals[0]); +} + +void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); + props->Fshifter.Left_direction = val; + break; + + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); + props->Fshifter.Right_direction = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ALfshifter_setParami(effect, context, param, vals[0]); +} + +void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: + *val = (ALint)props->Fshifter.Left_direction; + break; + case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: + *val = (ALint)props->Fshifter.Right_direction; + break; + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); + } +} +void ALfshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ALfshifter_getParami(effect, context, param, vals); +} + +void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + + const ALeffectProps *props = &effect->Props; + switch(param) + { + case AL_FREQUENCY_SHIFTER_FREQUENCY: + *val = (ALfloat)props->Fshifter.Frequency; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x", param); + } + +} + +void ALfshifter_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ALfshifter_getParamf(effect, context, param, vals); +} + +DEFINE_ALEFFECT_VTABLE(ALfshifter); -- cgit v1.2.3 From 80df89d0db7805a5661a72b07dd3961b4f5aa836 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 06:12:55 -0700 Subject: Improve the frequency shifter output accum handling --- Alc/effects/fshifter.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 16710ac2..2e1a6c45 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -50,7 +50,7 @@ typedef struct ALfshifterState { /*Effects buffers*/ ALfloat InFIFO[HIL_SIZE]; ALcomplex OutFIFO[HIL_SIZE]; - ALcomplex OutputAccum[2*HIL_SIZE]; + ALcomplex OutputAccum[HIL_SIZE]; ALcomplex Analytic[HIL_SIZE]; ALcomplex Outdata[BUFFERSIZE]; @@ -147,8 +147,9 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { + static const ALcomplex complex_zero = { 0.0, 0.0 }; ALfloat *restrict BufferOut = state->BufferOut; - ALsizei i, k; + ALsizei i, j, k; for(i = 0; i < SamplesToDo;i++) { @@ -180,15 +181,13 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; } - for(k = 0;k < HIL_STEP;k++) - state->OutFIFO[k] = state->OutputAccum[k]; - /* Shift accumulator */ - memmove(state->OutputAccum, state->OutputAccum+HIL_STEP, HIL_SIZE*sizeof(ALcomplex)); - - /* Move input FIFO */ + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k + HIL_STEP]; + state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; } } -- cgit v1.2.3 From 8219bb374df7412edb6359ddeb5f45fffafb47a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 06:19:59 -0700 Subject: Fix a couple property variable names --- Alc/effects/fshifter.c | 14 +++++++------- OpenAL32/Include/alEffect.h | 6 +++--- OpenAL32/alEffect.c | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 2e1a6c45..fd229f3f 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -125,7 +125,7 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; - switch(props->Fshifter.Left_direction) + switch(props->Fshifter.LeftDirection) { case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: state->ld_sign = -1.0; @@ -242,7 +242,7 @@ void ALfshifter_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, A case AL_FREQUENCY_SHIFTER_FREQUENCY: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter frequency out of range"); - props->Fshifter.Frequency = (ALfloat) val; + props->Fshifter.Frequency = val; break; default: @@ -263,13 +263,13 @@ void ALfshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, A case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter left direction out of range"); - props->Fshifter.Left_direction = val; + props->Fshifter.LeftDirection = val; break; case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION)) SETERR_RETURN(context, AL_INVALID_VALUE,,"Frequency shifter right direction out of range"); - props->Fshifter.Right_direction = val; + props->Fshifter.RightDirection = val; break; default: @@ -287,10 +287,10 @@ void ALfshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum pa switch(param) { case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION: - *val = (ALint)props->Fshifter.Left_direction; + *val = props->Fshifter.LeftDirection; break; case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION: - *val = (ALint)props->Fshifter.Right_direction; + *val = props->Fshifter.RightDirection; break; default: alSetError(context, AL_INVALID_ENUM, "Invalid frequency shifter integer property 0x%04x", param); @@ -308,7 +308,7 @@ void ALfshifter_getParamf(const ALeffect *effect, ALCcontext *context, ALenum pa switch(param) { case AL_FREQUENCY_SHIFTER_FREQUENCY: - *val = (ALfloat)props->Fshifter.Frequency; + *val = props->Fshifter.Frequency; break; default: diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 206c495b..4d28a708 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -147,10 +147,10 @@ typedef union ALeffectProps { ALfloat HighGain; } Equalizer; - struct { + struct { ALfloat Frequency; - ALint Left_direction; - ALint Right_direction; + ALint LeftDirection; + ALint RightDirection; } Fshifter; struct { diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index a69bf70c..aacddd4c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -586,9 +586,9 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->vtab = &ALflanger_vtable; break; case AL_EFFECT_FREQUENCY_SHIFTER: - effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; - effect->Props.Fshifter.Left_direction = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; - effect->Props.Fshifter.Right_direction = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; + effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY; + effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION; + effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION; effect->vtab = &ALfshifter_vtable; break; case AL_EFFECT_RING_MODULATOR: -- cgit v1.2.3 From f3d4220cab368428e04b8c3fcfec7078e34bd2c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 07:02:14 -0700 Subject: Use fixed point for the frequency shifter's phase --- Alc/effects/fshifter.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index fd229f3f..66ec7124 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -43,8 +43,8 @@ typedef struct ALfshifterState { /* Effect parameters */ ALsizei count; - ALdouble frac_freq; - ALdouble inc; + ALsizei PhaseStep; + ALsizei Phase; ALdouble ld_sign; /*Effects buffers*/ @@ -103,8 +103,8 @@ static ALboolean ALfshifterState_deviceUpdate(ALfshifterState *state, ALCdevice { /* (Re-)initializing parameters and clear the buffers. */ state->count = FIFO_LATENCY; - state->frac_freq = 0.0; - state->inc = 0.0; + state->PhaseStep = 0; + state->Phase = 0; state->ld_sign = 1.0; memset(state->InFIFO, 0, sizeof(state->InFIFO)); @@ -122,8 +122,10 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c { const ALCdevice *device = context->Device; ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat step; - state->frac_freq = props->Fshifter.Frequency/(ALdouble)device->Frequency; + step = props->Fshifter.Frequency / (ALfloat)device->Frequency; + state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE); switch(props->Fshifter.LeftDirection) { @@ -132,12 +134,12 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c break; case AL_FREQUENCY_SHIFTER_DIRECTION_UP: - state->ld_sign = 1.0; + state->ld_sign = 1.0; break; case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: - state->inc = 0.0; - state->frac_freq = 0.0; + state->Phase = 0; + state->PhaseStep = 0; break; } @@ -194,16 +196,12 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD /* Process frequency shifter using the analytic signal obtained. */ for(k = 0;k < SamplesToDo;k++) { - ALdouble phase; - - if(state->inc >= 1.0) - state->inc -= 1.0; - - phase = 2.0*M_PI * state->inc; + ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI); BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) + - state->ld_sign*state->Outdata[k].Imag*sin(phase)); + state->Outdata[k].Imag*sin(phase)*state->ld_sign); - state->inc += state->frac_freq; + state->Phase += state->PhaseStep; + state->Phase &= FRACTIONMASK; } /* Now, mix the processed sound data to the output. */ -- cgit v1.2.3 From c2a4a35c2e3d9959f6a0f20881a7d7dc2ef2c4b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 May 2018 07:28:53 -0700 Subject: Use a tighter loop to handle the frequency shifter's fifo --- Alc/effects/fshifter.c | 72 +++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 66ec7124..3a58f087 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -151,46 +151,52 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD { static const ALcomplex complex_zero = { 0.0, 0.0 }; ALfloat *restrict BufferOut = state->BufferOut; - ALsizei i, j, k; + ALsizei j, k, base; - for(i = 0; i < SamplesToDo;i++) + for(base = 0;base < SamplesToDo;) { + ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base); + + ASSUME(todo > 0); + /* Fill FIFO buffer with samples data */ - state->InFIFO[state->count] = SamplesIn[0][i]; - state->Outdata[i] = state->OutFIFO[state->count-FIFO_LATENCY]; - state->count++; + k = state->count; + for(j = 0;j < todo;j++,k++) + { + state->InFIFO[k] = SamplesIn[0][base+j]; + state->Outdata[base+j] = state->OutFIFO[k-FIFO_LATENCY]; + } + state->count += todo; + base += todo; /* Check whether FIFO buffer is filled */ - if(state->count >= HIL_SIZE) + if(state->count < HIL_SIZE) continue; + + state->count = FIFO_LATENCY; + + /* Real signal windowing and store in Analytic buffer */ + for(k = 0;k < HIL_SIZE;k++) { - state->count = FIFO_LATENCY; - - /* Real signal windowing and store in Analytic buffer */ - for(k = 0;k < HIL_SIZE;k++) - { - state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; - state->Analytic[k].Imag = 0.0; - } - - /* Processing signal by Discrete Hilbert Transform (analytical - * signal). - */ - hilbert(HIL_SIZE, state->Analytic); - - /* Windowing and add to output accumulator */ - for(k = 0;k < HIL_SIZE;k++) - { - state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; - state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; - } - - /* Shift accumulator, input & output FIFO */ - for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; - for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; - for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; - for(k = 0;k < FIFO_LATENCY;k++) - state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; + state->Analytic[k].Real = state->InFIFO[k] * HannWindow[k]; + state->Analytic[k].Imag = 0.0; } + + /* Processing signal by Discrete Hilbert Transform (analytical signal). */ + hilbert(HIL_SIZE, state->Analytic); + + /* Windowing and add to output accumulator */ + for(k = 0;k < HIL_SIZE;k++) + { + state->OutputAccum[k].Real += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Real; + state->OutputAccum[k].Imag += 2.0/OVERSAMP*HannWindow[k]*state->Analytic[k].Imag; + } + + /* Shift accumulator, input & output FIFO */ + for(k = 0;k < HIL_STEP;k++) state->OutFIFO[k] = state->OutputAccum[k]; + for(j = 0;k < HIL_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k]; + for(;j < HIL_SIZE;j++) state->OutputAccum[j] = complex_zero; + for(k = 0;k < FIFO_LATENCY;k++) + state->InFIFO[k] = state->InFIFO[k+HIL_STEP]; } /* Process frequency shifter using the analytic signal obtained. */ -- cgit v1.2.3 From 84a94a61098ea6bf1ede1d93ace00b5e2dcaf625 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 01:04:52 -0700 Subject: Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a7aec638..80a55df7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,7 @@ openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. - Implemented the Pitch Shifter effect. + Implemented the Pitch Shifter and Frequency Shifter effects. Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. -- cgit v1.2.3 From 1782208fde4352e4e40a3f3ec9102fb136e1f5e1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 05:58:06 -0700 Subject: Remove unused function --- Alc/ALu.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3c36cbc6..acd5de06 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -145,16 +145,6 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void) } -/* Prior to VS2013, MSVC lacks the round() family of functions. */ -#if defined(_MSC_VER) && _MSC_VER < 1800 -static float roundf(float val) -{ - if(val < 0.0f) - return ceilf(val-0.5f); - return floorf(val+0.5f); -} -#endif - /* This RNG method was created based on the math found in opusdec. It's quick, * and starting with a seed value of 22222, is suitable for generating * whitenoise. -- cgit v1.2.3 From 9bf3ee722c338f367a65a75ec4d2353f259bc2af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 06:10:09 -0700 Subject: Fix a function comment about a return value --- Alc/ALu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index acd5de06..72c3dd60 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -332,9 +332,7 @@ void aluSelectPostProcess(ALCdevice *device) } -/* Prepares the interpolator for a given rate (determined by increment). A - * result of AL_FALSE indicates that the filter output will completely cut - * the input signal. +/* Prepares the interpolator for a given rate (determined by increment). * * With a bit of work, and a trade of memory for CPU cost, this could be * modified for use with an interpolated increment for buttery-smooth pitch -- cgit v1.2.3 From 93de5350b9d41c4106bc6a6ccfc23e1bc5f48482 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 19:22:21 -0700 Subject: Add some LIKELY and ASSUME statements --- Alc/ALu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 72c3dd60..3cd8ed5c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1610,7 +1610,7 @@ static void ApplyDistanceComp(ALfloat (*restrict Samples)[BUFFERSIZE], DistanceC continue; } - if(SamplesToDo >= base) + if(LIKELY(SamplesToDo >= base)) { for(i = 0;i < base;i++) Values[i] = distbuf[i]; @@ -1638,6 +1638,9 @@ static void ApplyDither(ALfloat (*restrict Samples)[BUFFERSIZE], ALuint *dither_ ALuint seed = *dither_seed; ALsizei c, i; + ASSUME(numchans > 0); + ASSUME(SamplesToDo > 0); + /* Dithering. Step 1, generate whitenoise (uniform distribution of random * values between -1 and +1). Step 2 is to add the noise to the samples, * before rounding and after scaling up to the desired quantization depth. @@ -1690,6 +1693,10 @@ static void Write##A(const ALfloat (*restrict InBuffer)[BUFFERSIZE], \ ALsizei numchans) \ { \ ALsizei i, j; \ + \ + ASSUME(numchans > 0); \ + ASSUME(SamplesToDo > 0); \ + \ for(j = 0;j < numchans;j++) \ { \ const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \ -- cgit v1.2.3 From 422cf429e61c610f271a05c9b5ac44c60b7e58fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 23 May 2018 19:49:49 -0700 Subject: Clamp the dither depth between 2 and 20 bits --- Alc/ALc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1d001a55..1858c29b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2217,9 +2217,12 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) break; } } - else if(depth > 24) - depth = 24; - device->DitherDepth = (depth > 0) ? powf(2.0f, (ALfloat)(depth-1)) : 0.0f; + + if(depth > 0) + { + depth = clampi(depth, 2, 20); + device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); + } } if(!(device->DitherDepth > 0.0f)) TRACE("Dithering disabled\n"); -- cgit v1.2.3 From 803d331711cf5c0ecd0796bf28e9c95cf3724198 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 24 May 2018 00:16:50 -0700 Subject: Improve formatting of the hilbert function --- Alc/effects/fshifter.c | 2 +- common/alcomplex.c | 62 +++++++++++++++++++++++--------------------------- common/alcomplex.h | 12 +++++----- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 3a58f087..5aa08453 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -182,7 +182,7 @@ static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToD } /* Processing signal by Discrete Hilbert Transform (analytical signal). */ - hilbert(HIL_SIZE, state->Analytic); + complex_hilbert(state->Analytic, HIL_SIZE); /* Windowing and add to output accumulator */ for(k = 0;k < HIL_SIZE;k++) diff --git a/common/alcomplex.c b/common/alcomplex.c index 9cf9d9bd..d4045aeb 100644 --- a/common/alcomplex.c +++ b/common/alcomplex.c @@ -60,37 +60,33 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) } } -/*Discrete Hilbert Transform (analytic signal form)*/ -void hilbert(ALsizei size, ALcomplex *InOutBuffer ) -{ - ALsizei k; - const ALdouble inverse_size = 1.0/(ALdouble)size; - - for ( k = 0; k < size;k++ ) - InOutBuffer[k].Imag = 0.0; - - complex_fft( InOutBuffer, size, 1.0 ); - - for( k = 0; k < size; k++ ) - { - if( k == 0 || k == size/2 ) - { - InOutBuffer[k].Real *= inverse_size; - InOutBuffer[k].Imag *= inverse_size; - } - - else if ( k >=1 && k < size/2 ) - { - InOutBuffer[k].Real *= 2.0*inverse_size; - InOutBuffer[k].Imag *= 2.0*inverse_size; - } - - else - { - InOutBuffer[k].Real = 0.0; - InOutBuffer[k].Imag = 0.0; - } - } - - complex_fft( InOutBuffer, size,-1.0 ); +void complex_hilbert(ALcomplex *Buffer, ALsizei size) +{ + const ALdouble inverse_size = 1.0/(ALdouble)size; + ALsizei todo, i; + + for(i = 0;i < size;i++) + Buffer[i].Imag = 0.0; + + complex_fft(Buffer, size, 1.0); + + todo = size >> 1; + Buffer[0].Real *= inverse_size; + Buffer[0].Imag *= inverse_size; + for(i = 1;i < todo;i++) + { + Buffer[i].Real *= 2.0*inverse_size; + Buffer[i].Imag *= 2.0*inverse_size; + } + Buffer[i].Real *= inverse_size; + Buffer[i].Imag *= inverse_size; + i++; + + for(;i < size;i++) + { + Buffer[i].Real = 0.0; + Buffer[i].Imag = 0.0; + } + + complex_fft(Buffer, size, -1.0); } diff --git a/common/alcomplex.h b/common/alcomplex.h index cfd164b6..2418ce78 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -56,13 +56,13 @@ inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); /** - *Calculate the complex helical sequence (or discrete-time analytical signal) - *of the given input using the discrete Hilbert transform (In-place algorithm). - *Fills InOutBuffer[0...size-1] with the discrete-time analytical signal stored - *in InOutBuffer[0...size-1]. InOutBuffer is an array of complex numbers, - *size MUST BE power of two. + * Calculate the complex helical sequence (discrete-time analytical signal) of + * the given input using the discrete Hilbert transform (In-place algorithm). + * Fills Buffer[0...size-1] with the discrete-time analytical signal stored in + * Buffer[0...size-1]. Buffer is an array of complex numbers, size MUST BE + * power of two. */ -void hilbert(ALsizei size, ALcomplex *InOutBuffer ); +void complex_hilbert(ALcomplex *Buffer, ALsizei size); #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From ec84a107a4e0d26fa6a528940a40405d1fd1ce65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 00:26:11 -0700 Subject: Don't hardcode the max channels for HRTF B-Format decoding --- Alc/hrtf.c | 6 +++++- Alc/hrtf.h | 6 ------ Alc/panning.c | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Alc/hrtf.c b/Alc/hrtf.c index 376c849f..ddbd3a28 100644 --- a/Alc/hrtf.c +++ b/Alc/hrtf.c @@ -202,13 +202,15 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N #define NUM_BANDS 2 BandSplitter splitter; ALdouble (*tmpres)[HRIR_LENGTH][2]; - ALsizei idx[HRTF_AMBI_MAX_CHANNELS]; + ALsizei *restrict idx; ALsizei min_delay = HRTF_HISTORY_LENGTH; ALsizei max_delay = 0; ALfloat temps[3][HRIR_LENGTH]; ALsizei max_length; ALsizei i, c, b; + idx = al_calloc(DEF_ALIGN, AmbiCount*sizeof(*idx)); + for(c = 0;c < AmbiCount;c++) { ALuint evidx, azidx; @@ -312,6 +314,8 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N } al_free(tmpres); tmpres = NULL; + al_free(idx); + idx = NULL; if(NUM_BANDS == 1) max_length = mini(max_delay-min_delay + Hrtf->irSize, HRIR_LENGTH); diff --git a/Alc/hrtf.h b/Alc/hrtf.h index aaffa904..ab68929b 100644 --- a/Alc/hrtf.h +++ b/Alc/hrtf.h @@ -9,12 +9,6 @@ #include "atomic.h" -/* The maximum number of virtual speakers used to generate HRTF coefficients - * for decoding B-Format. - */ -#define HRTF_AMBI_MAX_CHANNELS 18 - - #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1<AmbiUp) { -- cgit v1.2.3 From ac4061b9d2f5f0994e79ebc71ec85eb69b8b9655 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 18:17:17 -0700 Subject: Better sort the effect list in alsoft-config --- utils/alsoft-config/mainwindow.ui | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index bc112157..18a00659 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ - 5 + 0 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 80 - 20 + 93 + 29 @@ -2011,8 +2011,8 @@ for the system to handle. - 320 - 30 + 70 + 180 131 21 @@ -2028,7 +2028,7 @@ for the system to handle. 320 - 60 + 30 131 21 @@ -2060,7 +2060,7 @@ for the system to handle. 320 - 120 + 150 131 21 @@ -2076,7 +2076,7 @@ for the system to handle. 320 - 150 + 180 131 21 @@ -2111,8 +2111,8 @@ added by the ALC_EXT_DEDICATED extension. - 70 - 180 + 320 + 120 131 21 @@ -2128,7 +2128,7 @@ added by the ALC_EXT_DEDICATED extension. 320 - 180 + 60 131 21 @@ -2162,8 +2162,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 108 - 20 + 125 + 29 @@ -2332,7 +2332,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 21 + 27 -- cgit v1.2.3 From 728dd5a4e05a5353795290c5d0b881883f5ecc83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 May 2018 20:43:05 -0700 Subject: Avoid setting unnecessary variables --- Alc/ALu.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3cd8ed5c..dd720183 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1878,17 +1878,7 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) va_end(args); if(msglen < 0 || (size_t)msglen >= sizeof(evt.Message)) - { evt.Message[sizeof(evt.Message)-1] = 0; - msglen = (int)strlen(evt.Message); - } - if(msglen > 0) - msg = evt.Message; - else - { - msg = ""; - msglen = (int)strlen(msg); - } ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) -- cgit v1.2.3 From a5edf487dd1a4095ef5c022c1f254f032ff7f537 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 May 2018 01:03:18 -0700 Subject: Use a macro to handle common case formatting --- Alc/ALu.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index dd720183..dc24755d 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1828,27 +1828,16 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) switch(device->FmtType) { - case DevFmtByte: - WriteI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUByte: - WriteUI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtShort: - WriteI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUShort: - WriteUI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtInt: - WriteI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtUInt: - WriteUI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; - case DevFmtFloat: - WriteF32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); - break; +#define HANDLE_WRITE(T, S) case T: \ + Write##S(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels); break; + HANDLE_WRITE(DevFmtByte, I8) + HANDLE_WRITE(DevFmtUByte, UI8) + HANDLE_WRITE(DevFmtShort, I16) + HANDLE_WRITE(DevFmtUShort, UI16) + HANDLE_WRITE(DevFmtInt, I32) + HANDLE_WRITE(DevFmtUInt, UI32) + HANDLE_WRITE(DevFmtFloat, F32) +#undef HANDLE_WRITE } } -- cgit v1.2.3 From 5cba81cf35ff7f8b6739b317ada82163899a3168 Mon Sep 17 00:00:00 2001 From: "Jan Chren (rindeal)" Date: Tue, 29 May 2018 18:31:41 +0200 Subject: CMake: fix SSE3 typo Closes: https://github.com/kcat/openal-soft/issues/195 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6024bf4..c27c6e4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -858,7 +858,7 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2) MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions") ENDIF() -OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF) +OPTION(ALSOFT_REQUIRE_SSE3 "Require SSE3 support" OFF) CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}") IF(HAVE_EMMINTRIN_H) OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) -- cgit v1.2.3 From 8854720e8a83ccb25221b085612b9a47c36bfa16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:15:49 -0700 Subject: Avoid separate in/out parameters when they're always the same --- utils/makehrtf.c | 92 +++++++++++++++++++++----------------------------------- 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/utils/makehrtf.c b/utils/makehrtf.c index e19c77c9..0bd36849 100644 --- a/utils/makehrtf.c +++ b/utils/makehrtf.c @@ -988,46 +988,30 @@ static Complex *CreateComplexes(size_t n) return a; } -/* Fast Fourier transform routines. The number of points must be a power of - * two. In-place operation is possible only if both the real and imaginary - * parts are in-place together. +/* Fast Fourier transform routines. The number of points must be a power of + * two. */ // Performs bit-reversal ordering. -static void FftArrange(const uint n, const Complex *in, Complex *out) +static void FftArrange(const uint n, Complex *inout) { uint rk, k, m; - if(in == out) + // Handle in-place arrangement. + rk = 0; + for(k = 0;k < n;k++) { - // Handle in-place arrangement. - rk = 0; - for(k = 0;k < n;k++) + if(rk > k) { - if(rk > k) - { - Complex temp = in[rk]; - out[rk] = in[k]; - out[k] = temp; - } - m = n; - while(rk&(m >>= 1)) - rk &= ~m; - rk |= m; - } - } - else - { - // Handle copy arrangement. - rk = 0; - for(k = 0;k < n;k++) - { - out[rk] = in[k]; - m = n; - while(rk&(m >>= 1)) - rk &= ~m; - rk |= m; + Complex temp = inout[rk]; + inout[rk] = inout[k]; + inout[k] = temp; } + + m = n; + while(rk&(m >>= 1)) + rk &= ~m; + rk |= m; } } @@ -1061,23 +1045,23 @@ static void FftSummation(const int n, const double s, Complex *cplx) } // Performs a forward FFT. -static void FftForward(const uint n, const Complex *in, Complex *out) +static void FftForward(const uint n, Complex *inout) { - FftArrange(n, in, out); - FftSummation(n, 1.0, out); + FftArrange(n, inout); + FftSummation(n, 1.0, inout); } // Performs an inverse FFT. -static void FftInverse(const uint n, const Complex *in, Complex *out) +static void FftInverse(const uint n, Complex *inout) { double f; uint i; - FftArrange(n, in, out); - FftSummation(n, -1.0, out); + FftArrange(n, inout); + FftSummation(n, -1.0, inout); f = 1.0 / n; for(i = 0;i < n;i++) - out[i] = c_muls(out[i], f); + inout[i] = c_muls(inout[i], f); } /* Calculate the complex helical sequence (or discrete-time analytical signal) @@ -1085,30 +1069,22 @@ static void FftInverse(const uint n, const Complex *in, Complex *out) * of a signal's magnitude response, the imaginary components can be used as * the angles for minimum-phase reconstruction. */ -static void Hilbert(const uint n, const Complex *in, Complex *out) +static void Hilbert(const uint n, Complex *inout) { uint i; - if(in == out) - { - // Handle in-place operation. - for(i = 0;i < n;i++) - out[i].Imag = 0.0; - } - else - { - // Handle copy operation. - for(i = 0;i < n;i++) - out[i] = MakeComplex(in[i].Real, 0.0); - } - FftInverse(n, out, out); + // Handle in-place operation. + for(i = 0;i < n;i++) + inout[i].Imag = 0.0; + + FftInverse(n, inout); for(i = 1;i < (n+1)/2;i++) - out[i] = c_muls(out[i], 2.0); + inout[i] = c_muls(inout[i], 2.0); /* Increment i if n is even. */ i += (n&1)^1; for(;i < n;i++) - out[i] = MakeComplex(0.0, 0.0); - FftForward(n, out, out); + inout[i] = MakeComplex(0.0, 0.0); + FftForward(n, inout); } /* Calculate the magnitude response of the given input. This is used in @@ -1175,7 +1151,7 @@ static void MinimumPhase(const uint n, const double *in, Complex *out) mags[i] = mags[n - i]; out[i] = out[n - i]; } - Hilbert(n, out, out); + Hilbert(n, out); // Remove any DC offset the filter has. mags[0] = EPSILON; for(i = 0;i < n;i++) @@ -2073,7 +2049,7 @@ static void AverageHrirMagnitude(const uint points, const uint n, const double * h[i] = MakeComplex(hrir[i], 0.0); for(;i < n;i++) h[i] = MakeComplex(0.0, 0.0); - FftForward(n, h, h); + FftForward(n, h); MagnitudeResponse(n, h, r); for(i = 0;i < m;i++) mag[i] = Lerp(mag[i], r[i], f); @@ -2243,7 +2219,7 @@ static void ReconstructHrirs(const HrirDataT *hData) for(ti = 0;ti < channels;ti++) { MinimumPhase(n, azd->mIrs[ti], h); - FftInverse(n, h, h); + FftInverse(n, h); for(i = 0;i < hData->mIrPoints;i++) azd->mIrs[ti][i] = h[i].Real; pcdone = ++count * 100 / total; -- cgit v1.2.3 From 46c59f382f5d417a8e95a58a8e2156b9c4b35f1a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:49:45 -0700 Subject: Use fastf2i instead of manual rounding in another place --- Alc/effects/modulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7f1a2cad..db771103 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -137,7 +137,8 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->GetSamples = ModulateSquare; - state->step = float2int(props->Modulator.Frequency*WAVEFORM_FRACONE/device->Frequency + 0.5f); + state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * + WAVEFORM_FRACONE); state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); /* Custom filter coeffs, which match the old version instead of a low-shelf. */ -- cgit v1.2.3 From 0b7f35b28922e2250f06d1aee1ebb60bfecf91d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 May 2018 22:55:21 -0700 Subject: Avoid extra sample copies and storage in the modulator effect --- Alc/effects/modulator.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index db771103..7985f03e 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -40,8 +40,6 @@ typedef struct ALmodulatorState { ALsizei index; ALsizei step; - alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES]; - struct { BiquadFilter Filter; @@ -162,13 +160,12 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat *restrict modsamples = ASSUME_ALIGNED(state->ModSamples, 16); const ALsizei step = state->step; ALsizei base; for(base = 0;base < SamplesToDo;) { - alignas(16) ALfloat temps[2][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES]; ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base); ALsizei c, i; @@ -178,11 +175,13 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesT for(c = 0;c < MAX_EFFECT_CHANNELS;c++) { - BiquadFilter_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td); + alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES]; + + BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td); for(i = 0;i < td;i++) - temps[1][i] = temps[0][i] * modsamples[i]; + temps[i] *= modsamples[i]; - MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[c].CurrentGains, + MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains, state->Chans[c].TargetGains, SamplesToDo-base, base, td); } -- cgit v1.2.3 From 1bba276aaf007c8ef5b5ca495b300f63c8f1c5f7 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Thu, 31 May 2018 15:47:47 +0200 Subject: EFX: Ring modulator fixes Change from unipolar to bipolar carrier signal in the Ring modulator effect. --- Alc/effects/modulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 7985f03e..b629b584 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -63,17 +63,17 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); static inline ALfloat Sin(ALsizei index) { - return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f; + return sinf(index * (F_TAU / WAVEFORM_FRACONE)); } static inline ALfloat Saw(ALsizei index) { - return (ALfloat)index / WAVEFORM_FRACONE; + return index*(2.0f/WAVEFORM_FRACONE) - 1.0f; } static inline ALfloat Square(ALsizei index) { - return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1); + return ((index>>(WAVEFORM_FRACBITS-1))&1)*2.0f - 1.0f; } #define DECL_TEMPLATE(func) \ -- cgit v1.2.3 From f76509950308df52bd29a988a109e9cb0e53e3ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 31 May 2018 19:43:02 -0700 Subject: Slightly simplify the modulator square wave generator --- Alc/effects/modulator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index b629b584..f743a2b2 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -63,17 +63,17 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState); static inline ALfloat Sin(ALsizei index) { - return sinf(index * (F_TAU / WAVEFORM_FRACONE)); + return sinf((ALfloat)index * (F_TAU / WAVEFORM_FRACONE)); } static inline ALfloat Saw(ALsizei index) { - return index*(2.0f/WAVEFORM_FRACONE) - 1.0f; + return (ALfloat)index*(2.0f/WAVEFORM_FRACONE) - 1.0f; } static inline ALfloat Square(ALsizei index) { - return ((index>>(WAVEFORM_FRACBITS-1))&1)*2.0f - 1.0f; + return (ALfloat)(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } #define DECL_TEMPLATE(func) \ -- cgit v1.2.3 From 7865ebb6d5d92adb7f4c17e4765a3ebb892b3a59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 31 May 2018 22:21:00 -0700 Subject: Use the biquad high-pass in the ring modulator --- Alc/effects/modulator.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index f743a2b2..495942aa 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -125,7 +125,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevic static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; - ALfloat cw, a; + ALfloat f0norm; ALsizei i; if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) @@ -139,15 +139,11 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext WAVEFORM_FRACONE); state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); - /* Custom filter coeffs, which match the old version instead of a low-shelf. */ - cw = cosf(F_TAU * props->Modulator.HighPassCutoff / device->Frequency); - a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); - - state->Chans[0].Filter.b0 = a; - state->Chans[0].Filter.b1 = -a; - state->Chans[0].Filter.b2 = 0.0f; - state->Chans[0].Filter.a1 = -a; - state->Chans[0].Filter.a2 = 0.0f; + f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; + f0norm = maxf(f0norm, FLT_EPSILON); + /* Bandwidth value is constant in octaves. */ + BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, + f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); for(i = 1;i < MAX_EFFECT_CHANNELS;i++) BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter); -- cgit v1.2.3 From 48b265e136adab3d0f424bd1adbbf0641fa5697f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Jun 2018 23:47:02 -0700 Subject: Use a higher normalized frequency limit for the ring modulator --- Alc/effects/modulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 495942aa..e6143001 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -140,7 +140,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; - f0norm = maxf(f0norm, FLT_EPSILON); + f0norm = maxf(f0norm, 0.003125f); /* Bandwidth value is constant in octaves. */ BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); -- cgit v1.2.3 From 72e4b603747124b398448cf3b408d09ff0544015 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Jun 2018 01:40:17 -0700 Subject: Clamp the maximum normalized reference frequency too --- Alc/effects/modulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index e6143001..a5180669 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -140,7 +140,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; - f0norm = maxf(f0norm, 0.003125f); + f0norm = clampf(f0norm, 1.0f/512.0f, 0.5f); /* Bandwidth value is constant in octaves. */ BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); -- cgit v1.2.3 From bd9c6989c20ea40cc12dd54105ec708c4b28beaa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Jun 2018 23:10:37 -0700 Subject: Clear the TLS pointer after running its destructor callback --- common/threads.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/threads.c b/common/threads.c index 2655a244..6cfe383b 100644 --- a/common/threads.c +++ b/common/threads.c @@ -428,7 +428,11 @@ void althrd_thread_detach(void) { void *ptr = altss_get(TlsDestructors.keys[i]); altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i]; - if(ptr && callback) callback(ptr); + if(ptr) + { + if(callback) callback(ptr); + altss_set(TlsDestructors.keys[i], NULL); + } } UnlockUIntMapRead(&TlsDestructors); } -- cgit v1.2.3 From 35b78d55a4554d41bfcb8864c080ea1164c9b183 Mon Sep 17 00:00:00 2001 From: kdhp Date: Fri, 8 Jun 2018 01:42:13 +0000 Subject: Stop capture devices while closing In 'alcCaptureCloseDevice', check if the capture device is running and stop it if necessary. This fixes the case where the device data is deallocated while a background thread is still running (Issue #199) --- Alc/ALc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1858c29b..2e9dc710 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -4401,6 +4401,12 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) } UnlockLists(); + almtx_lock(&device->BackendLock); + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; + almtx_unlock(&device->BackendLock); + ALCdevice_DecRef(device); return ALC_TRUE; -- cgit v1.2.3 From fd1458ce1bfef0d8f8baba0aff5edb5cfa0940a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Jun 2018 05:02:47 -0700 Subject: Always prepare the ALSA PCM handle before starting capture Draining the ALSA device via stopping puts it into a setup state, which requires re-preparing before playback can start again. Preparing it prior to the first start seems to cause no harm, so just always do it before starting. --- Alc/backends/alsa.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index e0fdc070..409be7fa 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -1153,10 +1153,17 @@ error2: static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self) { - int err = snd_pcm_start(self->pcmHandle); + int err = snd_pcm_prepare(self->pcmHandle); + if(err < 0) + ERR("prepare failed: %s\n", snd_strerror(err)); + else + { + err = snd_pcm_start(self->pcmHandle); + if(err < 0) + ERR("start failed: %s\n", snd_strerror(err)); + } if(err < 0) { - ERR("start failed: %s\n", snd_strerror(err)); aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s", snd_strerror(err)); return ALC_FALSE; -- cgit v1.2.3 From 73e08e51ba3eb156240c4b240829d85548d25f5a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Jun 2018 19:49:13 -0700 Subject: Properly get the full executable and pathname on FreeBSD --- Alc/helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index e54f3fb2..53d85a86 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -676,13 +676,13 @@ void GetProcBinary(al_string *path, al_string *fname) size_t pathlen; #ifdef __FreeBSD__ - int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid() }; - if(sysctl(mib, 3, NULL, &pathlen, NULL, 0) == -1) - WARN("Failed to sysctl kern.procargs.%d: %s\n", mib[2], strerror(errno)); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if(sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) + WARN("Failed to sysctl kern.proc.pathname: %s\n", strerror(errno)); else { pathname = malloc(pathlen + 1); - sysctl(mib, 3, (void*)pathname, &pathlen, NULL, 0); + sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0); pathname[pathlen] = 0; } #endif -- cgit v1.2.3 From a80ab012270bc38f6e07f535e445051af3b85349 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Wed, 20 Jun 2018 10:40:25 +0200 Subject: Correctly check byte order for newer Android compiler, fix #203 --- OpenAL32/Include/alMain.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 093f7950..74dba1ad 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -184,8 +184,8 @@ inline int fallback_ctz64(ALuint64 value) #define CTZ64 fallback_ctz64 #endif -#if defined(__BYTE_ORDER__) && defined(__LITTLE_ENDIAN__) -#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __LITTLE_ENDIAN__) +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) +#define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #else static const union { ALuint u; -- cgit v1.2.3 From e2d7c5dfb362736bde27db9a973310a15fd90c41 Mon Sep 17 00:00:00 2001 From: Tobias Kortkamp Date: Fri, 22 Jun 2018 14:36:33 +0200 Subject: Prefer sndio over OSS when both are enabled Signed-off-by: Tobias Kortkamp --- Alc/ALc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 2e9dc710..26219752 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -75,15 +75,15 @@ static struct BackendInfo BackendList[] = { #ifdef HAVE_COREAUDIO { "core", ALCcoreAudioBackendFactory_getFactory }, #endif -#ifdef HAVE_OSS - { "oss", ALCossBackendFactory_getFactory }, -#endif #ifdef HAVE_SOLARIS { "solaris", ALCsolarisBackendFactory_getFactory }, #endif #ifdef HAVE_SNDIO { "sndio", ALCsndioBackendFactory_getFactory }, #endif +#ifdef HAVE_OSS + { "oss", ALCossBackendFactory_getFactory }, +#endif #ifdef HAVE_QSA { "qsa", ALCqsaBackendFactory_getFactory }, #endif -- cgit v1.2.3 From 4c61103e34b190c53f0669cb341355d031044571 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Mon, 2 Jul 2018 17:09:53 -0700 Subject: Fix COPYING Remove bad chars, remove section that shouldn't be there. --- COPYING | 60 ++++++++---------------------------------------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/COPYING b/COPYING index 5bc8fb2c..8d5d0000 100644 --- a/COPYING +++ b/COPYING @@ -51,7 +51,7 @@ library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. - + Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect @@ -98,7 +98,7 @@ works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. - + GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -145,7 +145,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -203,7 +203,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. - + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -254,7 +254,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. - + 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -308,7 +308,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. - + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -349,7 +349,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. - + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -401,7 +401,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. - + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is @@ -435,47 +435,3 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! -- cgit v1.2.3 From ed1f1d2bf331110ab6cc55797272eeb968760048 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2018 21:01:26 -0700 Subject: Start an extension to allow source filter gains greater than 1 --- Alc/ALc.c | 1 + OpenAL32/alFilter.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 26219752..97d62812 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -725,6 +725,7 @@ static const ALchar alExtList[] = "AL_SOFT_deferred_updates " "AL_SOFT_direct_channels " "AL_SOFTX_events " + "AL_SOFTX_filter_gain_ex " "AL_SOFT_gain_clamp_ex " "AL_SOFT_loop_points " "AL_SOFTX_map_buffer " diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index 7d8a886c..e57653e0 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -28,6 +28,9 @@ #include "alError.h" +#define FILTER_MIN_GAIN 0.0f +#define FILTER_MAX_GAIN 4.0f /* +12dB */ + extern inline void LockFilterList(ALCdevice *device); extern inline void UnlockFilterList(ALCdevice *device); @@ -347,7 +350,7 @@ static void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum pa switch(param) { case AL_LOWPASS_GAIN: - if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN)) + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val); filter->Gain = val; break; @@ -400,7 +403,7 @@ static void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum p switch(param) { case AL_HIGHPASS_GAIN: - if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN)) + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range"); filter->Gain = val; break; @@ -453,7 +456,7 @@ static void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum p switch(param) { case AL_BANDPASS_GAIN: - if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN)) + if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN)) SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range"); filter->Gain = val; break; -- cgit v1.2.3 From d117a5209f390dfe97e072fa9665fdbf449828f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 16 Jul 2018 08:41:56 -0700 Subject: On 32-bit targets with SSE, enable SSE/SSE2 codegen by default Two new CMake options are available for 32-bit targets that accept -msse: ALSOFT_ENABLE_SSE_CODEGEN and ALSOFT_ENABLE_SSE2_CODEGEN, which default to TRUE. This should not affect MSVC, which already defaults to SSE2 codegen. --- CMakeLists.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c27c6e4e..b7de4a69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,6 +432,30 @@ IF(HAVE_MFPU_NEON_SWITCH) SET(FPU_NEON_SWITCH "-mfpu=neon") ENDIF() +SET(FPMATH_SET "0") +IF(HAVE_MSSE_SWITCH AND CMAKE_SIZEOF_VOID_P MATCHES "4") + OPTION(ALSOFT_ENABLE_SSE_CODEGEN "Enable SSE code generation instead of x87 for 32-bit targets." TRUE) + IF(HAVE_MSSE2_SWITCH) + OPTION(ALSOFT_ENABLE_SSE2_CODEGEN "Enable SSE2 code generation instead of x87 for 32-bit targets." TRUE) + ENDIF() + + IF(HAVE_MSSE2_SWITCH AND ALSOFT_ENABLE_SSE2_CODEGEN) + CHECK_C_COMPILER_FLAG("${SSE2_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE_2) + IF(ALSOFT_ENABLE_SSE2_CODEGEN AND HAVE_MFPMATH_SSE_2) + SET(C_FLAGS ${C_FLAGS} ${SSE2_SWITCH} -mfpmath=sse) + SET(FPMATH_SET 2) + ENDIF() + ENDIF() + IF(ALSOFT_ENABLE_SSE_CODEGEN AND NOT FPMATH_SET) + CHECK_C_COMPILER_FLAG("${SSE_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE) + IF(ALSOFT_ENABLE_SSE_CODEGEN AND HAVE_MFPMATH_SSE) + SET(C_FLAGS ${C_FLAGS} ${SSE_SWITCH} -mfpmath=sse) + SET(FPMATH_SET 1) + ENDIF() + ENDIF() +ENDIF() + + CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2))); int main() {return 0;}" HAVE_GCC_FORMAT) @@ -1471,6 +1495,10 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Building with support for CPU extensions:") MESSAGE(STATUS " ${CPU_EXTS}") MESSAGE(STATUS "") +IF(FPMATH_SET) + MESSAGE(STATUS "Building with SSE${FPMATH_SET} codegen") + MESSAGE(STATUS "") +ENDIF() IF(WIN32) IF(NOT HAVE_DSOUND) -- cgit v1.2.3 From 6fe1ffa3bb822105f1f0a848adba22478eef02a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2018 14:21:00 -0700 Subject: Improve handling of 0hz ring modulator frequency --- Alc/effects/modulator.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index a5180669..797a2075 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -76,6 +76,11 @@ static inline ALfloat Square(ALsizei index) return (ALfloat)(((index>>(WAVEFORM_FRACBITS-2))&2) - 1); } +static inline ALfloat One(ALsizei UNUSED(index)) +{ + return 1.0f; +} + #define DECL_TEMPLATE(func) \ static void Modulate##func(ALfloat *restrict dst, ALsizei index, \ const ALsizei step, ALsizei todo) \ @@ -92,6 +97,7 @@ static void Modulate##func(ALfloat *restrict dst, ALsizei index, \ DECL_TEMPLATE(Sin) DECL_TEMPLATE(Saw) DECL_TEMPLATE(Square) +DECL_TEMPLATE(One) #undef DECL_TEMPLATE @@ -128,17 +134,19 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext ALfloat f0norm; ALsizei i; - if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * + WAVEFORM_FRACONE); + state->step = clampi(state->step, 0, WAVEFORM_FRACONE-1); + + if(state->step == 0) + state->GetSamples = ModulateOne; + else if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->GetSamples = ModulateSin; else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) state->GetSamples = ModulateSaw; else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/ state->GetSamples = ModulateSquare; - state->step = fastf2i(props->Modulator.Frequency / (ALfloat)device->Frequency * - WAVEFORM_FRACONE); - state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1); - f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; f0norm = clampf(f0norm, 1.0f/512.0f, 0.5f); /* Bandwidth value is constant in octaves. */ -- cgit v1.2.3 From 809f709ba6afd81defae132128f68d0fce56ea82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 21 Jul 2018 14:22:52 -0700 Subject: Limit the normalized filter frequency to under half Nearing half, weird things can start happening with the filters' generated sine and cosine values. --- Alc/effects/modulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 797a2075..9855b1b8 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -148,7 +148,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext state->GetSamples = ModulateSquare; f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency; - f0norm = clampf(f0norm, 1.0f/512.0f, 0.5f); + f0norm = clampf(f0norm, 1.0f/512.0f, 0.49f); /* Bandwidth value is constant in octaves. */ BiquadFilter_setParams(&state->Chans[0].Filter, BiquadType_HighPass, 1.0f, f0norm, calc_rcpQ_from_bandwidth(f0norm, 0.75f)); -- cgit v1.2.3 From 83dba26ea6a1bbbd3c9ba266523204014446ef09 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 22 Jul 2018 00:48:54 +0200 Subject: EFX: Autowah implementation Add autowah effect using biquad peaking filter and envelope follower --- Alc/ALc.c | 7 +- Alc/effects/autowah.c | 266 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 1 + OpenAL32/Include/alAuxEffectSlot.h | 1 + OpenAL32/Include/alEffect.h | 11 +- OpenAL32/alAuxEffectSlot.c | 1 + OpenAL32/alEffect.c | 8 ++ 7 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 Alc/effects/autowah.c diff --git a/Alc/ALc.c b/Alc/ALc.c index 97d62812..535f9475 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -555,9 +555,7 @@ static const struct { DECL(AL_EFFECT_VOCAL_MORPHER), #endif DECL(AL_EFFECT_RING_MODULATOR), -#if 0 DECL(AL_EFFECT_AUTOWAH), -#endif DECL(AL_EFFECT_COMPRESSOR), DECL(AL_EFFECT_EQUALIZER), DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), @@ -658,6 +656,11 @@ static const struct { DECL(AL_DEDICATED_GAIN), + DECL(AL_AUTOWAH_ATTACK_TIME), + DECL(AL_AUTOWAH_RELEASE_TIME), + DECL(AL_AUTOWAH_RESONANCE), + DECL(AL_AUTOWAH_PEAK_GAIN), + DECL(AL_NUM_RESAMPLERS_SOFT), DECL(AL_DEFAULT_RESAMPLER_SOFT), DECL(AL_SOURCE_RESAMPLER_SOFT), diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c new file mode 100644 index 00000000..e9dbf304 --- /dev/null +++ b/Alc/effects/autowah.c @@ -0,0 +1,266 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2018 by Raul Herraiz. + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include +#include + +#include "alMain.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" +#include "filters/defs.h" + +#define MIN_FREQ 20.0f +#define MAX_FREQ 2500.0f +#define Q_FACTOR 5.0f + + +typedef struct ALautowahState { + DERIVE_FROM_TYPE(ALeffectState); + + /* Effect parameters */ + ALfloat AttackRate; + ALfloat ReleaseRate; + ALfloat ResonanceGain; + ALfloat PeakGain; + ALfloat FreqMinNorm; + ALfloat BandwidthNorm; + ALfloat env_delay; + + BiquadFilter Filter; + + /*Effects buffers*/ + alignas(16) ALfloat BufferOut[BUFFERSIZE]; + + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; +} ALautowahState; + +static ALvoid ALautowahState_Destruct(ALautowahState *state); +static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device); +static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props); +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ALautowahState) + +DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); + +/*Envelope follewer described on the book: Audio Effects, Theory, Implementation and Application*/ +static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn) +{ + ALfloat alpha, Sample; + + Sample = state->PeakGain*fabsf(SampleIn); + alpha = (Sample > state->env_delay) ? state->AttackRate : state->ReleaseRate; + state->env_delay = alpha*state->env_delay + (1.0f-alpha)*Sample; + + return state->env_delay; +} + +static void ALautowahState_Construct(ALautowahState *state) +{ + ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); + SET_VTABLE2(ALautowahState, ALeffectState, state); +} + +static ALvoid ALautowahState_Destruct(ALautowahState *state) +{ + ALeffectState_Destruct(STATIC_CAST(ALeffectState,state)); +} + +static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) +{ + /* (Re-)initializing parameters and clear the buffers. */ + state->AttackRate = 1.0f; + state->ReleaseRate = 1.0f; + state->ResonanceGain = 10.0f; + state->PeakGain = 4.5f; + state->FreqMinNorm = 4.5e-4f; + state->BandwidthNorm = 0.05f; + state->env_delay = 0.0f; + + BiquadFilter_clear(&state->Filter); + + memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); + memset(state->TargetGains, 0, sizeof(state->TargetGains)); + + return AL_TRUE; +} + +static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) +{ + const ALCdevice *device = context->Device; + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALfloat ReleaseTime; + + ReleaseTime = clampf(props->Autowah.ReleaseTime,0.001f,1.0f); + + state->AttackRate = expf(-1.0f/(props->Autowah.AttackTime*device->Frequency)); + state->ReleaseRate = expf(-1.0f/(ReleaseTime*device->Frequency)); + state->ResonanceGain = 10.0f/3.0f*log10f(props->Autowah.Resonance);/*0-20dB Resonance Peak gain*/ + state->PeakGain = 1.0f -log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + state->FreqMinNorm = MIN_FREQ/device->Frequency; + state->BandwidthNorm = (MAX_FREQ - MIN_FREQ)/device->Frequency; + + CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); + ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); +} + +static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +{ + ALfloat *restrict BufferOut = state->BufferOut; + ALsizei i; + + for(i = 0;i < SamplesToDo;i++) + { + ALfloat env_out, f0norm, temp; + + env_out = envelope_follower(state, SamplesIn[0][i]); + f0norm = state->BandwidthNorm*env_out + state->FreqMinNorm; + + BiquadFilter_setParams(&state->Filter, BiquadType_Peaking, state->ResonanceGain, + f0norm, 1.0f/Q_FACTOR); + BiquadFilter_process(&state->Filter, &temp, &SamplesIn[0][i], 1); + + BufferOut[i] = temp; + } + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, + SamplesToDo, 0, SamplesToDo); + +} + +typedef struct AutowahStateFactory { + DERIVE_FROM_TYPE(EffectStateFactory); +} AutowahStateFactory; + +static ALeffectState *AutowahStateFactory_create(AutowahStateFactory *UNUSED(factory)) +{ + ALautowahState *state; + + NEW_OBJ0(state, ALautowahState)(); + if(!state) return NULL; + + return STATIC_CAST(ALeffectState, state); +} + +DEFINE_EFFECTSTATEFACTORY_VTABLE(AutowahStateFactory); + +EffectStateFactory *AutowahStateFactory_getFactory(void) +{ + static AutowahStateFactory AutowahFactory = { { GET_VTABLE2(AutowahStateFactory, EffectStateFactory) } }; + + return STATIC_CAST(EffectStateFactory, &AutowahFactory); +} + +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)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah attack time out of range"); + props->Autowah.AttackTime = val; + break; + + case AL_AUTOWAH_RELEASE_TIME: + if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah release time out of range"); + props->Autowah.ReleaseTime = val; + break; + + case AL_AUTOWAH_RESONANCE: + if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah resonance out of range"); + props->Autowah.Resonance = val; + break; + + case AL_AUTOWAH_PEAK_GAIN: + if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) + SETERR_RETURN(context, AL_INVALID_VALUE,,"Autowah peak gain out of range"); + props->Autowah.PeakGain = val; + break; + + default: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } +} + +void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ALautowah_setParamf(effect, context, param, vals[0]); +} + +void ALautowah_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); +} + +void ALautowah_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); +} + +void ALautowah_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); +} +void ALautowah_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals)) +{ + alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); +} + +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: + alSetError(context, AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param); + } + +} + +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/CMakeLists.txt b/CMakeLists.txt index b7de4a69..a7d13777 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -779,6 +779,7 @@ SET(ALC_OBJS Alc/mastering.h Alc/ringbuffer.c Alc/ringbuffer.h + Alc/effects/autowah.c Alc/effects/chorus.c Alc/effects/compressor.c Alc/effects/dedicated.c diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index c1eae443..c4d662f1 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -160,6 +160,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); EffectStateFactory *NullStateFactory_getFactory(void); EffectStateFactory *ReverbStateFactory_getFactory(void); +EffectStateFactory *AutowahStateFactory_getFactory(void); EffectStateFactory *ChorusStateFactory_getFactory(void); EffectStateFactory *CompressorStateFactory_getFactory(void); EffectStateFactory *DistortionStateFactory_getFactory(void); diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h index 4d28a708..7b849c0c 100644 --- a/OpenAL32/Include/alEffect.h +++ b/OpenAL32/Include/alEffect.h @@ -12,6 +12,7 @@ struct ALeffect; enum { EAXREVERB_EFFECT = 0, REVERB_EFFECT, + AUTOWAH_EFFECT, CHORUS_EFFECT, COMPRESSOR_EFFECT, DISTORTION_EFFECT, @@ -34,7 +35,7 @@ struct EffectList { int type; ALenum val; }; -#define EFFECTLIST_SIZE 13 +#define EFFECTLIST_SIZE 14 extern const struct EffectList EffectList[EFFECTLIST_SIZE]; @@ -60,6 +61,7 @@ const struct ALeffectVtable T##_vtable = { \ 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; @@ -103,6 +105,13 @@ typedef union ALeffectProps { ALfloat LFReference; } Reverb; + struct { + ALfloat AttackTime; + ALfloat ReleaseTime; + ALfloat Resonance; + ALfloat PeakGain; + } Autowah; + struct { ALint Waveform; ALint Phase; diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 6f6ef163..815a8d5a 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -48,6 +48,7 @@ static const struct { { AL_EFFECT_NULL, NullStateFactory_getFactory }, { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory }, { AL_EFFECT_REVERB, ReverbStateFactory_getFactory }, + { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory }, { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory }, { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory }, { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory }, diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c index aacddd4c..c2a78a0c 100644 --- a/OpenAL32/alEffect.c +++ b/OpenAL32/alEffect.c @@ -38,6 +38,7 @@ extern inline ALboolean IsReverbEffect(ALenum type); const struct EffectList EffectList[EFFECTLIST_SIZE] = { { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB }, { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB }, + { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH }, { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS }, { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR }, { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION }, @@ -534,6 +535,13 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; effect->vtab = &ALreverb_vtable; break; + case AL_EFFECT_AUTOWAH: + effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME; + effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME; + effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE; + effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN; + effect->vtab = &ALautowah_vtable; + break; case AL_EFFECT_CHORUS: effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM; effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE; -- cgit v1.2.3 From f79683d45986cade438404d82d56176ca20de3a2 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 22 Jul 2018 00:49:52 +0200 Subject: Alsoft-config: Add autowah effect --- alsoftrc.sample | 5 +++-- utils/alsoft-config/mainwindow.cpp | 4 ++++ utils/alsoft-config/mainwindow.ui | 30 +++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/alsoftrc.sample b/alsoftrc.sample index 04dd72f6..8061ed1c 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -219,8 +219,9 @@ ## excludefx: (global) # 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,chorus,compressor, -# distortion,echo,equalizer,flanger,modulator,dedicated,pshifter,fshifter +# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus, +# compressor,distortion,echo,equalizer,flanger,modulator,dedicated,pshifter, +# fshifter #excludefx = ## default-reverb: (global) diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 07b5992b..110fe4ed 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -372,6 +372,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->defaultReverbComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); connect(ui->enableEaxReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableStdReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableAutowahCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableChorusCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableCompressorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); connect(ui->enableDistortionCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); @@ -839,6 +840,7 @@ void MainWindow::loadConfig(const QString &fname) *iter = iter->trimmed(); ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); + ui->enableAutowahCheck->setChecked(!excludefx.contains("autowah", Qt::CaseInsensitive)); ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive)); ui->enableCompressorCheck->setChecked(!excludefx.contains("compressor", Qt::CaseInsensitive)); ui->enableDistortionCheck->setChecked(!excludefx.contains("distortion", Qt::CaseInsensitive)); @@ -1046,6 +1048,8 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("eaxreverb"); if(!ui->enableStdReverbCheck->isChecked()) strlist.append("reverb"); + if(!ui->enableAutowahCheck->isChecked()) + strlist.append("autowah"); if(!ui->enableChorusCheck->isChecked()) strlist.append("chorus"); if(!ui->enableDistortionCheck->isChecked()) diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 18a00659..9c89cbc7 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -53,7 +53,7 @@ - 0 + 5 @@ -131,8 +131,8 @@ to stereo output. 380 20 - 93 - 29 + 80 + 20 @@ -1933,7 +1933,7 @@ be useful for preventing those extensions from being used. 10 100 511 - 231 + 241 @@ -2140,6 +2140,22 @@ added by the ALC_EXT_DEDICATED extension. true + + + + 70 + 210 + 131 + 21 + + + + Autowah + + + true + + @@ -2162,8 +2178,8 @@ added by the ALC_EXT_DEDICATED extension. 160 20 - 125 - 29 + 108 + 20 @@ -2332,7 +2348,7 @@ added by the ALC_EXT_DEDICATED extension. 0 0 564 - 27 + 21 -- cgit v1.2.3 From 92fd59fe6af1e60a19d54ebfb034c2b81580e63a Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Sun, 22 Jul 2018 00:50:39 +0200 Subject: EFX: Add 3D processing for autowah Add 3D processing code. It can be activated at compilation time. --- Alc/effects/autowah.c | 91 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index e9dbf304..6b7b3241 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -33,6 +33,13 @@ #define MAX_FREQ 2500.0f #define Q_FACTOR 5.0f +/*#define EFFECTS*/ + +#ifndef EFFECTS +#define CHANNELS 1 +#else +#define CHANNELS MAX_EFFECT_CHANNELS +#endif typedef struct ALautowahState { DERIVE_FROM_TYPE(ALeffectState); @@ -44,16 +51,19 @@ typedef struct ALautowahState { ALfloat PeakGain; ALfloat FreqMinNorm; ALfloat BandwidthNorm; - ALfloat env_delay; + ALfloat env_delay[MAX_EFFECT_CHANNELS]; - BiquadFilter Filter; + struct { + /* Effect gains for each output channel */ + ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; + ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - /*Effects buffers*/ - alignas(16) ALfloat BufferOut[BUFFERSIZE]; + /* Effect filters */ + BiquadFilter Filter; + } Chans[MAX_EFFECT_CHANNELS]; - /* Effect gains for each output channel */ - ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; - ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; + /*Effects buffers*/ + alignas(16) ALfloat BufferOut[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALautowahState; static ALvoid ALautowahState_Destruct(ALautowahState *state); @@ -65,15 +75,15 @@ DECLARE_DEFAULT_ALLOCATORS(ALautowahState) DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); /*Envelope follewer described on the book: Audio Effects, Theory, Implementation and Application*/ -static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn) +static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn, ALsizei Index) { ALfloat alpha, Sample; Sample = state->PeakGain*fabsf(SampleIn); - alpha = (Sample > state->env_delay) ? state->AttackRate : state->ReleaseRate; - state->env_delay = alpha*state->env_delay + (1.0f-alpha)*Sample; + alpha = (Sample > state->env_delay[Index]) ? state->AttackRate : state->ReleaseRate; + state->env_delay[Index] = alpha*state->env_delay[Index] + (1.0f-alpha)*Sample; - return state->env_delay; + return state->env_delay[Index]; } static void ALautowahState_Construct(ALautowahState *state) @@ -90,18 +100,22 @@ static ALvoid ALautowahState_Destruct(ALautowahState *state) static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *UNUSED(device)) { /* (Re-)initializing parameters and clear the buffers. */ + ALsizei i, j; + state->AttackRate = 1.0f; state->ReleaseRate = 1.0f; state->ResonanceGain = 10.0f; state->PeakGain = 4.5f; state->FreqMinNorm = 4.5e-4f; state->BandwidthNorm = 0.05f; - state->env_delay = 0.0f; - - BiquadFilter_clear(&state->Filter); - memset(state->CurrentGains, 0, sizeof(state->CurrentGains)); - memset(state->TargetGains, 0, sizeof(state->TargetGains)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + { + state->env_delay[i] = 0.0f; + BiquadFilter_clear(&state->Chans[i].Filter); + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + state->Chans[i].CurrentGains[j] = 0.0f; + } return AL_TRUE; } @@ -109,8 +123,8 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props) { const ALCdevice *device = context->Device; - ALfloat coeffs[MAX_AMBI_COEFFS]; ALfloat ReleaseTime; + ALuint i; ReleaseTime = clampf(props->Autowah.ReleaseTime,0.001f,1.0f); @@ -121,32 +135,37 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con state->FreqMinNorm = MIN_FREQ/device->Frequency; state->BandwidthNorm = (MAX_FREQ - MIN_FREQ)/device->Frequency; - CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], + slot->Params.Gain, state->Chans[i].TargetGains); } static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat *restrict BufferOut = state->BufferOut; - ALsizei i; + ALfloat (*restrict BufferOut)[BUFFERSIZE] = state->BufferOut; + ALsizei c, i; - for(i = 0;i < SamplesToDo;i++) + for(c = 0;c < CHANNELS; c++) { - ALfloat env_out, f0norm, temp; - - env_out = envelope_follower(state, SamplesIn[0][i]); - f0norm = state->BandwidthNorm*env_out + state->FreqMinNorm; - - BiquadFilter_setParams(&state->Filter, BiquadType_Peaking, state->ResonanceGain, - f0norm, 1.0f/Q_FACTOR); - BiquadFilter_process(&state->Filter, &temp, &SamplesIn[0][i], 1); - - BufferOut[i] = temp; + for(i = 0;i < SamplesToDo;i++) + { + ALfloat env_out, f0norm, temp; + + env_out = envelope_follower(state, SamplesIn[c][i], c); + f0norm = state->BandwidthNorm*env_out + state->FreqMinNorm; + + BiquadFilter_setParams(&state->Chans[c].Filter, BiquadType_Peaking, + state->ResonanceGain, f0norm, 1.0f/Q_FACTOR); + BiquadFilter_process(&state->Chans[c].Filter, &temp, &SamplesIn[c][i], 1); + + BufferOut[c][i] = temp; + } + /* Now, mix the processed sound data to the output. */ + MixSamples(BufferOut[c], NumChannels, SamplesOut, state->Chans[c].CurrentGains, + state->Chans[c].TargetGains, SamplesToDo, 0, SamplesToDo); } - /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains, - SamplesToDo, 0, SamplesToDo); - } typedef struct AutowahStateFactory { -- cgit v1.2.3 From 7d68eeac882c62c68ce835c842ce5805d14b3b30 Mon Sep 17 00:00:00 2001 From: Raulshc <33253777+Raulshc@users.noreply.github.com> Date: Wed, 25 Jul 2018 21:26:01 +0200 Subject: EFX: Enable 3D processing Use channel 0 envelope for calculate the frequency in all channels. --- Alc/effects/autowah.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 6b7b3241..7cc2539e 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -33,14 +33,6 @@ #define MAX_FREQ 2500.0f #define Q_FACTOR 5.0f -/*#define EFFECTS*/ - -#ifndef EFFECTS -#define CHANNELS 1 -#else -#define CHANNELS MAX_EFFECT_CHANNELS -#endif - typedef struct ALautowahState { DERIVE_FROM_TYPE(ALeffectState); @@ -51,7 +43,7 @@ typedef struct ALautowahState { ALfloat PeakGain; ALfloat FreqMinNorm; ALfloat BandwidthNorm; - ALfloat env_delay[MAX_EFFECT_CHANNELS]; + ALfloat env_delay; struct { /* Effect gains for each output channel */ @@ -75,15 +67,15 @@ DECLARE_DEFAULT_ALLOCATORS(ALautowahState) DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); /*Envelope follewer described on the book: Audio Effects, Theory, Implementation and Application*/ -static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn, ALsizei Index) +static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn) { ALfloat alpha, Sample; Sample = state->PeakGain*fabsf(SampleIn); - alpha = (Sample > state->env_delay[Index]) ? state->AttackRate : state->ReleaseRate; - state->env_delay[Index] = alpha*state->env_delay[Index] + (1.0f-alpha)*Sample; + alpha = (Sample > state->env_delay) ? state->AttackRate : state->ReleaseRate; + state->env_delay = alpha*state->env_delay + (1.0f-alpha)*Sample; - return state->env_delay[Index]; + return state->env_delay; } static void ALautowahState_Construct(ALautowahState *state) @@ -108,10 +100,10 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U state->PeakGain = 4.5f; state->FreqMinNorm = 4.5e-4f; state->BandwidthNorm = 0.05f; + state->env_delay = 0.0f; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - state->env_delay[i] = 0.0f; BiquadFilter_clear(&state->Chans[i].Filter); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; @@ -145,19 +137,24 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALfloat (*restrict BufferOut)[BUFFERSIZE] = state->BufferOut; + ALfloat f0norm[BUFFERSIZE]; ALsizei c, i; - for(c = 0;c < CHANNELS; c++) + for(i = 0;i < SamplesToDo;i++) + { + ALfloat env_out; + env_out = envelope_follower(state, SamplesIn[0][i]); + f0norm[i] = state->BandwidthNorm*env_out + state->FreqMinNorm; + } + + for(c = 0;c < MAX_EFFECT_CHANNELS; c++) { for(i = 0;i < SamplesToDo;i++) { - ALfloat env_out, f0norm, temp; - - env_out = envelope_follower(state, SamplesIn[c][i], c); - f0norm = state->BandwidthNorm*env_out + state->FreqMinNorm; + ALfloat temp; BiquadFilter_setParams(&state->Chans[c].Filter, BiquadType_Peaking, - state->ResonanceGain, f0norm, 1.0f/Q_FACTOR); + state->ResonanceGain, f0norm[i], 1.0f/Q_FACTOR); BiquadFilter_process(&state->Chans[c].Filter, &temp, &SamplesIn[c][i], 1); BufferOut[c][i] = temp; -- cgit v1.2.3 From 39a5d0cb9494c771c870c0952c25d64e87191667 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jul 2018 13:15:47 -0700 Subject: Mark a couple parameters as unused --- Alc/effects/autowah.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 7cc2539e..b58970ab 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -237,7 +237,7 @@ void ALautowah_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x", param); } -void ALautowah_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +void ALautowah_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val)) { alSetError(context, AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param); } -- cgit v1.2.3 From 8ab448b119681f1d3a22a72f457299bbcc74d571 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jul 2018 13:48:53 -0700 Subject: Inline the autowah peaking filter processing --- Alc/effects/autowah.c | 113 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 39 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index b58970ab..5bdd5dda 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -45,17 +45,23 @@ typedef struct ALautowahState { ALfloat BandwidthNorm; ALfloat env_delay; + /* Filter components derived from the envelope. */ + ALfloat Alpha[BUFFERSIZE]; + ALfloat CosW0[BUFFERSIZE]; + struct { + /* Effect filters' history. */ + struct { + ALfloat z1, z2; + } Filter; + /* Effect gains for each output channel */ ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - - /* Effect filters */ - BiquadFilter Filter; } Chans[MAX_EFFECT_CHANNELS]; - /*Effects buffers*/ - alignas(16) ALfloat BufferOut[MAX_EFFECT_CHANNELS][BUFFERSIZE]; + /* Effects buffers */ + alignas(16) ALfloat BufferOut[BUFFERSIZE]; } ALautowahState; static ALvoid ALautowahState_Destruct(ALautowahState *state); @@ -66,18 +72,6 @@ DECLARE_DEFAULT_ALLOCATORS(ALautowahState) DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); -/*Envelope follewer described on the book: Audio Effects, Theory, Implementation and Application*/ -static inline ALfloat envelope_follower(ALautowahState *state, ALfloat SampleIn) -{ - ALfloat alpha, Sample; - - Sample = state->PeakGain*fabsf(SampleIn); - alpha = (Sample > state->env_delay) ? state->AttackRate : state->ReleaseRate; - state->env_delay = alpha*state->env_delay + (1.0f-alpha)*Sample; - - return state->env_delay; -} - static void ALautowahState_Construct(ALautowahState *state) { ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); @@ -104,9 +98,10 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { - BiquadFilter_clear(&state->Chans[i].Filter); for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) state->Chans[i].CurrentGains[j] = 0.0f; + state->Chans[i].Filter.z1 = 0.0f; + state->Chans[i].Filter.z2 = 0.0f; } return AL_TRUE; @@ -116,16 +111,17 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con { const ALCdevice *device = context->Device; ALfloat ReleaseTime; - ALuint i; + ALsizei i; - ReleaseTime = clampf(props->Autowah.ReleaseTime,0.001f,1.0f); + ReleaseTime = clampf(props->Autowah.ReleaseTime, 0.001f, 1.0f); - state->AttackRate = expf(-1.0f/(props->Autowah.AttackTime*device->Frequency)); - state->ReleaseRate = expf(-1.0f/(ReleaseTime*device->Frequency)); - state->ResonanceGain = 10.0f/3.0f*log10f(props->Autowah.Resonance);/*0-20dB Resonance Peak gain*/ - state->PeakGain = 1.0f -log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); - state->FreqMinNorm = MIN_FREQ/device->Frequency; - state->BandwidthNorm = (MAX_FREQ - MIN_FREQ)/device->Frequency; + state->AttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); + state->ReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); + /* 0-20dB Resonance Peak gain */ + state->ResonanceGain = log10f(props->Autowah.Resonance)*10.0f / 3.0f; + state->PeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); + state->FreqMinNorm = MIN_FREQ / device->Frequency; + state->BandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; @@ -136,31 +132,70 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*restrict BufferOut)[BUFFERSIZE] = state->BufferOut; - ALfloat f0norm[BUFFERSIZE]; + const ALfloat peak_gain = state->PeakGain; + const ALfloat attack_rate = state->AttackRate; + const ALfloat release_rate = state->ReleaseRate; + const ALfloat freq_min = state->FreqMinNorm; + const ALfloat bandwidth = state->BandwidthNorm; + ALfloat env_delay; ALsizei c, i; + env_delay = state->env_delay; for(i = 0;i < SamplesToDo;i++) { - ALfloat env_out; - env_out = envelope_follower(state, SamplesIn[0][i]); - f0norm[i] = state->BandwidthNorm*env_out + state->FreqMinNorm; + ALfloat w0, sample, a; + + /* Envelope follower described on the book: Audio Effects, Theory, + * Implementation and Application. + */ + sample = peak_gain * fabsf(SamplesIn[0][i]); + a = (sample > env_delay) ? attack_rate : release_rate; + env_delay = lerp(sample, env_delay, a); + + /* Calculate the cos and alpha components for this sample's filter. */ + w0 = (bandwidth*env_delay + freq_min) * F_TAU; + state->CosW0[i] = cosf(w0); + state->Alpha[i] = sinf(w0)/(2.0f * Q_FACTOR); } + state->env_delay = env_delay; for(c = 0;c < MAX_EFFECT_CHANNELS; c++) { + /* This effectively inlines BiquadFilter_setParams for a peaking + * filter and BiquadFilter_processC. The alpha and cosine components + * for the filter coefficients were previously calculated with the + * envelope. Because the filter changes for each sample, the + * coefficients are transient and don't need to be held. + */ + const ALfloat res_gain = sqrtf(state->ResonanceGain); + ALfloat z1 = state->Chans[c].Filter.z1; + ALfloat z2 = state->Chans[c].Filter.z2; + for(i = 0;i < SamplesToDo;i++) { - ALfloat temp; - - BiquadFilter_setParams(&state->Chans[c].Filter, BiquadType_Peaking, - state->ResonanceGain, f0norm[i], 1.0f/Q_FACTOR); - BiquadFilter_process(&state->Chans[c].Filter, &temp, &SamplesIn[c][i], 1); - - BufferOut[c][i] = temp; + const ALfloat alpha = state->Alpha[i]; + const ALfloat cos_w0 = state->CosW0[i]; + ALfloat input, output; + ALfloat a[3], b[3]; + + b[0] = 1.0f + alpha*res_gain; + b[1] = -2.0f * cos_w0; + b[2] = 1.0f - alpha*res_gain; + a[0] = 1.0f + alpha/res_gain; + a[1] = -2.0f * cos_w0; + a[2] = 1.0f - alpha/res_gain; + + input = SamplesIn[c][i]; + output = input*(b[0]/a[0]) + z1; + z1 = input*(b[1]/a[0]) - output*(a[1]/a[0]) + z2; + z2 = input*(b[2]/a[0]) - output*(a[2]/a[0]); + state->BufferOut[i] = output; } + state->Chans[c].Filter.z1 = z1; + state->Chans[c].Filter.z2 = z2; + /* Now, mix the processed sound data to the output. */ - MixSamples(BufferOut[c], NumChannels, SamplesOut, state->Chans[c].CurrentGains, + MixSamples(state->BufferOut, NumChannels, SamplesOut, state->Chans[c].CurrentGains, state->Chans[c].TargetGains, SamplesToDo, 0, SamplesToDo); } } -- cgit v1.2.3 From f1bf932a84a188b1f79a6affc17265128f738ae6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jul 2018 14:11:12 -0700 Subject: Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 80a55df7..7e6a5009 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,7 @@ openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. - Implemented the Pitch Shifter and Frequency Shifter effects. + Implemented the Pitch Shifter, Frequency Shifter, and Autowah effects. Fixed compiling on FreeBSD systems that use freebsd-lib 9.1. -- cgit v1.2.3 From 3894c580bf0059e93bb6171b661e2f96dc1ab27f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 29 Jul 2018 00:18:46 -0700 Subject: Use just the omnidirectional response for the compressor effect This is not the output compressor/limiter, but the EFX effect. Consequently, it simply compresses the dynamic range around 1.0 (boosting samples below it by up to double, reducing samples above it by as much as half). This is not intended to prevent clipping on the output, but to instead reduce the range between quiet sounds and loud sounds. --- Alc/effects/compressor.c | 122 ++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 64 deletions(-) diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index 4ec28f9a..a5f1953b 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -27,6 +27,13 @@ #include "alu.h" +#define AMP_ENVELOPE_MIN 0.5f +#define AMP_ENVELOPE_MAX 2.0f + +#define ATTACK_TIME 0.1f /* 100ms to rise from min to max */ +#define RELEASE_TIME 0.2f /* 200ms to drop from max to min */ + + typedef struct ALcompressorState { DERIVE_FROM_TYPE(ALeffectState); @@ -35,9 +42,9 @@ typedef struct ALcompressorState { /* Effect parameters */ ALboolean Enabled; - ALfloat AttackRate; - ALfloat ReleaseRate; - ALfloat GainCtrl; + ALfloat AttackMult; + ALfloat ReleaseMult; + ALfloat EnvFollower; } ALcompressorState; static ALvoid ALcompressorState_Destruct(ALcompressorState *state); @@ -55,9 +62,9 @@ static void ALcompressorState_Construct(ALcompressorState *state) SET_VTABLE2(ALcompressorState, ALeffectState, state); state->Enabled = AL_TRUE; - state->AttackRate = 0.0f; - state->ReleaseRate = 0.0f; - state->GainCtrl = 1.0f; + state->AttackMult = 1.0f; + state->ReleaseMult = 1.0f; + state->EnvFollower = 1.0f; } static ALvoid ALcompressorState_Destruct(ALcompressorState *state) @@ -67,11 +74,17 @@ static ALvoid ALcompressorState_Destruct(ALcompressorState *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; + /* Number of samples to do a full attack and release (non-integer sample + * counts are okay). + */ + const ALfloat attackCount = (ALfloat)device->Frequency * ATTACK_TIME; + const ALfloat releaseCount = (ALfloat)device->Frequency * RELEASE_TIME; + + /* Calculate per-sample multipliers to attack and release at the desired + * rates. + */ + state->AttackMult = powf(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount); + state->ReleaseMult = powf(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount); return AL_TRUE; } @@ -97,71 +110,52 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample for(base = 0;base < SamplesToDo;) { - ALfloat temps[64][4]; - ALsizei td = mini(64, SamplesToDo-base); - - /* Load samples into the temp buffer first. */ - for(j = 0;j < 4;j++) - { - for(i = 0;i < td;i++) - temps[i][j] = SamplesIn[j][i+base]; - } + ALfloat gains[256]; + ALsizei td = mini(256, SamplesToDo-base); + ALfloat env = state->EnvFollower; + /* Generate the per-sample gains from the signal envelope. */ if(state->Enabled) { - ALfloat gain = state->GainCtrl; - ALfloat output, amplitude; - - for(i = 0;i < td;i++) + for(i = 0;i < td;++i) { - /* Roughly calculate the maximum amplitude from the 4-channel - * signal, and attack or release the gain control to reach it. + /* Clamp the absolute amplitude to the defined envelope limits, + * then attack or release the envelope to reach it. + */ + ALfloat amplitude = clampf(fabsf(SamplesIn[0][base+i]), + AMP_ENVELOPE_MIN, AMP_ENVELOPE_MAX); + if(amplitude > env) + env = minf(env*state->AttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*state->ReleaseMult, amplitude); + + /* Apply the reciprocal of the envelope to normalize the volume + * (compress the dynamic range). */ - amplitude = fabsf(temps[i][0]); - amplitude = maxf(amplitude + fabsf(temps[i][1]), - maxf(amplitude + fabsf(temps[i][2]), - amplitude + fabsf(temps[i][3]))); - if(amplitude > gain) - gain = minf(gain+state->AttackRate, amplitude); - else if(amplitude < gain) - gain = maxf(gain-state->ReleaseRate, amplitude); - - /* Apply the inverse of the gain control to normalize/compress - * the volume. */ - output = 1.0f / clampf(gain, 0.5f, 2.0f); - for(j = 0;j < 4;j++) - temps[i][j] *= output; + gains[i] = 1.0f / env; } - - state->GainCtrl = gain; } else { - ALfloat gain = state->GainCtrl; - ALfloat output, amplitude; - - for(i = 0;i < td;i++) + /* Same as above, except the amplitude is forced to 1. This helps + * ensure smooth gain changes when the compressor is turned on and + * off. + */ + for(i = 0;i < td;++i) { - /* Same as above, except the amplitude is forced to 1. This - * helps ensure smooth gain changes when the compressor is - * turned on and off. - */ - 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); - for(j = 0;j < 4;j++) - temps[i][j] *= output; - } + ALfloat amplitude = 1.0f; + if(amplitude > env) + env = minf(env*state->AttackMult, amplitude); + else if(amplitude < env) + env = maxf(env*state->ReleaseMult, amplitude); - state->GainCtrl = gain; + gains[i] = 1.0f / env; + } } + state->EnvFollower = env; - /* Now mix to the output. */ - for(j = 0;j < 4;j++) + /* Now compress the signal amplitude to output. */ + for(j = 0;j < MAX_EFFECT_CHANNELS;j++) { for(k = 0;k < NumChannels;k++) { @@ -170,7 +164,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample continue; for(i = 0;i < td;i++) - SamplesOut[k][base+i] += gain * temps[i][j]; + SamplesOut[k][base+i] += SamplesIn[k][base+i] * gains[i] * gain; } } -- cgit v1.2.3 From aa58a5d20864283cf0cd9dfbcca5c02d5c54e00e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Aug 2018 02:48:31 -0700 Subject: Fix late reverb density gain blend weights Now it only accounts for the representable frequency range (0.5 normalized, or 0...pi radians instead of tau). Previously, the bulk of the weighting factors was given to the HF decay (nearly 90%, given a 44.1khz sample rate and the default 5khz reference), with low- and mid-frequency decays splitting the remaining 10%. Now it's closer to 75%, matching the range of representable frequencies above the reference. This could probably be improved further due to human hearing being less sensitive to higher frequencies, but that is much more complicated. --- Alc/effects/reverb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 12e78bdf..a4381389 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1014,10 +1014,10 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co */ bandWeights[0] = lfW; bandWeights[1] = hfW - lfW; - bandWeights[2] = F_TAU - hfW; + bandWeights[2] = F_PI - hfW; Late->DensityGain = CalcDensityGain( CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + - bandWeights[2]*hfDecayTime) / F_TAU) + bandWeights[2]*hfDecayTime) / F_PI) ); for(i = 0;i < NUM_LINES;i++) @@ -1151,14 +1151,14 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte ALsizei i; /* Calculate the master filters */ - hf0norm = props->Reverb.HFReference / frequency; + hf0norm = minf(props->Reverb.HFReference / frequency, 0.49f); /* Restrict the filter gains from going below -60dB to keep the filter from * killing most of the signal. */ gainhf = maxf(props->Reverb.GainHF, 0.001f); BiquadFilter_setParams(&State->Filter[0].Lp, BiquadType_HighShelf, gainhf, hf0norm, calc_rcpQ_from_slope(gainhf, 1.0f)); - lf0norm = props->Reverb.LFReference / frequency; + lf0norm = minf(props->Reverb.LFReference / frequency, 0.49f); gainlf = maxf(props->Reverb.GainLF, 0.001f); BiquadFilter_setParams(&State->Filter[0].Hp, BiquadType_LowShelf, gainlf, lf0norm, calc_rcpQ_from_slope(gainlf, 1.0f)); -- cgit v1.2.3 From 0c67429a38836115c7dfafac989d41f006d88c86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 1 Aug 2018 16:08:27 -0700 Subject: Apply late reverb density gain adjustment on output Because density/late line length changes start affecting late reverb output right away, with samples that are still going through feedback decay and not just new input samples, it makes more sense to correct for it on output instead of input. This has the additional benefit of working with the output mixer's gain fading, avoiding discontinuities from significant density gain changes. --- Alc/effects/reverb.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a4381389..2c5205a1 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -258,11 +258,6 @@ typedef struct EarlyReflections { } EarlyReflections; typedef struct LateReverb { - /* Attenuation to compensate for the modal density and decay rate of the - * late lines. - */ - ALfloat DensityGain; - /* A recursive delay line is used fill in the reverb tail. */ DelayLineI Delay; ALsizei Offset[NUM_LINES][2]; @@ -386,8 +381,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Coeff[i] = 0.0f; } - state->Late.DensityGain = 0.0f; - state->Late.Delay.Mask = 0; state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; @@ -987,7 +980,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, LateReverb *Late) +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALfloat *density_gain, LateReverb *Late) { ALfloat multiplier, length, bandWeights[3]; ALsizei i; @@ -1007,15 +1000,16 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = lerp(length, echoTime, echoDepth); length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; - /* The density gain calculation uses an average decay time weighted by - * approximate bandwidth. This attempts to compensate for losses of - * energy that reduce decay time due to scattering into highly attenuated - * bands. + /* Attenuation to compensate for the modal density and decay rate of the + * late lines. The density gain calculation uses an average decay time + * weighted by approximate bandwidth. This attempts to compensate for + * losses of energy that reduce decay time due to scattering into highly + * attenuated bands. */ bandWeights[0] = lfW; bandWeights[1] = hfW - lfW; bandWeights[2] = F_PI - hfW; - Late->DensityGain = CalcDensityGain( + *density_gain = CalcDensityGain( CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime) / F_PI) ); @@ -1103,7 +1097,7 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) } /* Update the early and late 3D panning gains. */ -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat gain, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State) +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State) { aluMatrixf transform, rot; ALsizei i; @@ -1128,14 +1122,14 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection MATRIX_MULT(transform, rot, A2B); memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], gain*earlyGain, + ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], earlyGain, State->Early.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); MATRIX_MULT(transform, rot, A2B); memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], gain*lateGain, + ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], lateGain, State->Late.PanGain[i]); #undef MATRIX_MULT } @@ -1148,6 +1142,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte ALfloat lf0norm, hf0norm, hfRatio; ALfloat lfDecayTime, hfDecayTime; ALfloat gain, gainlf, gainhf; + ALfloat density_gain; ALsizei i; /* Calculate the master filters */ @@ -1203,14 +1198,14 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte lfDecayTime, props->Reverb.DecayTime, hfDecayTime, F_TAU * lf0norm, F_TAU * hf0norm, props->Reverb.EchoTime, props->Reverb.EchoDepth, - frequency, &State->Late); + frequency, &density_gain, &State->Late); /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; - Update3DPanning(Device, props->Reverb.ReflectionsPan, - props->Reverb.LateReverbPan, gain, - props->Reverb.ReflectionsGain, - props->Reverb.LateReverbGain, State); + Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, + props->Reverb.ReflectionsGain * gain, + props->Reverb.LateReverbGain * gain * density_gain, + State); /* Determine if delay-line cross-fading is required. */ for(i = 0;i < NUM_LINES;i++) @@ -1490,7 +1485,7 @@ static void LateReverb_##T(ALreverbState *State, const ALsizei todo, \ f[j] = T##DelayLineOut(&State->Delay, \ offset - State->LateDelayTap[j][0], \ offset - State->LateDelayTap[j][1], j, fade \ - ) * State->Late.DensityGain; \ + ); \ \ for(j = 0;j < NUM_LINES;j++) \ f[j] += T##DelayLineOut(&State->Late.Delay, \ -- cgit v1.2.3 From 57b860d8cacff4599da5aec52b67902a57bb6b55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Aug 2018 00:07:08 -0700 Subject: Trace the NFC reference distance when set --- Alc/panning.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Alc/panning.c b/Alc/panning.c index e4562387..51d65a24 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -425,6 +425,7 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde * be used when rendering to an ambisonic buffer. */ device->AvgSpeakerDist = minf(ctrl_dist, 10.0f); + TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); for(i = 0;i < order+1;i++) device->Dry.NumChannelsPerOrder[i] = chans_per_order[i]; -- cgit v1.2.3 From 754a32fa169b170a1c5c078c8e454ebb9570f313 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 3 Aug 2018 20:04:08 -0700 Subject: Scale the reverb decay weights to cover up to 20khz Otherwise, using the device's maximum frequency will cause the weighting factors to shift for different sample rates, irrespective of the content being processed. 20khz is the maximum allowed reference frequency, and also acts as the upper limit of human hearing. --- Alc/effects/reverb.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 2c5205a1..f30956e5 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -980,8 +980,12 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lfW, const ALfloat hfW, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALfloat *density_gain, LateReverb *Late) +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALfloat *density_gain, LateReverb *Late) { + /* Scaling factor to convert the normalized reference frequencies from + * representing 0...freq to 0...max_reference. + */ + const ALfloat norm_weight_factor = (ALfloat)frequency / AL_EAXREVERB_MAX_HFREFERENCE; ALfloat multiplier, length, bandWeights[3]; ALsizei i; @@ -1006,12 +1010,13 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co * losses of energy that reduce decay time due to scattering into highly * attenuated bands. */ - bandWeights[0] = lfW; - bandWeights[1] = hfW - lfW; - bandWeights[2] = F_PI - hfW; + bandWeights[0] = lf0norm*norm_weight_factor; + bandWeights[1] = hf0norm*norm_weight_factor - lf0norm*norm_weight_factor; + bandWeights[2] = 1.0f - hf0norm*norm_weight_factor; *density_gain = CalcDensityGain( - CalcDecayCoeff(length, (bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + - bandWeights[2]*hfDecayTime) / F_PI) + CalcDecayCoeff(length, + bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime + ) ); for(i = 0;i < NUM_LINES;i++) @@ -1043,7 +1048,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the T60 damping coefficients for each line. */ CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, - lfW, hfW, Late->T60[i].LFCoeffs, + lf0norm*F_TAU, hf0norm*F_TAU, Late->T60[i].LFCoeffs, Late->T60[i].HFCoeffs); } } @@ -1195,10 +1200,10 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, - lfDecayTime, props->Reverb.DecayTime, hfDecayTime, - F_TAU * lf0norm, F_TAU * hf0norm, - props->Reverb.EchoTime, props->Reverb.EchoDepth, - frequency, &density_gain, &State->Late); + lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, + props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, &density_gain, + &State->Late + ); /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; -- cgit v1.2.3 From 3f165040e2e7880c36f431bce4af13b64b2692d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 4 Aug 2018 22:48:44 -0700 Subject: Mix reverb samples right after generating them Instead of generating both the early and late reverb samples first, then mixing them both to output, this now generates and mixes the early reflections then generates and mixes the late reverb. There's no reason to hold both at the same time so this reduces the amount of temporary storage needed. --- Alc/effects/reverb.c | 67 ++++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index f30956e5..3e157cbc 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -318,8 +318,7 @@ typedef struct ALreverbState { /* Temporary storage used when processing. */ alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat ReverbSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; - alignas(16) ALfloat EarlySamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; } ALreverbState; static ALvoid ALreverbState_Destruct(ALreverbState *State); @@ -1520,8 +1519,7 @@ DECL_TEMPLATE(Faded) static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; - ALfloat (*restrict early)[MAX_UPDATE_SAMPLES] = State->EarlySamples; - ALfloat (*restrict late)[MAX_UPDATE_SAMPLES] = State->ReverbSamples; + ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; ALsizei fadeCount = State->FadeCount; ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; ALsizei base, c; @@ -1544,32 +1542,53 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Process the samples for reverb. */ for(c = 0;c < NUM_LINES;c++) { - /* Band-pass the incoming samples. Use the early output lines for - * temp storage. - */ - BiquadFilter_process(&State->Filter[c].Lp, early[0], afmt[c], todo); - BiquadFilter_process(&State->Filter[c].Hp, early[1], early[0], todo); + /* Band-pass the incoming samples. */ + BiquadFilter_process(&State->Filter[c].Lp, samples[0], afmt[c], todo); + BiquadFilter_process(&State->Filter[c].Hp, samples[1], samples[0], todo); /* Feed the initial delay line. */ - DelayLineIn(&State->Delay, State->Offset, c, early[1], todo); + DelayLineIn(&State->Delay, State->Offset, c, samples[1], todo); } if(UNLIKELY(fadeCount < FADE_SAMPLES)) { /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, early); + EarlyReflection_Faded(State, todo, fade, samples); + /* Mix the A-Format results to output, implicitly converting back + * to B-Format. + */ + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo + ); - /* Generate late reverb. */ - LateReverb_Faded(State, todo, fade, late); + /* Generate and mix late reverb. */ + LateReverb_Faded(State, todo, fade, samples); fade = minf(1.0f, fade + todo*FadeStep); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo + ); } else { - /* Generate early reflections. */ - EarlyReflection_Unfaded(State, todo, fade, early); + /* Generate and mix early reflections. */ + EarlyReflection_Unfaded(State, todo, fade, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo + ); - /* Generate late reverb. */ - LateReverb_Unfaded(State, todo, fade, late); + /* Generate and mix late reverb. */ + LateReverb_Unfaded(State, todo, fade, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo + ); } /* Step all delays forward. */ @@ -1591,20 +1610,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c } } - /* Mix the A-Format results to output, implicitly converting back to - * B-Format. - */ - for(c = 0;c < NUM_LINES;c++) - MixSamples(early[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], - SamplesToDo-base, base, todo - ); - for(c = 0;c < NUM_LINES;c++) - MixSamples(late[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], - SamplesToDo-base, base, todo - ); - base += todo; } State->FadeCount = fadeCount; -- cgit v1.2.3 From 4aa029183b8fcdf16f43ee953cab809c9274eebd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 Aug 2018 00:45:13 -0700 Subject: Apply the reverb's T60 filter in groups of samples The late reverb line lengths are long enough to ensure a single process loop won't rely on reading samples it wrote in the same call. So we can safely read in all samples we need from the feedback buffer up front, then more efficiently filter them. --- Alc/effects/reverb.c | 132 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 54 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 3e157cbc..7ef95cf3 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -317,7 +317,7 @@ typedef struct ALreverbState { ALsizei Offset; /* Temporary storage used when processing. */ - alignas(16) ALfloat AFormatSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; + alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; } ALreverbState; @@ -1035,6 +1035,11 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the delay offset for each delay line. */ Late->Offset[i][1] = float2int(length*frequency + 0.5f); + /* Late reverb is processed in chunks, so ensure the feedback delays + * are long enough to avoid needing to read what's written in a given + * update. + */ + assert(Late->Offset[i][1] >= MAX_UPDATE_SAMPLES); /* Approximate the absorption that the vector all-pass would exhibit * given the current diffusion so we don't have to process a full T60 @@ -1434,25 +1439,33 @@ DECL_TEMPLATE(Unfaded) DECL_TEMPLATE(Faded) #undef DECL_TEMPLATE -/* Applies a first order filter section. */ -static inline ALfloat FirstOrderFilter(const ALfloat in, const ALfloat *restrict coeffs, - ALfloat *restrict state) -{ - ALfloat out = coeffs[0]*in + *state; - *state = coeffs[1]*in + coeffs[2]*out; - return out; -} - /* Applies the two T60 damping filter sections. */ -static inline void LateT60Filter(ALfloat *restrict out, const ALfloat *restrict in, - T60Filter *filter) +static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, T60Filter *filter) { + const ALfloat hfb0 = filter->HFCoeffs[0]; + const ALfloat hfb1 = filter->HFCoeffs[1]; + const ALfloat hfa1 = filter->HFCoeffs[2]; + const ALfloat lfb0 = filter->LFCoeffs[0]; + const ALfloat lfb1 = filter->LFCoeffs[1]; + const ALfloat lfa1 = filter->LFCoeffs[2]; + ALfloat hfz = filter->HFState; + ALfloat lfz = filter->LFState; ALsizei i; - for(i = 0;i < NUM_LINES;i++) - out[i] = FirstOrderFilter( - FirstOrderFilter(in[i], filter[i].HFCoeffs, &filter[i].HFState), - filter[i].LFCoeffs, &filter[i].LFState - ); + + for(i = 0;i < todo;i++) + { + ALfloat in = samples[i]; + ALfloat out = in*hfb0 + hfz; + hfz = in*hfb1 + out*hfa1; + + in = out; + out = in*lfb0 + lfz; + lfz = in*lfb1 + out*lfa1; + + samples[i] = out; + } + filter->HFState = hfz; + filter->LFState = lfz; } /* This generates the reverb tail using a modified feed-back delay network @@ -1474,30 +1487,39 @@ static void LateReverb_##T(ALreverbState *State, const ALsizei todo, \ ALfloat fade, \ ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ { \ + ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; \ const ALfloat apFeedCoeff = State->ApFeedCoeff; \ const ALfloat mixX = State->MixX; \ const ALfloat mixY = State->MixY; \ ALsizei offset; \ ALsizei i, j; \ \ + for(j = 0;j < NUM_LINES;j++) \ + { \ + ALfloat fader = fade; \ + offset = State->Offset; \ + for(i = 0;i < todo;i++) \ + { \ + temps[j][i] = T##DelayLineOut(&State->Delay, \ + offset - State->LateDelayTap[j][0], \ + offset - State->LateDelayTap[j][1], j, fader \ + ) + T##DelayLineOut(&State->Late.Delay, \ + offset - State->Late.Offset[j][0], \ + offset - State->Late.Offset[j][1], j, fader \ + ); \ + ++offset; \ + fader += FadeStep; \ + } \ + LateT60Filter(temps[j], todo, &State->Late.T60[j]); \ + } \ + \ offset = State->Offset; \ for(i = 0;i < todo;i++) \ { \ ALfloat f[NUM_LINES], fr[NUM_LINES]; \ - \ for(j = 0;j < NUM_LINES;j++) \ - f[j] = T##DelayLineOut(&State->Delay, \ - offset - State->LateDelayTap[j][0], \ - offset - State->LateDelayTap[j][1], j, fade \ - ); \ + fr[j] = temps[j][i]; \ \ - for(j = 0;j < NUM_LINES;j++) \ - f[j] += T##DelayLineOut(&State->Late.Delay, \ - offset - State->Late.Offset[j][0], \ - offset - State->Late.Offset[j][1], j, fade \ - ); \ - \ - LateT60Filter(fr, f, State->Late.T60); \ VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ &State->Late.VecAp); \ \ @@ -1518,7 +1540,7 @@ DECL_TEMPLATE(Faded) static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->AFormatSamples; + ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; ALsizei fadeCount = State->FadeCount; ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; @@ -1550,10 +1572,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c DelayLineIn(&State->Delay, State->Offset, c, samples[1], todo); } - if(UNLIKELY(fadeCount < FADE_SAMPLES)) + if(LIKELY(fadeCount >= FADE_SAMPLES)) { - /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, samples); + /* Generate and mix early reflections. */ + EarlyReflection_Unfaded(State, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back * to B-Format. */ @@ -1564,8 +1586,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ); /* Generate and mix late reverb. */ - LateReverb_Faded(State, todo, fade, samples); - fade = minf(1.0f, fade + todo*FadeStep); + LateReverb_Unfaded(State, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], @@ -1574,8 +1595,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c } else { - /* Generate and mix early reflections. */ - EarlyReflection_Unfaded(State, todo, fade, samples); + /* Generate early reflections. */ + EarlyReflection_Faded(State, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Early.CurrentGain[c], State->Early.PanGain[c], @@ -1583,33 +1604,36 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ); /* Generate and mix late reverb. */ - LateReverb_Unfaded(State, todo, fade, samples); + LateReverb_Faded(State, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], SamplesToDo-base, base, todo ); - } - - /* Step all delays forward. */ - State->Offset += todo; - if(UNLIKELY(fadeCount < FADE_SAMPLES) && (fadeCount += todo) >= FADE_SAMPLES) - { - /* Update the cross-fading delay line taps. */ - fadeCount = FADE_SAMPLES; - fade = 1.0f; - for(c = 0;c < NUM_LINES;c++) + /* Step fading forward. */ + fade += todo*FadeStep; + fadeCount += todo; + if(LIKELY(fadeCount >= FADE_SAMPLES)) { - State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; - State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; - State->Early.Offset[c][0] = State->Early.Offset[c][1]; - State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; - State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; - State->Late.Offset[c][0] = State->Late.Offset[c][1]; + /* Update the cross-fading delay line taps. */ + fadeCount = FADE_SAMPLES; + fade = 1.0f; + for(c = 0;c < NUM_LINES;c++) + { + State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; + State->Early.Offset[c][0] = State->Early.Offset[c][1]; + State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; + State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; + State->Late.Offset[c][0] = State->Late.Offset[c][1]; + } } } + /* Step all delays forward. */ + State->Offset += todo; + base += todo; } State->FadeCount = fadeCount; -- cgit v1.2.3 From 4f92bd59387bd2478487ebd312a045f54747e4a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 5 Aug 2018 20:29:03 -0700 Subject: Apply the vector all-pass separate on uninterleaved samples With the vector all-pass applied in a self-contained function, the individual steps of the early and late reverb stages can be better optimized with tighter loops. That allows for more data to be held local, resulting in less thrashing from reloading the same values multiple times. There is room for further improvement, depending on the length of the early delay lines and all-pass delay lines allowing for bulk reads. --- Alc/effects/reverb.c | 469 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 310 insertions(+), 159 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 7ef95cf3..a14b6926 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1252,9 +1252,9 @@ static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei o return Delay->Line[off0&Delay->Mask][c]*(1.0f-mu) + Delay->Line[off1&Delay->Mask][c]*( mu); } -#define UnfadedDelayLineOut(d, o0, o1, c, mu) DelayLineOut(d, o0, c) -static inline ALvoid DelayLineIn(DelayLineI *Delay, ALsizei offset, const ALsizei c, + +static inline ALvoid DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, const ALfloat *restrict in, ALsizei count) { ALsizei i; @@ -1262,15 +1262,7 @@ static inline ALvoid DelayLineIn(DelayLineI *Delay, ALsizei offset, const ALsize Delay->Line[(offset++)&Delay->Mask][c] = *(in++); } -static inline ALvoid DelayLineIn4(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) -{ - ALsizei i; - offset &= Delay->Mask; - for(i = 0;i < NUM_LINES;i++) - Delay->Line[offset][i] = in[i]; -} - -static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) +static inline ALvoid DelayLineIn4Rev(const DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) { ALsizei i; offset &= Delay->Mask; @@ -1324,6 +1316,8 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re out[2] = xCoeff*in[2] + yCoeff*( in[0] + -in[1] + in[3]); out[3] = xCoeff*in[3] + yCoeff*(-in[0] + -in[1] + -in[2] ); } +#define VectorScatterDelayIn(delay, o, in, xcoeff, ycoeff) \ + VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) /* Same as above, but reverses the input. */ static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat *restrict in, @@ -1334,6 +1328,8 @@ static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat out[2] = xCoeff*in[1] + yCoeff*(in[0] + -in[2] + in[3]); out[3] = xCoeff*in[0] + yCoeff*( -in[1] + -in[2] + -in[3]); } +#define VectorScatterRevDelayIn(delay, o, in, xcoeff, ycoeff) \ + VectorPartialScatterRev((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass * filter to the 4-line input. @@ -1345,34 +1341,72 @@ static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -#define DECL_TEMPLATE(T) \ -static void VectorAllpass_##T(ALfloat *restrict out, \ - const ALfloat *restrict in, \ - const ALsizei offset, const ALfloat feedCoeff, \ - const ALfloat xCoeff, const ALfloat yCoeff, \ - const ALfloat mu, VecAllpass *Vap) \ -{ \ - ALfloat f[NUM_LINES], fs[NUM_LINES]; \ - ALfloat input; \ - ALsizei i; \ - \ - (void)mu; /* Ignore for Unfaded. */ \ - \ - for(i = 0;i < NUM_LINES;i++) \ - { \ - input = in[i]; \ - out[i] = T##DelayLineOut(&Vap->Delay, offset-Vap->Offset[i][0], \ - offset-Vap->Offset[i][1], i, mu) - \ - feedCoeff*input; \ - f[i] = input + feedCoeff*out[i]; \ - } \ - VectorPartialScatter(fs, f, xCoeff, yCoeff); \ - \ - DelayLineIn4(&Vap->Delay, offset, fs); \ +static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], + ALsizei offset, const ALfloat feedCoeff, + const ALfloat xCoeff, const ALfloat yCoeff, + ALsizei todo, VecAllpass *Vap) +{ + const DelayLineI delay = Vap->Delay; + ALsizei vap_offset[NUM_LINES]; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + vap_offset[j] = offset-Vap->Offset[j][0]; + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + { + ALfloat input = samples[j][i]; + ALfloat out = DelayLineOut(&delay, vap_offset[j]++, j) - feedCoeff*input; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + + VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); + ++offset; + } +} +static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], + ALsizei offset, const ALfloat feedCoeff, + const ALfloat xCoeff, const ALfloat yCoeff, + ALfloat fade, ALsizei todo, VecAllpass *Vap) +{ + const DelayLineI delay = Vap->Delay; + ALsizei vap_offset[NUM_LINES][2]; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + { + vap_offset[j][0] = offset-Vap->Offset[j][0]; + vap_offset[j][1] = offset-Vap->Offset[j][1]; + } + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + { + ALfloat input = samples[j][i]; + ALfloat out = + FadedDelayLineOut(&delay, vap_offset[j][0]++, vap_offset[j][1]++, j, fade) - + feedCoeff*input; + f[j] = input + feedCoeff*out; + + samples[j][i] = out; + } + fade += FadeStep; + + VectorScatterDelayIn(&delay, offset, f, xCoeff, yCoeff); + ++offset; + } } -DECL_TEMPLATE(Unfaded) -DECL_TEMPLATE(Faded) -#undef DECL_TEMPLATE /* This generates early reflections. * @@ -1393,51 +1427,128 @@ DECL_TEMPLATE(Faded) * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -#define DECL_TEMPLATE(T) \ -static void EarlyReflection_##T(ALreverbState *State, const ALsizei todo, \ - ALfloat fade, \ - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ -{ \ - ALsizei offset = State->Offset; \ - const ALfloat apFeedCoeff = State->ApFeedCoeff; \ - const ALfloat mixX = State->MixX; \ - const ALfloat mixY = State->MixY; \ - ALfloat f[NUM_LINES], fr[NUM_LINES]; \ - ALsizei i, j; \ - \ - for(i = 0;i < todo;i++) \ - { \ - for(j = 0;j < NUM_LINES;j++) \ - fr[j] = T##DelayLineOut(&State->Delay, \ - offset-State->EarlyDelayTap[j][0], \ - offset-State->EarlyDelayTap[j][1], j, fade \ - ) * State->EarlyDelayCoeff[j]; \ - \ - VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ - &State->Early.VecAp); \ - \ - DelayLineIn4Rev(&State->Early.Delay, offset, f); \ - \ - for(j = 0;j < NUM_LINES;j++) \ - f[j] += T##DelayLineOut(&State->Early.Delay, \ - offset-State->Early.Offset[j][0], \ - offset-State->Early.Offset[j][1], j, fade \ - ) * State->Early.Coeff[j]; \ - \ - for(j = 0;j < NUM_LINES;j++) \ - out[j][i] = f[j]; \ - \ - VectorPartialScatterRev(fr, f, mixX, mixY); \ - \ - DelayLineIn4(&State->Delay, offset-State->LateFeedTap, fr); \ - \ - offset++; \ - fade += FadeStep; \ - } \ +static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI early_delay = State->Early.Delay; + const DelayLineI main_delay = State->Delay; + ALsizei early_feedb_tap[NUM_LINES]; + ALfloat early_feedb_coeff[NUM_LINES]; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei offset = State->Offset; + ALsizei late_feed_tap; + ALsizei i, j; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main delay line as the primary + * reflections. + */ + for(j = 0;j < NUM_LINES;j++) + { + ALsizei early_delay_tap = offset - State->EarlyDelayTap[j][0]; + ALfloat coeff = State->EarlyDelayCoeff[j]; + for(i = 0;i < todo;i++) + temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; + } + + /* Apply a vector all-pass, to help color the initial reflections based on + * the diffusion strength. + */ + VectorAllpass_Unfaded(temps, offset, State->ApFeedCoeff, mixX, mixY, todo, + &State->Early.VecAp); + + for(j = 0;j < NUM_LINES;j++) + { + early_feedb_tap[j] = offset - State->Early.Offset[j][0]; + early_feedb_coeff[j] = State->Early.Coeff[j]; + } + late_feed_tap = offset - State->LateFeedTap; + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + f[j] = temps[j][i]; + + /* Apply a delay and bounce to generate secondary reflections, combine + * with the primary reflections and write out the result for mixing. + */ + DelayLineIn4Rev(&early_delay, offset, f); + for(j = 0;j < NUM_LINES;j++) + { + f[j] += DelayLineOut(&early_delay, early_feedb_tap[j]++, j) * early_feedb_coeff[j]; + out[j][i] = f[j]; + } + + /* Also write the result back to the main delay line for the late + * reverb stage to pick up at the appropriate time, appplying a scatter + * and bounce to improve the initial diffusion in the late reverb. + */ + VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); + offset++; + } +} +static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI early_delay = State->Early.Delay; + const DelayLineI main_delay = State->Delay; + ALsizei early_feedb_tap[NUM_LINES][2]; + ALfloat early_feedb_coeff[NUM_LINES]; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei offset = State->Offset; + ALsizei late_feed_tap; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + { + ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; + ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; + ALfloat coeff = State->EarlyDelayCoeff[j]; + for(i = 0;i < todo;i++) + temps[j][i] = FadedDelayLineOut(&main_delay, + early_delay_tap0++, early_delay_tap1++, j, fade + ) * coeff; + } + + VectorAllpass_Faded(temps, offset, State->ApFeedCoeff, mixX, mixY, fade, todo, + &State->Early.VecAp); + + for(j = 0;j < NUM_LINES;j++) + { + early_feedb_tap[j][0] = offset - State->Early.Offset[j][0]; + early_feedb_tap[j][1] = offset - State->Early.Offset[j][1]; + early_feedb_coeff[j] = State->Early.Coeff[j]; + } + late_feed_tap = offset - State->LateFeedTap; + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + + for(j = 0;j < NUM_LINES;j++) + f[j] = temps[j][i]; + + DelayLineIn4Rev(&early_delay, offset, f); + for(j = 0;j < NUM_LINES;j++) + { + f[j] += FadedDelayLineOut(&early_delay, + early_feedb_tap[j][0]++, early_feedb_tap[j][1]++, j, fade + ) * early_feedb_coeff[j]; + out[j][i] = f[j]; + } + fade += FadeStep; + + VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); + offset++; + } } -DECL_TEMPLATE(Unfaded) -DECL_TEMPLATE(Faded) -#undef DECL_TEMPLATE /* Applies the two T60 damping filter sections. */ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, T60Filter *filter) @@ -1452,6 +1563,8 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, ALfloat lfz = filter->LFState; ALsizei i; + ASSUME(todo > 0); + for(i = 0;i < todo;i++) { ALfloat in = samples[i]; @@ -1471,8 +1584,8 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, /* This generates the reverb tail using a modified feed-back delay network * (FDN). * - * Results from the early reflections are attenuated by the density gain and - * mixed with the output from the late delay lines. + * Results from the early reflections are mixed with the output from the late + * delay lines. * * The late response is then completed by T60 and all-pass filtering the mix. * @@ -1482,61 +1595,99 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -#define DECL_TEMPLATE(T) \ -static void LateReverb_##T(ALreverbState *State, const ALsizei todo, \ - ALfloat fade, \ - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) \ -{ \ - ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; \ - const ALfloat apFeedCoeff = State->ApFeedCoeff; \ - const ALfloat mixX = State->MixX; \ - const ALfloat mixY = State->MixY; \ - ALsizei offset; \ - ALsizei i, j; \ - \ - for(j = 0;j < NUM_LINES;j++) \ - { \ - ALfloat fader = fade; \ - offset = State->Offset; \ - for(i = 0;i < todo;i++) \ - { \ - temps[j][i] = T##DelayLineOut(&State->Delay, \ - offset - State->LateDelayTap[j][0], \ - offset - State->LateDelayTap[j][1], j, fader \ - ) + T##DelayLineOut(&State->Late.Delay, \ - offset - State->Late.Offset[j][0], \ - offset - State->Late.Offset[j][1], j, fader \ - ); \ - ++offset; \ - fader += FadeStep; \ - } \ - LateT60Filter(temps[j], todo, &State->Late.T60[j]); \ - } \ - \ - offset = State->Offset; \ - for(i = 0;i < todo;i++) \ - { \ - ALfloat f[NUM_LINES], fr[NUM_LINES]; \ - for(j = 0;j < NUM_LINES;j++) \ - fr[j] = temps[j][i]; \ - \ - VectorAllpass_##T(f, fr, offset, apFeedCoeff, mixX, mixY, fade, \ - &State->Late.VecAp); \ - \ - for(j = 0;j < NUM_LINES;j++) \ - out[j][i] = f[j]; \ - \ - VectorPartialScatterRev(fr, f, mixX, mixY); \ - \ - DelayLineIn4(&State->Late.Delay, offset, fr); \ - \ - offset++; \ - fade += FadeStep; \ - } \ +static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI late_delay = State->Late.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei offset = State->Offset; + ALsizei i, j; + + ASSUME(todo > 0); + + /* First, load decorrelated samples from the main and feedback delay lines. + * Filter the signal to apply its frequency-dependent decay. + */ + for(j = 0;j < NUM_LINES;j++) + { + ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; + ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; + for(i = 0;i < todo;i++) + temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j) + + DelayLineOut(&late_delay, late_feedb_tap++, j); + LateT60Filter(temps[j], todo, &State->Late.T60[j]); + } + + /* Apply a vector all-pass to improve micro-surface diffusion, and write + * out the results for mixing. + */ + VectorAllpass_Unfaded(temps, offset, State->ApFeedCoeff, mixX, mixY, todo, &State->Late.VecAp); + + for(j = 0;j < NUM_LINES;j++) + memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + for(j = 0;j < NUM_LINES;j++) + f[j] = temps[j][i]; + + /* Finally, scatter and bounce the results to refeed the feedback + * buffer. + */ + VectorScatterRevDelayIn(&late_delay, offset, f, mixX, mixY); + offset++; + } +} +static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, + ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +{ + ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; + const DelayLineI late_delay = State->Late.Delay; + const DelayLineI main_delay = State->Delay; + const ALfloat mixX = State->MixX; + const ALfloat mixY = State->MixY; + ALsizei offset = State->Offset; + ALsizei i, j; + + ASSUME(todo > 0); + + for(j = 0;j < NUM_LINES;j++) + { + ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; + ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; + ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; + ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; + ALfloat fader = fade; + for(i = 0;i < todo;i++) + { + temps[j][i] = + FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, fader) + + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, fader); + fader += FadeStep; + } + LateT60Filter(temps[j], todo, &State->Late.T60[j]); + } + + VectorAllpass_Faded(temps, offset, State->ApFeedCoeff, mixX, mixY, fade, todo, + &State->Late.VecAp); + + for(j = 0;j < NUM_LINES;j++) + memcpy(out[j], temps[j], todo*sizeof(ALfloat)); + + for(i = 0;i < todo;i++) + { + ALfloat f[NUM_LINES]; + for(j = 0;j < NUM_LINES;j++) + f[j] = temps[j][i]; + + VectorScatterRevDelayIn(&late_delay, offset, f, mixX, mixY); + offset++; + } } -DECL_TEMPLATE(Unfaded) -DECL_TEMPLATE(Faded) -#undef DECL_TEMPLATE static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { @@ -1572,10 +1723,10 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c DelayLineIn(&State->Delay, State->Offset, c, samples[1], todo); } - if(LIKELY(fadeCount >= FADE_SAMPLES)) + if(UNLIKELY(fadeCount < FADE_SAMPLES)) { - /* Generate and mix early reflections. */ - EarlyReflection_Unfaded(State, todo, fade, samples); + /* Generate early reflections. */ + EarlyReflection_Faded(State, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back * to B-Format. */ @@ -1585,24 +1736,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c SamplesToDo-base, base, todo ); - /* Generate and mix late reverb. */ - LateReverb_Unfaded(State, todo, fade, samples); - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Late.CurrentGain[c], State->Late.PanGain[c], - SamplesToDo-base, base, todo - ); - } - else - { - /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, samples); - for(c = 0;c < NUM_LINES;c++) - MixSamples(samples[c], NumChannels, SamplesOut, - State->Early.CurrentGain[c], State->Early.PanGain[c], - SamplesToDo-base, base, todo - ); - /* Generate and mix late reverb. */ LateReverb_Faded(State, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) @@ -1630,6 +1763,24 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c } } } + else + { + /* Generate and mix early reflections. */ + EarlyReflection_Unfaded(State, todo, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Early.CurrentGain[c], State->Early.PanGain[c], + SamplesToDo-base, base, todo + ); + + /* Generate and mix late reverb. */ + LateReverb_Unfaded(State, todo, samples); + for(c = 0;c < NUM_LINES;c++) + MixSamples(samples[c], NumChannels, SamplesOut, + State->Late.CurrentGain[c], State->Late.PanGain[c], + SamplesToDo-base, base, todo + ); + } /* Step all delays forward. */ State->Offset += todo; -- cgit v1.2.3 From 32edc7f33fd1a03ad1eaefada1aac3160d9c319a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 6 Aug 2018 14:14:31 -0700 Subject: Prevent the autowah filter frequency from reaching nyquist --- Alc/effects/autowah.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 5bdd5dda..5f45c43a 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -153,7 +153,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, env_delay = lerp(sample, env_delay, a); /* Calculate the cos and alpha components for this sample's filter. */ - w0 = (bandwidth*env_delay + freq_min) * F_TAU; + w0 = minf((bandwidth*env_delay + freq_min), 0.49f) * F_TAU; state->CosW0[i] = cosf(w0); state->Alpha[i] = sinf(w0)/(2.0f * Q_FACTOR); } -- cgit v1.2.3 From 06da60c5551313a08078aae4bf5cd8f662469307 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 6 Aug 2018 21:54:42 -0700 Subject: Make the all-pass coefficient part of the all-pass structure --- Alc/effects/reverb.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a14b6926..c2616331 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -223,6 +223,7 @@ typedef struct DelayLineI { typedef struct VecAllpass { DelayLineI Delay; + ALfloat Coeff; ALsizei Offset[NUM_LINES][2]; } VecAllpass; @@ -299,9 +300,6 @@ typedef struct ALreverbState { ALsizei LateFeedTap; ALsizei LateDelayTap[NUM_LINES][2]; - /* The feed-back and feed-forward all-pass coefficient. */ - ALfloat ApFeedCoeff; - /* Coefficients for the all-pass and line scattering matrices. */ ALfloat MixX; ALfloat MixY; @@ -363,7 +361,6 @@ static void ALreverbState_Construct(ALreverbState *state) state->LateDelayTap[i][1] = 0; } - state->ApFeedCoeff = 0.0f; state->MixX = 0.0f; state->MixY = 0.0f; @@ -384,6 +381,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; state->Late.VecAp.Delay.Line = NULL; + state->Late.VecAp.Coeff = 0.0f; for(i = 0;i < NUM_LINES;i++) { state->Late.Offset[i][0] = 0; @@ -1018,6 +1016,9 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co ) ); + /* Calculate the all-pass feed-back/forward coefficient. */ + Late->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ @@ -1177,9 +1178,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.Density, props->Reverb.DecayTime, frequency, State); - /* Calculate the all-pass feed-back/forward coefficient. */ - State->ApFeedCoeff = sqrtf(0.5f) * powf(props->Reverb.Diffusion, 2.0f); - /* Update the early lines. */ UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime, frequency, &State->Early); @@ -1341,12 +1339,12 @@ static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], - ALsizei offset, const ALfloat feedCoeff, - const ALfloat xCoeff, const ALfloat yCoeff, - ALsizei todo, VecAllpass *Vap) +static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALsizei todo, + VecAllpass *Vap) { const DelayLineI delay = Vap->Delay; + const ALfloat feedCoeff = Vap->Coeff; ALsizei vap_offset[NUM_LINES]; ALsizei i, j; @@ -1371,12 +1369,12 @@ static void VectorAllpass_Unfaded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES ++offset; } } -static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], - ALsizei offset, const ALfloat feedCoeff, - const ALfloat xCoeff, const ALfloat yCoeff, - ALfloat fade, ALsizei todo, VecAllpass *Vap) +static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], ALsizei offset, + const ALfloat xCoeff, const ALfloat yCoeff, ALfloat fade, + ALsizei todo, VecAllpass *Vap) { const DelayLineI delay = Vap->Delay; + const ALfloat feedCoeff = Vap->Coeff; ALsizei vap_offset[NUM_LINES][2]; ALsizei i, j; @@ -1457,8 +1455,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, /* Apply a vector all-pass, to help color the initial reflections based on * the diffusion strength. */ - VectorAllpass_Unfaded(temps, offset, State->ApFeedCoeff, mixX, mixY, todo, - &State->Early.VecAp); + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Early.VecAp); for(j = 0;j < NUM_LINES;j++) { @@ -1518,8 +1515,7 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl ) * coeff; } - VectorAllpass_Faded(temps, offset, State->ApFeedCoeff, mixX, mixY, fade, todo, - &State->Early.VecAp); + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Early.VecAp); for(j = 0;j < NUM_LINES;j++) { @@ -1624,7 +1620,7 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, /* Apply a vector all-pass to improve micro-surface diffusion, and write * out the results for mixing. */ - VectorAllpass_Unfaded(temps, offset, State->ApFeedCoeff, mixX, mixY, todo, &State->Late.VecAp); + VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); @@ -1672,8 +1668,7 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f LateT60Filter(temps[j], todo, &State->Late.T60[j]); } - VectorAllpass_Faded(temps, offset, State->ApFeedCoeff, mixX, mixY, fade, todo, - &State->Late.VecAp); + VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); -- cgit v1.2.3 From 04921dd7275326148fb20dac7ae599c91e8f96b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 6 Aug 2018 23:45:32 -0700 Subject: Properly set early reflection all-pass coefficient --- Alc/effects/reverb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c2616331..dd8167ef 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -366,6 +366,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.VecAp.Delay.Mask = 0; state->Early.VecAp.Delay.Line = NULL; + state->Early.VecAp.Coeff = 0.0f; state->Early.Delay.Mask = 0; state->Early.Delay.Line = NULL; for(i = 0;i < NUM_LINES;i++) @@ -950,13 +951,16 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, } /* Update the early reflection line lengths and gain coefficients. */ -static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) +static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, const ALfloat decayTime, const ALuint frequency, EarlyReflections *Early) { ALfloat multiplier, length; ALsizei i; multiplier = CalcDelayLengthMult(density); + /* Calculate the all-pass feed-back/forward coefficient. */ + Early->VecAp.Coeff = sqrtf(0.5f) * powf(diffusion, 2.0f); + for(i = 0;i < NUM_LINES;i++) { /* Calculate the length (in seconds) of each all-pass line. */ @@ -1179,8 +1183,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte State); /* Update the early lines. */ - UpdateEarlyLines(props->Reverb.Density, props->Reverb.DecayTime, - frequency, &State->Early); + UpdateEarlyLines(props->Reverb.Density, props->Reverb.Diffusion, + props->Reverb.DecayTime, frequency, &State->Early); /* Get the mixing matrix coefficients. */ CalcMatrixCoeffs(props->Reverb.Diffusion, &State->MixX, &State->MixY); -- cgit v1.2.3 From a8250db2bbfbc06b7438cff83ebf382cf43690b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Aug 2018 04:05:07 -0700 Subject: Use the correct input channel for the compressor effect --- Alc/effects/compressor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index a5f1953b..af60777a 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -164,7 +164,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample continue; for(i = 0;i < td;i++) - SamplesOut[k][base+i] += SamplesIn[k][base+i] * gains[i] * gain; + SamplesOut[k][base+i] += SamplesIn[j][base+i] * gains[i] * gain; } } -- cgit v1.2.3 From 1e33c4a922af156ca0cc5efd976c1ecc0cb3e176 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Aug 2018 06:24:12 -0700 Subject: Specify both scale values to FadedDelayLineOut --- Alc/effects/reverb.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index dd8167ef..351fd239 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1249,10 +1249,11 @@ static inline ALfloat DelayLineOut(const DelayLineI *Delay, const ALsizei offset * offsets, this interpolates (cross-fades) the outputs at each offset. */ static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei off0, - const ALsizei off1, const ALsizei c, const ALfloat mu) + const ALsizei off1, const ALsizei c, + const ALfloat sc0, const ALfloat sc1) { - return Delay->Line[off0&Delay->Mask][c]*(1.0f-mu) + - Delay->Line[off1&Delay->Mask][c]*( mu); + return Delay->Line[off0&Delay->Mask][c]*sc0 + + Delay->Line[off1&Delay->Mask][c]*sc1; } @@ -1397,8 +1398,9 @@ static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], { ALfloat input = samples[j][i]; ALfloat out = - FadedDelayLineOut(&delay, vap_offset[j][0]++, vap_offset[j][1]++, j, fade) - - feedCoeff*input; + FadedDelayLineOut(&delay, vap_offset[j][0]++, vap_offset[j][1]++, j, + 1.0f-fade, fade + ) - feedCoeff*input; f[j] = input + feedCoeff*out; samples[j][i] = out; @@ -1513,10 +1515,14 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; ALfloat coeff = State->EarlyDelayCoeff[j]; + ALfloat fader = fade; for(i = 0;i < todo;i++) + { temps[j][i] = FadedDelayLineOut(&main_delay, - early_delay_tap0++, early_delay_tap1++, j, fade + early_delay_tap0++, early_delay_tap1++, j, 1.0f-fader, fader ) * coeff; + fader += FadeStep; + } } VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Early.VecAp); @@ -1539,7 +1545,7 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl for(j = 0;j < NUM_LINES;j++) { f[j] += FadedDelayLineOut(&early_delay, - early_feedb_tap[j][0]++, early_feedb_tap[j][1]++, j, fade + early_feedb_tap[j][0]++, early_feedb_tap[j][1]++, j, 1.0f-fade, fade ) * early_feedb_coeff[j]; out[j][i] = f[j]; } @@ -1665,8 +1671,10 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f for(i = 0;i < todo;i++) { temps[j][i] = - FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, fader) + - FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, fader); + FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, + 1.0f-fader, fader) + + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, + 1.0f-fader, fader); fader += FadeStep; } LateT60Filter(temps[j], todo, &State->Late.T60[j]); -- cgit v1.2.3 From 125ac166d19a17bc767f1193847e0d53f6a73279 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Aug 2018 19:30:58 -0700 Subject: Apply late reverb density gain on late reverb input This also uses gain stepping for changes in density or decay, so that the late reverb tap fades smoothly between delay offsets and density gain levels simultaneously. Now with these changes, it's preferrable to apply density gain adjustments on late reverb input instead of output so that samples currently in the feedback loop won't see a sudden increase or decrease in amplitude. A similar change can probably be made for the early reflection delays to further smooth out delay changes. --- Alc/effects/reverb.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 351fd239..93937799 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -263,6 +263,11 @@ typedef struct LateReverb { DelayLineI Delay; ALsizei Offset[NUM_LINES][2]; + /* Attenuation to compensate for the modal density and decay rate of the + * late lines. + */ + ALfloat DensityGain[2]; + /* T60 decay filters are used to simulate absorption. */ T60Filter T60[NUM_LINES]; @@ -378,6 +383,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.Coeff[i] = 0.0f; } + state->Late.DensityGain[0] = 0.0f; + state->Late.DensityGain[1] = 0.0f; state->Late.Delay.Mask = 0; state->Late.Delay.Line = NULL; state->Late.VecAp.Delay.Mask = 0; @@ -981,7 +988,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, c } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, ALfloat *density_gain, LateReverb *Late) +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, LateReverb *Late) { /* Scaling factor to convert the normalized reference frequencies from * representing 0...freq to 0...max_reference. @@ -1005,16 +1012,14 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co length = lerp(length, echoTime, echoDepth); length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; - /* Attenuation to compensate for the modal density and decay rate of the - * late lines. The density gain calculation uses an average decay time - * weighted by approximate bandwidth. This attempts to compensate for - * losses of energy that reduce decay time due to scattering into highly - * attenuated bands. + /* The density gain calculation uses an average decay time weighted by + * approximate bandwidth. This attempts to compensate for losses of energy + * that reduce decay time due to scattering into highly attenuated bands. */ bandWeights[0] = lf0norm*norm_weight_factor; bandWeights[1] = hf0norm*norm_weight_factor - lf0norm*norm_weight_factor; bandWeights[2] = 1.0f - hf0norm*norm_weight_factor; - *density_gain = CalcDensityGain( + Late->DensityGain[1] = CalcDensityGain( CalcDecayCoeff(length, bandWeights[0]*lfDecayTime + bandWeights[1]*mfDecayTime + bandWeights[2]*hfDecayTime ) @@ -1156,7 +1161,6 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte ALfloat lf0norm, hf0norm, hfRatio; ALfloat lfDecayTime, hfDecayTime; ALfloat gain, gainlf, gainhf; - ALfloat density_gain; ALsizei i; /* Calculate the master filters */ @@ -1207,15 +1211,13 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, - props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, &density_gain, - &State->Late + props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, &State->Late ); /* Update early and late 3D panning. */ gain = props->Reverb.Gain * Slot->Params.Gain * ReverbBoost; Update3DPanning(Device, props->Reverb.ReflectionsPan, props->Reverb.LateReverbPan, - props->Reverb.ReflectionsGain * gain, - props->Reverb.LateReverbGain * gain * density_gain, + props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, State); /* Determine if delay-line cross-fading is required. */ @@ -1226,7 +1228,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte State->Early.Offset[i][1] != State->Early.Offset[i][0] || State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || - State->Late.Offset[i][1] != State->Late.Offset[i][0]) + State->Late.Offset[i][1] != State->Late.Offset[i][0] || + State->Late.DensityGain[1] != State->Late.DensityGain[0]) { State->FadeCount = 0; break; @@ -1607,6 +1610,7 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; + const ALfloat densityGain = State->Late.DensityGain[1]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; @@ -1622,7 +1626,7 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; for(i = 0;i < todo;i++) - temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j) + + temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + DelayLineOut(&late_delay, late_feedb_tap++, j); LateT60Filter(temps[j], todo, &State->Late.T60[j]); } @@ -1654,6 +1658,10 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; + const ALfloat oldDensityGain = State->Late.DensityGain[0]; + const ALfloat densityGain = State->Late.DensityGain[1]; + const ALfloat oldDensityStep = -oldDensityGain / todo; + const ALfloat densityStep = densityGain / todo; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; @@ -1670,15 +1678,21 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f ALfloat fader = fade; for(i = 0;i < todo;i++) { + const ALfloat fade0 = oldDensityGain + oldDensityStep*i; + const ALfloat fade1 = densityStep*i; temps[j][i] = FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, - 1.0f-fader, fader) + + fade0, fade1) + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, 1.0f-fader, fader); fader += FadeStep; } LateT60Filter(temps[j], todo, &State->Late.T60[j]); } + /* Update the old density gain with its now-current level (in case another + * update needs to finish the fade). + */ + State->Late.DensityGain[0] = densityStep*todo; VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); @@ -1768,6 +1782,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } + State->Late.DensityGain[0] = State->Late.DensityGain[1]; } } else -- cgit v1.2.3 From adfbe0d6cd8f1bebf48e2b2833ba0bedb644559a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 8 Aug 2018 22:47:07 -0700 Subject: Crossfade the early reflections delay coefficients --- Alc/effects/reverb.c | 80 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 93937799..c53e67d1 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -251,7 +251,7 @@ typedef struct EarlyReflections { */ DelayLineI Delay; ALsizei Offset[NUM_LINES][2]; - ALfloat Coeff[NUM_LINES]; + ALfloat Coeff[NUM_LINES][2]; /* The gain for each output channel based on 3D panning. */ ALfloat CurrentGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; @@ -299,7 +299,7 @@ typedef struct ALreverbState { /* Tap points for early reflection delay. */ ALsizei EarlyDelayTap[NUM_LINES][2]; - ALfloat EarlyDelayCoeff[NUM_LINES]; + ALfloat EarlyDelayCoeff[NUM_LINES][2]; /* Tap points for late reverb feed and delay. */ ALsizei LateFeedTap; @@ -355,7 +355,8 @@ static void ALreverbState_Construct(ALreverbState *state) { state->EarlyDelayTap[i][0] = 0; state->EarlyDelayTap[i][1] = 0; - state->EarlyDelayCoeff[i] = 0.0f; + state->EarlyDelayCoeff[i][0] = 0.0f; + state->EarlyDelayCoeff[i][1] = 0.0f; } state->LateFeedTap = 0; @@ -380,7 +381,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Early.VecAp.Offset[i][1] = 0; state->Early.Offset[i][0] = 0; state->Early.Offset[i][1] = 0; - state->Early.Coeff[i] = 0.0f; + state->Early.Coeff[i][0] = 0.0f; + state->Early.Coeff[i][1] = 0.0f; } state->Late.DensityGain[0] = 0.0f; @@ -950,7 +952,7 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, State->EarlyDelayTap[i][1] = float2int(length * frequency); length = EARLY_TAP_LENGTHS[i]*multiplier; - State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime); + State->EarlyDelayCoeff[i][1] = CalcDecayCoeff(length, decayTime); length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier; State->LateDelayTap[i][1] = State->LateFeedTap + float2int(length * frequency); @@ -983,7 +985,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, c Early->Offset[i][1] = float2int(length * frequency); /* Calculate the gain (coefficient) for each line. */ - Early->Coeff[i] = CalcDecayCoeff(length, decayTime); + Early->Coeff[i][1] = CalcDecayCoeff(length, decayTime); } } @@ -1220,16 +1222,24 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, State); - /* Determine if delay-line cross-fading is required. */ - for(i = 0;i < NUM_LINES;i++) + /* Determine if delay-line cross-fading is required. TODO: Add some fuzz + * for the float comparisons? The math should be stable enough that the + * result should be the same if nothing's changed, and changes in the float + * values should (though may not always) be matched by changes in delay + * offsets. + */ + if(State->Late.DensityGain[1] != State->Late.DensityGain[0]) + State->FadeCount = 0; + else for(i = 0;i < NUM_LINES;i++) { if(State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0] || + State->EarlyDelayCoeff[i][1] != State->EarlyDelayCoeff[i][0] || State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0] || State->Early.Offset[i][1] != State->Early.Offset[i][0] || + State->Early.Coeff[i][1] != State->Early.Coeff[i][0] || State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || - State->Late.Offset[i][1] != State->Late.Offset[i][0] || - State->Late.DensityGain[1] != State->Late.DensityGain[0]) + State->Late.Offset[i][1] != State->Late.Offset[i][0]) { State->FadeCount = 0; break; @@ -1456,7 +1466,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, for(j = 0;j < NUM_LINES;j++) { ALsizei early_delay_tap = offset - State->EarlyDelayTap[j][0]; - ALfloat coeff = State->EarlyDelayCoeff[j]; + ALfloat coeff = State->EarlyDelayCoeff[j][0]; for(i = 0;i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, early_delay_tap++, j) * coeff; } @@ -1469,7 +1479,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, for(j = 0;j < NUM_LINES;j++) { early_feedb_tap[j] = offset - State->Early.Offset[j][0]; - early_feedb_coeff[j] = State->Early.Coeff[j]; + early_feedb_coeff[j] = State->Early.Coeff[j][0]; } late_feed_tap = offset - State->LateFeedTap; for(i = 0;i < todo;i++) @@ -1503,8 +1513,10 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; const DelayLineI main_delay = State->Delay; - ALsizei early_feedb_tap[NUM_LINES][2]; - ALfloat early_feedb_coeff[NUM_LINES]; + ALsizei feedb_tap[NUM_LINES][2]; + ALfloat feedb_oldCoeff[NUM_LINES]; + ALfloat feedb_oldCoeffStep[NUM_LINES]; + ALfloat feedb_newCoeffStep[NUM_LINES]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; @@ -1517,14 +1529,16 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl { ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; - ALfloat coeff = State->EarlyDelayCoeff[j]; - ALfloat fader = fade; + ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; + ALfloat oldCoeffStep = -oldCoeff / todo; + ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / todo; for(i = 0;i < todo;i++) { + const ALfloat fade0 = oldCoeff + oldCoeffStep*i; + const ALfloat fade1 = newCoeffStep*i; temps[j][i] = FadedDelayLineOut(&main_delay, - early_delay_tap0++, early_delay_tap1++, j, 1.0f-fader, fader - ) * coeff; - fader += FadeStep; + early_delay_tap0++, early_delay_tap1++, j, fade0, fade1 + ); } } @@ -1532,9 +1546,11 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl for(j = 0;j < NUM_LINES;j++) { - early_feedb_tap[j][0] = offset - State->Early.Offset[j][0]; - early_feedb_tap[j][1] = offset - State->Early.Offset[j][1]; - early_feedb_coeff[j] = State->Early.Coeff[j]; + feedb_tap[j][0] = offset - State->Early.Offset[j][0]; + feedb_tap[j][1] = offset - State->Early.Offset[j][1]; + feedb_oldCoeff[j] = State->Early.Coeff[j][0]; + feedb_oldCoeffStep[j] = -feedb_oldCoeff[j] / todo; + feedb_newCoeffStep[j] = State->Early.Coeff[j][1] / todo; } late_feed_tap = offset - State->LateFeedTap; for(i = 0;i < todo;i++) @@ -1547,9 +1563,11 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl DelayLineIn4Rev(&early_delay, offset, f); for(j = 0;j < NUM_LINES;j++) { + const ALfloat fade0 = feedb_oldCoeff[j] + feedb_oldCoeffStep[j]*i; + const ALfloat fade1 = feedb_newCoeffStep[j]*i; f[j] += FadedDelayLineOut(&early_delay, - early_feedb_tap[j][0]++, early_feedb_tap[j][1]++, j, 1.0f-fade, fade - ) * early_feedb_coeff[j]; + feedb_tap[j][0]++, feedb_tap[j][1]++, j, fade0, fade1 + ); out[j][i] = f[j]; } fade += FadeStep; @@ -1610,7 +1628,7 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; - const ALfloat densityGain = State->Late.DensityGain[1]; + const ALfloat densityGain = State->Late.DensityGain[0]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; @@ -1689,10 +1707,6 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f } LateT60Filter(temps[j], todo, &State->Late.T60[j]); } - /* Update the old density gain with its now-current level (in case another - * update needs to finish the fade). - */ - State->Late.DensityGain[0] = densityStep*todo; VectorAllpass_Faded(temps, offset, mixX, mixY, fade, todo, &State->Late.VecAp); @@ -1765,6 +1779,13 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c SamplesToDo-base, base, todo ); + for(c = 0;c < NUM_LINES;c++) + { + State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; + State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; + } + State->Late.DensityGain[0] = State->Late.DensityGain[1]; + /* Step fading forward. */ fade += todo*FadeStep; fadeCount += todo; @@ -1782,7 +1803,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } - State->Late.DensityGain[0] = State->Late.DensityGain[1]; } } else -- cgit v1.2.3 From 2b9c213f89445e56f393c0a3313883d497cd59d1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 9 Aug 2018 21:10:17 -0700 Subject: Correctly apply reverb coefficient fading over the entire fade length --- Alc/effects/reverb.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c53e67d1..ba2707d5 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1521,6 +1521,7 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; ALsizei late_feed_tap; + ALfloat fadeCount; ALsizei i, j; ASSUME(todo > 0); @@ -1530,15 +1531,18 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl ALsizei early_delay_tap0 = offset - State->EarlyDelayTap[j][0]; ALsizei early_delay_tap1 = offset - State->EarlyDelayTap[j][1]; ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; - ALfloat oldCoeffStep = -oldCoeff / todo; - ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / todo; + ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; + ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / FADE_SAMPLES; + + fadeCount = fade * FADE_SAMPLES; for(i = 0;i < todo;i++) { - const ALfloat fade0 = oldCoeff + oldCoeffStep*i; - const ALfloat fade1 = newCoeffStep*i; + const ALfloat fade0 = oldCoeff + oldCoeffStep*fadeCount; + const ALfloat fade1 = newCoeffStep*fadeCount; temps[j][i] = FadedDelayLineOut(&main_delay, early_delay_tap0++, early_delay_tap1++, j, fade0, fade1 ); + fadeCount += 1.0f; } } @@ -1549,10 +1553,11 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl feedb_tap[j][0] = offset - State->Early.Offset[j][0]; feedb_tap[j][1] = offset - State->Early.Offset[j][1]; feedb_oldCoeff[j] = State->Early.Coeff[j][0]; - feedb_oldCoeffStep[j] = -feedb_oldCoeff[j] / todo; - feedb_newCoeffStep[j] = State->Early.Coeff[j][1] / todo; + feedb_oldCoeffStep[j] = -feedb_oldCoeff[j] / FADE_SAMPLES; + feedb_newCoeffStep[j] = State->Early.Coeff[j][1] / FADE_SAMPLES; } late_feed_tap = offset - State->LateFeedTap; + fadeCount = fade * FADE_SAMPLES; for(i = 0;i < todo;i++) { ALfloat f[NUM_LINES]; @@ -1563,14 +1568,14 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl DelayLineIn4Rev(&early_delay, offset, f); for(j = 0;j < NUM_LINES;j++) { - const ALfloat fade0 = feedb_oldCoeff[j] + feedb_oldCoeffStep[j]*i; - const ALfloat fade1 = feedb_newCoeffStep[j]*i; + const ALfloat fade0 = feedb_oldCoeff[j] + feedb_oldCoeffStep[j]*fadeCount; + const ALfloat fade1 = feedb_newCoeffStep[j]*fadeCount; f[j] += FadedDelayLineOut(&early_delay, feedb_tap[j][0]++, feedb_tap[j][1]++, j, fade0, fade1 ); out[j][i] = f[j]; } - fade += FadeStep; + fadeCount += 1.0f; VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); offset++; @@ -1678,8 +1683,8 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f const DelayLineI main_delay = State->Delay; const ALfloat oldDensityGain = State->Late.DensityGain[0]; const ALfloat densityGain = State->Late.DensityGain[1]; - const ALfloat oldDensityStep = -oldDensityGain / todo; - const ALfloat densityStep = densityGain / todo; + const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; + const ALfloat densityStep = densityGain / FADE_SAMPLES; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei offset = State->Offset; @@ -1693,17 +1698,19 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; + ALfloat fadeCount = fade * FADE_SAMPLES; ALfloat fader = fade; for(i = 0;i < todo;i++) { - const ALfloat fade0 = oldDensityGain + oldDensityStep*i; - const ALfloat fade1 = densityStep*i; + const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; + const ALfloat fade1 = densityStep*fadeCount; temps[j][i] = FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, fade0, fade1) + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, 1.0f-fader, fader); fader += FadeStep; + fadeCount += 1.0f; } LateT60Filter(temps[j], todo, &State->Late.T60[j]); } @@ -1729,7 +1736,6 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; ALsizei fadeCount = State->FadeCount; - ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; ALsizei base, c; /* Process reverb for these samples. */ @@ -1760,6 +1766,8 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c if(UNLIKELY(fadeCount < FADE_SAMPLES)) { + ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; + /* Generate early reflections. */ EarlyReflection_Faded(State, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back @@ -1779,30 +1787,24 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c SamplesToDo-base, base, todo ); - for(c = 0;c < NUM_LINES;c++) - { - State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; - State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; - } - State->Late.DensityGain[0] = State->Late.DensityGain[1]; - /* Step fading forward. */ - fade += todo*FadeStep; fadeCount += todo; if(LIKELY(fadeCount >= FADE_SAMPLES)) { /* Update the cross-fading delay line taps. */ fadeCount = FADE_SAMPLES; - fade = 1.0f; for(c = 0;c < NUM_LINES;c++) { State->EarlyDelayTap[c][0] = State->EarlyDelayTap[c][1]; + State->EarlyDelayCoeff[c][0] = State->EarlyDelayCoeff[c][1]; State->Early.VecAp.Offset[c][0] = State->Early.VecAp.Offset[c][1]; State->Early.Offset[c][0] = State->Early.Offset[c][1]; + State->Early.Coeff[c][0] = State->Early.Coeff[c][1]; State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; } + State->Late.DensityGain[0] = State->Late.DensityGain[1]; } } else -- cgit v1.2.3 From 90ca9b9ff4fda3e2dd998e437f18db4a5edb2a6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 9 Aug 2018 21:24:24 -0700 Subject: Store the reverb state offset locally while processing --- Alc/effects/reverb.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ba2707d5..9fb74b76 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1444,7 +1444,7 @@ static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, +static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1454,7 +1454,6 @@ static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, ALfloat early_feedb_coeff[NUM_LINES]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; - ALsizei offset = State->Offset; ALsizei late_feed_tap; ALsizei i, j; @@ -1507,8 +1506,8 @@ static void EarlyReflection_Unfaded(ALreverbState *State, const ALsizei todo, offset++; } } -static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, + const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; @@ -1519,7 +1518,6 @@ static void EarlyReflection_Faded(ALreverbState *State, const ALsizei todo, ALfl ALfloat feedb_newCoeffStep[NUM_LINES]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; - ALsizei offset = State->Offset; ALsizei late_feed_tap; ALfloat fadeCount; ALsizei i, j; @@ -1627,7 +1625,7 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, +static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1636,7 +1634,6 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, const ALfloat densityGain = State->Late.DensityGain[0]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; - ALsizei offset = State->Offset; ALsizei i, j; ASSUME(todo > 0); @@ -1675,8 +1672,8 @@ static void LateReverb_Unfaded(ALreverbState *State, const ALsizei todo, offset++; } } -static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat fade, - ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) +static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, + const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; @@ -1687,7 +1684,6 @@ static void LateReverb_Faded(ALreverbState *State, const ALsizei todo, ALfloat f const ALfloat densityStep = densityGain / FADE_SAMPLES; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; - ALsizei offset = State->Offset; ALsizei i, j; ASSUME(todo > 0); @@ -1736,6 +1732,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; ALsizei fadeCount = State->FadeCount; + ALsizei offset = State->Offset; ALsizei base, c; /* Process reverb for these samples. */ @@ -1761,7 +1758,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c BiquadFilter_process(&State->Filter[c].Hp, samples[1], samples[0], todo); /* Feed the initial delay line. */ - DelayLineIn(&State->Delay, State->Offset, c, samples[1], todo); + DelayLineIn(&State->Delay, offset, c, samples[1], todo); } if(UNLIKELY(fadeCount < FADE_SAMPLES)) @@ -1769,7 +1766,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; /* Generate early reflections. */ - EarlyReflection_Faded(State, todo, fade, samples); + EarlyReflection_Faded(State, offset, todo, fade, samples); /* Mix the A-Format results to output, implicitly converting back * to B-Format. */ @@ -1780,7 +1777,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ); /* Generate and mix late reverb. */ - LateReverb_Faded(State, todo, fade, samples); + LateReverb_Faded(State, offset, todo, fade, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], @@ -1810,7 +1807,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c else { /* Generate and mix early reflections. */ - EarlyReflection_Unfaded(State, todo, samples); + EarlyReflection_Unfaded(State, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Early.CurrentGain[c], State->Early.PanGain[c], @@ -1818,7 +1815,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c ); /* Generate and mix late reverb. */ - LateReverb_Unfaded(State, todo, samples); + LateReverb_Unfaded(State, offset, todo, samples); for(c = 0;c < NUM_LINES;c++) MixSamples(samples[c], NumChannels, SamplesOut, State->Late.CurrentGain[c], State->Late.PanGain[c], @@ -1827,10 +1824,11 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c } /* Step all delays forward. */ - State->Offset += todo; + offset += todo; base += todo; } + State->Offset = offset; State->FadeCount = fadeCount; } -- cgit v1.2.3 From 7d76cbddd6fbdb52eaa917845435b95ae89efced Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 Aug 2018 18:02:39 -0700 Subject: Use second-order biquad filters for the reverb's T60 decay --- Alc/effects/reverb.c | 327 +++------------------------------------------------ 1 file changed, 18 insertions(+), 309 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9fb74b76..9b507b3d 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -232,12 +232,7 @@ typedef struct T60Filter { * frequencies, and one to control the high frequencies. The HF filter also * adjusts the overall output gain, affecting the remaining mid-band. */ - ALfloat HFCoeffs[3]; - ALfloat LFCoeffs[3]; - - /* The HF and LF filters each keep a delay component. */ - ALfloat HFState; - ALfloat LFState; + BiquadFilter HFFilter, LFFilter; } T60Filter; typedef struct EarlyReflections { @@ -400,13 +395,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.VecAp.Offset[i][0] = 0; state->Late.VecAp.Offset[i][1] = 0; - for(j = 0;j < 3;j++) - { - state->Late.T60[i].HFCoeffs[j] = 0.0f; - state->Late.T60[i].LFCoeffs[j] = 0.0f; - } - state->Late.T60[i].HFState = 0.0f; - state->Late.T60[i].LFState = 0.0f; + BiquadFilter_clear(&state->Late.T60[i].HFFilter); + BiquadFilter_clear(&state->Late.T60[i].LFFilter); } for(i = 0;i < NUM_LINES;i++) @@ -648,284 +638,27 @@ static ALfloat CalcLimitedHfRatio(const ALfloat hfRatio, const ALfloat airAbsorp return minf(limitRatio, hfRatio); } -/* Calculates the first-order high-pass coefficients following the I3DL2 - * reference model. This is the transfer function: - * - * 1 - z^-1 - * H(z) = p ------------ - * 1 - p z^-1 - * - * And this is the I3DL2 coefficient calculation given gain (g) and reference - * angular frequency (w): - * - * g - * p = ------------------------------------------------------ - * g cos(w) + sqrt((cos(w) - 1) (g^2 cos(w) + g^2 - 2)) - * - * The coefficient is applied to the partial differential filter equation as: - * - * c_0 = p - * c_1 = -p - * c_2 = p - * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) - * - */ -static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) -{ - ALfloat g, g2, cw, p; - - if(gain >= 1.0f) - { - coeffs[0] = 1.0f; - coeffs[1] = 0.0f; - coeffs[2] = 0.0f; - return; - } - - g = maxf(0.001f, gain); - g2 = g * g; - cw = cosf(w); - p = g / (g*cw + sqrtf((cw - 1.0f) * (g2*cw + g2 - 2.0f))); - - coeffs[0] = p; - coeffs[1] = -p; - coeffs[2] = p; -} - -/* Calculates the first-order low-pass coefficients following the I3DL2 - * reference model. This is the transfer function: - * - * (1 - a) z^0 - * H(z) = ---------------- - * 1 z^0 - a z^-1 - * - * And this is the I3DL2 coefficient calculation given gain (g) and reference - * angular frequency (w): - * - * 1 - g^2 cos(w) - sqrt(2 g^2 (1 - cos(w)) - g^4 (1 - cos(w)^2)) - * a = ---------------------------------------------------------------- - * 1 - g^2 - * - * The coefficient is applied to the partial differential filter equation as: - * - * c_0 = 1 - a - * c_1 = 0 - * c_2 = a - * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) - * - */ -static inline void CalcLowpassCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) -{ - ALfloat g, g2, cw, a; - - if(gain >= 1.0f) - { - coeffs[0] = 1.0f; - coeffs[1] = 0.0f; - coeffs[2] = 0.0f; - return; - } - - /* Be careful with gains < 0.001, as that causes the coefficient - * to head towards 1, which will flatten the signal. */ - g = maxf(0.001f, gain); - g2 = g * g; - cw = cosf(w); - a = (1.0f - g2*cw - sqrtf((2.0f*g2*(1.0f - cw)) - g2*g2*(1.0f - cw*cw))) / - (1.0f - g2); - - coeffs[0] = 1.0f - a; - coeffs[1] = 0.0f; - coeffs[2] = a; -} - -/* Calculates the first-order low-shelf coefficients. The shelf filters are - * used in place of low/high-pass filters to preserve the mid-band. This is - * the transfer function: - * - * a_0 + a_1 z^-1 - * H(z) = ---------------- - * 1 + b_1 z^-1 - * - * And these are the coefficient calculations given cut gain (g) and a center - * angular frequency (w): - * - * sin(0.5 (pi - w) - 0.25 pi) - * p = ----------------------------- - * sin(0.5 (pi - w) + 0.25 pi) - * - * g + 1 g + 1 - * a = ------- + sqrt((-------)^2 - 1) - * g - 1 g - 1 - * - * 1 + g + (1 - g) a - * b_0 = ------------------- - * 2 - * - * 1 - g + (1 + g) a - * b_1 = ------------------- - * 2 - * - * The coefficients are applied to the partial differential filter equation - * as: - * - * b_0 + p b_1 - * c_0 = ------------- - * 1 + p a - * - * -(b_1 + p b_0) - * c_1 = ---------------- - * 1 + p a - * - * p + a - * c_2 = --------- - * 1 + p a - * - * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) - * - */ -static inline void CalcLowShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) -{ - ALfloat g, rw, p, n; - ALfloat alpha, beta0, beta1; - - if(gain >= 1.0f) - { - coeffs[0] = 1.0f; - coeffs[1] = 0.0f; - coeffs[2] = 0.0f; - return; - } - - g = maxf(0.001f, gain); - rw = F_PI - w; - p = sinf(0.5f*rw - 0.25f*F_PI) / sinf(0.5f*rw + 0.25f*F_PI); - n = (g + 1.0f) / (g - 1.0f); - alpha = n + sqrtf(n*n - 1.0f); - beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f; - beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f; - - coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha); - coeffs[1] = -(beta1 + p*beta0) / (1.0f + p*alpha); - coeffs[2] = (p + alpha) / (1.0f + p*alpha); -} - -/* Calculates the first-order high-shelf coefficients. The shelf filters are - * used in place of low/high-pass filters to preserve the mid-band. This is - * the transfer function: - * - * a_0 + a_1 z^-1 - * H(z) = ---------------- - * 1 + b_1 z^-1 - * - * And these are the coefficient calculations given cut gain (g) and a center - * angular frequency (w): - * - * sin(0.5 w - 0.25 pi) - * p = ---------------------- - * sin(0.5 w + 0.25 pi) - * - * g + 1 g + 1 - * a = ------- + sqrt((-------)^2 - 1) - * g - 1 g - 1 - * - * 1 + g + (1 - g) a - * b_0 = ------------------- - * 2 - * - * 1 - g + (1 + g) a - * b_1 = ------------------- - * 2 - * - * The coefficients are applied to the partial differential filter equation - * as: - * - * b_0 + p b_1 - * c_0 = ------------- - * 1 + p a - * - * b_1 + p b_0 - * c_1 = ------------- - * 1 + p a - * - * -(p + a) - * c_2 = ---------- - * 1 + p a - * - * y_i = c_0 x_i + c_1 x_(i-1) + c_2 y_(i-1) - * - */ -static inline void CalcHighShelfCoeffs(const ALfloat gain, const ALfloat w, ALfloat coeffs[3]) -{ - ALfloat g, p, n; - ALfloat alpha, beta0, beta1; - - if(gain >= 1.0f) - { - coeffs[0] = 1.0f; - coeffs[1] = 0.0f; - coeffs[2] = 0.0f; - return; - } - - g = maxf(0.001f, gain); - p = sinf(0.5f*w - 0.25f*F_PI) / sinf(0.5f*w + 0.25f*F_PI); - n = (g + 1.0f) / (g - 1.0f); - alpha = n + sqrtf(n*n - 1.0f); - beta0 = (1.0f + g + (1.0f - g)*alpha) / 2.0f; - beta1 = (1.0f - g + (1.0f + g)*alpha) / 2.0f; - - coeffs[0] = (beta0 + p*beta1) / (1.0f + p*alpha); - coeffs[1] = (beta1 + p*beta0) / (1.0f + p*alpha); - coeffs[2] = -(p + alpha) / (1.0f + p*alpha); -} /* Calculates the 3-band T60 damping coefficients for a particular delay line - * of specified length using a combination of two low/high-pass/shelf or - * pass-through filter sections (producing 3 coefficients each) given decay - * times for each band split at two (LF/HF) reference frequencies (w). + * of specified length, using a combination of two shelf filter sections given + * decay times for each band split at two reference frequencies. */ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, - const ALfloat lfW, const ALfloat hfW, ALfloat lfcoeffs[3], - ALfloat hfcoeffs[3]) + const ALfloat lf0norm, const ALfloat hf0norm, + T60Filter *filter) { ALfloat lfGain = CalcDecayCoeff(length, lfDecayTime); ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); - if(lfGain <= mfGain) - { - CalcHighpassCoeffs(lfGain / mfGain, lfW, lfcoeffs); - if(mfGain >= hfGain) - { - CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - hfcoeffs[0] *= mfGain; hfcoeffs[1] *= mfGain; - } - else - { - CalcLowShelfCoeffs(mfGain / hfGain, hfW, hfcoeffs); - hfcoeffs[0] *= hfGain; hfcoeffs[1] *= hfGain; - } - } - else - { - CalcHighShelfCoeffs(mfGain / lfGain, lfW, lfcoeffs); - if(mfGain >= hfGain) - { - CalcLowpassCoeffs(hfGain / mfGain, hfW, hfcoeffs); - hfcoeffs[0] *= lfGain; hfcoeffs[1] *= lfGain; - } - else - { - ALfloat hg = mfGain / lfGain; - ALfloat lg = mfGain / hfGain; - ALfloat mg = maxf(lfGain, hfGain) / maxf(hg, lg); - - CalcLowShelfCoeffs(lg, hfW, hfcoeffs); - hfcoeffs[0] *= mg; hfcoeffs[1] *= mg; - } - } + BiquadFilter_setParams(&filter->LFFilter, BiquadType_LowShelf, lfGain/mfGain, lf0norm, + calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); + BiquadFilter_setParams(&filter->HFFilter, BiquadType_HighShelf, hfGain/mfGain, hf0norm, + calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); + filter->HFFilter.b0 *= mfGain; + filter->HFFilter.b1 *= mfGain; + filter->HFFilter.b2 *= mfGain; } /* Update the offsets for the main effect delay line. */ @@ -1064,8 +797,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the T60 damping coefficients for each line. */ CalcT60DampingCoeffs(length, lfDecayTime, mfDecayTime, hfDecayTime, - lf0norm*F_TAU, hf0norm*F_TAU, Late->T60[i].LFCoeffs, - Late->T60[i].HFCoeffs); + lf0norm, hf0norm, &Late->T60[i]); } } @@ -1583,32 +1315,9 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL /* Applies the two T60 damping filter sections. */ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, T60Filter *filter) { - const ALfloat hfb0 = filter->HFCoeffs[0]; - const ALfloat hfb1 = filter->HFCoeffs[1]; - const ALfloat hfa1 = filter->HFCoeffs[2]; - const ALfloat lfb0 = filter->LFCoeffs[0]; - const ALfloat lfb1 = filter->LFCoeffs[1]; - const ALfloat lfa1 = filter->LFCoeffs[2]; - ALfloat hfz = filter->HFState; - ALfloat lfz = filter->LFState; - ALsizei i; - - ASSUME(todo > 0); - - for(i = 0;i < todo;i++) - { - ALfloat in = samples[i]; - ALfloat out = in*hfb0 + hfz; - hfz = in*hfb1 + out*hfa1; - - in = out; - out = in*lfb0 + lfz; - lfz = in*lfb1 + out*lfa1; - - samples[i] = out; - } - filter->HFState = hfz; - filter->LFState = lfz; + ALfloat temp[MAX_UPDATE_SAMPLES]; + BiquadFilter_process(&filter->HFFilter, temp, samples, todo); + BiquadFilter_process(&filter->LFFilter, samples, temp, todo); } /* This generates the reverb tail using a modified feed-back delay network -- cgit v1.2.3 From 24b646dec0ea08434bc30b73389cbc01efb59596 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 23 Aug 2018 18:20:09 -0700 Subject: Append the OpenSL capture device to the appropriate list --- Alc/backends/opensl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index a5ad3b09..262fdaef 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -1039,7 +1039,7 @@ static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), break; case CAPTURE_DEVICE_PROBE: - AppendAllDevicesList(opensl_device); + AppendCaptureDeviceList(opensl_device); break; } } -- cgit v1.2.3 From 4be6584850e8e8d9958d00d5aa8dc548743671d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Aug 2018 19:04:49 -0700 Subject: Further limit the upper frequency range for autowah --- Alc/effects/autowah.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 5f45c43a..d7cb662a 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -153,7 +153,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, env_delay = lerp(sample, env_delay, a); /* Calculate the cos and alpha components for this sample's filter. */ - w0 = minf((bandwidth*env_delay + freq_min), 0.49f) * F_TAU; + w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; state->CosW0[i] = cosf(w0); state->Alpha[i] = sinf(w0)/(2.0f * Q_FACTOR); } -- cgit v1.2.3 From a3010f50be7396a96e6872600b4a3c2a3b79a107 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Aug 2018 19:08:50 -0700 Subject: Pack two arrays into one --- Alc/effects/autowah.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index d7cb662a..5a222bfd 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -46,8 +46,10 @@ typedef struct ALautowahState { ALfloat env_delay; /* Filter components derived from the envelope. */ - ALfloat Alpha[BUFFERSIZE]; - ALfloat CosW0[BUFFERSIZE]; + struct { + ALfloat cos_w0; + ALfloat alpha; + } Env[BUFFERSIZE]; struct { /* Effect filters' history. */ @@ -96,6 +98,8 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *U state->BandwidthNorm = 0.05f; state->env_delay = 0.0f; + memset(state->Env, 0, sizeof(state->Env)); + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) { for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) @@ -154,8 +158,8 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, /* Calculate the cos and alpha components for this sample's filter. */ w0 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU; - state->CosW0[i] = cosf(w0); - state->Alpha[i] = sinf(w0)/(2.0f * Q_FACTOR); + state->Env[i].cos_w0 = cosf(w0); + state->Env[i].alpha = sinf(w0)/(2.0f * Q_FACTOR); } state->env_delay = env_delay; @@ -173,8 +177,8 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, for(i = 0;i < SamplesToDo;i++) { - const ALfloat alpha = state->Alpha[i]; - const ALfloat cos_w0 = state->CosW0[i]; + const ALfloat alpha = state->Env[i].alpha; + const ALfloat cos_w0 = state->Env[i].cos_w0; ALfloat input, output; ALfloat a[3], b[3]; -- cgit v1.2.3 From 072ca731e2dffcbdbd8f7e8f2dad2ea699ef1b83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Aug 2018 19:14:17 -0700 Subject: Avoid making extraneous calls --- Alc/effects/autowah.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 5a222bfd..28b366b1 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -122,7 +122,7 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con state->AttackRate = expf(-1.0f / (props->Autowah.AttackTime*device->Frequency)); state->ReleaseRate = expf(-1.0f / (ReleaseTime*device->Frequency)); /* 0-20dB Resonance Peak gain */ - state->ResonanceGain = log10f(props->Autowah.Resonance)*10.0f / 3.0f; + state->ResonanceGain = sqrtf(log10f(props->Autowah.Resonance)*10.0f / 3.0f); state->PeakGain = 1.0f - log10f(props->Autowah.PeakGain/AL_AUTOWAH_MAX_PEAK_GAIN); state->FreqMinNorm = MIN_FREQ / device->Frequency; state->BandwidthNorm = (MAX_FREQ-MIN_FREQ) / device->Frequency; @@ -136,9 +136,10 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { - const ALfloat peak_gain = state->PeakGain; const ALfloat attack_rate = state->AttackRate; const ALfloat release_rate = state->ReleaseRate; + const ALfloat res_gain = state->ResonanceGain; + const ALfloat peak_gain = state->PeakGain; const ALfloat freq_min = state->FreqMinNorm; const ALfloat bandwidth = state->BandwidthNorm; ALfloat env_delay; @@ -171,7 +172,6 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, * envelope. Because the filter changes for each sample, the * coefficients are transient and don't need to be held. */ - const ALfloat res_gain = sqrtf(state->ResonanceGain); ALfloat z1 = state->Chans[c].Filter.z1; ALfloat z2 = state->Chans[c].Filter.z2; -- cgit v1.2.3 From dacd08dc5dc90369d7d38ff712475bd79fcb0023 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 26 Aug 2018 22:36:30 -0700 Subject: Use shuffle+cvt to extract SIMD values instead of storing to memory --- Alc/mixer/mixer_sse2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index 4aeb6fc4..e0198022 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -49,7 +49,7 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), for(i = 0;numsamples-i > 3;i += 4) { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); + const __m128 val1 = _mm_setr_ps(src[pos_.i[0] ], src[pos_.i[1] ], src[pos_.i[2] ], src[pos_.i[3] ]); const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); /* val1 + (val2-val1)*mu */ @@ -63,7 +63,10 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); frac4 = _mm_and_si128(frac4, fracMask4); - _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4)); + pos_.i[0] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); + pos_.i[1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); + pos_.i[2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2))); + pos_.i[3] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3))); } /* NOTE: These four elements represent the position *after* the last four -- cgit v1.2.3 From 529f387695d10368aca3460baa428ee90eea8332 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 Aug 2018 01:45:27 -0700 Subject: Use a separate method to warp the azimuth for plain stereo output --- Alc/ALu.c | 27 ++++++++++++++------------- Alc/panning.c | 9 +-------- OpenAL32/Include/alu.h | 16 ++++++++++------ 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index dc24755d..d033c0c4 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -648,10 +648,12 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo voice->Flags |= VOICE_HAS_NFC; } - if(Device->Render_Mode == StereoPair) - CalcAnglePairwiseCoeffs(Azi, Elev, Spread, coeffs); - else - CalcAngleCoeffs(Azi, Elev, Spread, coeffs); + /* A scalar of 3 for plain stereo results in +/-30 degrees being + * moved to +/-90 degrees for direct right and left speaker + * responses. + */ + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 3.0f) : Azi, + Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ ComputeDryPanGains(&Device->Dry, coeffs, DryGain*1.414213562f, @@ -895,10 +897,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo /* Calculate the directional coefficients once, which apply to all * input channels. */ - if(Device->Render_Mode == StereoPair) - CalcAnglePairwiseCoeffs(Azi, Elev, Spread, coeffs); - else - CalcAngleCoeffs(Azi, Elev, Spread, coeffs); + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 3.0f) : Azi, + Elev, Spread, coeffs); for(c = 0;c < num_channels;c++) { @@ -970,14 +970,15 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo continue; } - if(Device->Render_Mode == StereoPair) - CalcAnglePairwiseCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); - else - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, Spread, coeffs); + CalcAngleCoeffs( + (Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(chans[c].angle, 3.0f) + : chans[c].angle, + chans[c].elevation, Spread, coeffs + ); + ComputeDryPanGains(&Device->Dry, coeffs, DryGain, voice->Direct.Params[c].Gains.Target ); - for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; diff --git a/Alc/panning.c b/Alc/panning.c index 51d65a24..d114295b 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -40,6 +40,7 @@ extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +extern inline float ScaleAzimuthFront(float azimuth, float scale); extern inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); extern inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); @@ -150,14 +151,6 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf } } -void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]) -{ - ALfloat sign = (azimuth < 0.0f) ? -1.0f : 1.0f; - if(!(fabsf(azimuth) > F_PI_2)) - azimuth = minf(fabsf(azimuth) * F_PI_2 / (F_PI/6.0f), F_PI_2) * sign; - CalcAngleCoeffs(azimuth, elevation, spread, coeffs); -} - void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c09caa65..ed318ada 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -477,14 +477,18 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, } /** - * CalcAnglePairwiseCoeffs + * ScaleAzimuthFront * - * Calculates ambisonic coefficients based on azimuth and elevation. The - * azimuth and elevation parameters are in radians, going right and up - * respectively. This pairwise variant warps the result such that +30 azimuth - * is full right, and -30 azimuth is full left. + * Scales the given azimuth toward the side (+/- pi/2 radians) for positions in + * front. */ -void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); +inline float ScaleAzimuthFront(float azimuth, float scale) +{ + ALfloat sign = (azimuth < 0.0f) ? -1.0f : 1.0f; + if(!(fabsf(azimuth) > F_PI_2)) + return minf(fabsf(azimuth) * scale, F_PI_2) * sign; + return azimuth; +} void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -- cgit v1.2.3 From 21dc2c761d87592feb8b42a4556e2786f2e4581f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 Aug 2018 03:51:17 -0700 Subject: Check for and use copysignf --- CMakeLists.txt | 1 + OpenAL32/Include/alu.h | 2 +- common/math_defs.h | 13 +++++++++++++ config.h.in | 3 +++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7d13777..16daa8d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -536,6 +536,7 @@ CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F) CHECK_SYMBOL_EXISTS(cbrtf math.h HAVE_CBRTF) +CHECK_SYMBOL_EXISTS(copysignf math.h HAVE_COPYSIGNF) IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index ed318ada..c3e6ba12 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -484,7 +484,7 @@ inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, */ inline float ScaleAzimuthFront(float azimuth, float scale) { - ALfloat sign = (azimuth < 0.0f) ? -1.0f : 1.0f; + ALfloat sign = copysignf(1.0f, azimuth); if(!(fabsf(azimuth) > F_PI_2)) return minf(fabsf(azimuth) * scale, F_PI_2) * sign; return azimuth; diff --git a/common/math_defs.h b/common/math_defs.h index 04d73f42..99cc62ec 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -40,6 +40,19 @@ static inline float cbrtf(float f) } #endif +#ifndef HAVE_COPYSIGNF +static inline float copysignf(float x, float y) +{ + union { + float f; + unsigned int u; + } ux = { x }, uy = { y }; + ux.u &= 0x7fffffffu; + ux.u |= (uy.u&0x80000000u); + return ux.f; +} +#endif + #define DEG2RAD(x) ((float)(x) * (float)(M_PI/180.0)) #define RAD2DEG(x) ((float)(x) * (float)(180.0/M_PI)) diff --git a/config.h.in b/config.h.in index 1ff64fe4..9cc6c16b 100644 --- a/config.h.in +++ b/config.h.in @@ -98,6 +98,9 @@ /* Define if we have the cbrtf function */ #cmakedefine HAVE_CBRTF +/* Define if we have the copysignf function */ +#cmakedefine HAVE_COPYSIGNF + /* Define if we have the strtof function */ #cmakedefine HAVE_STRTOF -- cgit v1.2.3 From 827c66f4f6f1b84082e2ce77ab0dc82221e6adc7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 Aug 2018 07:13:54 -0700 Subject: Widen the plain stereo width Now full right and left is +-60 degrees instead of +-30. This should help create a smoother panning for a sound moving in front for plain stereo output (surround sound and HRTF are not changed). Multi-channel sources are also not affected by this change. The stereo channel defaults of +-pi/6 (30 degrees) still correspond to full left/right panning. This is an unfortuante discrepancy, but is necessary for AL_EXT_STEREO_ANGLES to work. --- Alc/ALu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index d033c0c4..0711d611 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -652,7 +652,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo * moved to +/-90 degrees for direct right and left speaker * responses. */ - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 3.0f) : Azi, + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ @@ -897,7 +897,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo /* Calculate the directional coefficients once, which apply to all * input channels. */ - CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 3.0f) : Azi, + CalcAngleCoeffs((Device->Render_Mode==StereoPair) ? ScaleAzimuthFront(Azi, 1.5f) : Azi, Elev, Spread, coeffs); for(c = 0;c < num_channels;c++) -- cgit v1.2.3 From 3368bd75c71e828d03d7e39c1f35a98876c46534 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 29 Aug 2018 15:31:04 -0700 Subject: Enable HRTF data set embedding by default --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16daa8d5..a6ed6d42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1284,7 +1284,7 @@ ADD_CUSTOM_TARGET(native-tools VERBATIM ) -option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" OFF) +option(ALSOFT_EMBED_HRTF_DATA "Embed the HRTF data files (increases library footprint)" ON) if(ALSOFT_EMBED_HRTF_DATA) MACRO(make_hrtf_header FILENAME VARNAME) SET(infile "${OpenAL_SOURCE_DIR}/hrtf/${FILENAME}") -- cgit v1.2.3 From 1fa464ec3e543dff5e8484a497df5f518bc8b68c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 30 Aug 2018 18:40:53 -0700 Subject: Don't modify the late reverb density with the echo parameters --- Alc/effects/reverb.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9b507b3d..95a5a3ac 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -509,10 +509,10 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.VecAp.Delay); - /* The late delay lines are calculated from the larger of the maximum - * density line length or the maximum echo time. + /* The late delay lines are calculated from the largest maximum density + * line length. */ - length = maxf(AL_EAXREVERB_MAX_ECHO_TIME, LATE_LINE_LENGTHS[NUM_LINES-1]*multiplier); + length = LATE_LINE_LENGTHS[NUM_LINES-1] * multiplier; totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay); @@ -723,7 +723,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat diffusion, c } /* Update the late reverb line lengths and T60 coefficients. */ -static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALfloat echoTime, const ALfloat echoDepth, const ALuint frequency, LateReverb *Late) +static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, const ALfloat lfDecayTime, const ALfloat mfDecayTime, const ALfloat hfDecayTime, const ALfloat lf0norm, const ALfloat hf0norm, const ALuint frequency, LateReverb *Late) { /* Scaling factor to convert the normalized reference frequencies from * representing 0...freq to 0...max_reference. @@ -743,8 +743,6 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co multiplier = CalcDelayLengthMult(density); length = (LATE_LINE_LENGTHS[0] + LATE_LINE_LENGTHS[1] + LATE_LINE_LENGTHS[2] + LATE_LINE_LENGTHS[3]) / 4.0f * multiplier; - /* Include the echo transformation (see below). */ - length = lerp(length, echoTime, echoDepth); length += (LATE_ALLPASS_LENGTHS[0] + LATE_ALLPASS_LENGTHS[1] + LATE_ALLPASS_LENGTHS[2] + LATE_ALLPASS_LENGTHS[3]) / 4.0f * multiplier; /* The density gain calculation uses an average decay time weighted by @@ -771,12 +769,8 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the delay offset for each all-pass line. */ Late->VecAp.Offset[i][1] = float2int(length * frequency); - /* Calculate the length (in seconds) of each delay line. This also - * applies the echo transformation. As the EAX echo depth approaches - * 1, the line lengths approach a length equal to the echoTime. This - * helps to produce distinct echoes along the tail. - */ - length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth); + /* Calculate the length (in seconds) of each delay line. */ + length = LATE_LINE_LENGTHS[i] * multiplier; /* Calculate the delay offset for each delay line. */ Late->Offset[i][1] = float2int(length*frequency + 0.5f); @@ -945,7 +939,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte /* Update the late lines. */ UpdateLateLines(props->Reverb.Density, props->Reverb.Diffusion, lfDecayTime, props->Reverb.DecayTime, hfDecayTime, lf0norm, hf0norm, - props->Reverb.EchoTime, props->Reverb.EchoDepth, frequency, &State->Late + frequency, &State->Late ); /* Update early and late 3D panning. */ -- cgit v1.2.3 From 8b733728afaae532edc1dd2ce44192893b170145 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 06:31:58 -0700 Subject: Apply the decay gain when reading from the late line --- Alc/effects/reverb.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 95a5a3ac..1b8a08fe 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -229,9 +229,9 @@ typedef struct VecAllpass { typedef struct T60Filter { /* Two filters are used to adjust the signal. One to control the low - * frequencies, and one to control the high frequencies. The HF filter also - * adjusts the overall output gain, affecting the remaining mid-band. + * frequencies, and one to control the high frequencies. */ + ALfloat MidGain[2]; BiquadFilter HFFilter, LFFilter; } T60Filter; @@ -395,6 +395,8 @@ static void ALreverbState_Construct(ALreverbState *state) state->Late.VecAp.Offset[i][0] = 0; state->Late.VecAp.Offset[i][1] = 0; + state->Late.T60[i].MidGain[0] = 0.0f; + state->Late.T60[i].MidGain[1] = 0.0f; BiquadFilter_clear(&state->Late.T60[i].HFFilter); BiquadFilter_clear(&state->Late.T60[i].LFFilter); } @@ -652,13 +654,11 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime ALfloat mfGain = CalcDecayCoeff(length, mfDecayTime); ALfloat hfGain = CalcDecayCoeff(length, hfDecayTime); + filter->MidGain[1] = mfGain; BiquadFilter_setParams(&filter->LFFilter, BiquadType_LowShelf, lfGain/mfGain, lf0norm, calc_rcpQ_from_slope(lfGain/mfGain, 1.0f)); BiquadFilter_setParams(&filter->HFFilter, BiquadType_HighShelf, hfGain/mfGain, hf0norm, calc_rcpQ_from_slope(hfGain/mfGain, 1.0f)); - filter->HFFilter.b0 *= mfGain; - filter->HFFilter.b1 *= mfGain; - filter->HFFilter.b2 *= mfGain; } /* Update the offsets for the main effect delay line. */ @@ -965,7 +965,8 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte State->Early.Coeff[i][1] != State->Early.Coeff[i][0] || State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || - State->Late.Offset[i][1] != State->Late.Offset[i][0]) + State->Late.Offset[i][1] != State->Late.Offset[i][0] || + State->Late.T60[i].MidGain[1] != State->Late.T60[i].MidGain[0]) { State->FadeCount = 0; break; @@ -1348,9 +1349,10 @@ static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsiz { ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; + ALfloat mid_gain = State->Late.T60[j].MidGain[0]; for(i = 0;i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + - DelayLineOut(&late_delay, late_feedb_tap++, j); + DelayLineOut(&late_delay, late_feedb_tap++, j)*mid_gain; LateT60Filter(temps[j], todo, &State->Late.T60[j]); } @@ -1393,22 +1395,26 @@ static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei for(j = 0;j < NUM_LINES;j++) { + const ALfloat oldMidGain = State->Late.T60[j].MidGain[0]; + const ALfloat midGain = State->Late.T60[j].MidGain[1]; + const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; + const ALfloat midStep = midGain / FADE_SAMPLES; ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; ALfloat fadeCount = fade * FADE_SAMPLES; - ALfloat fader = fade; for(i = 0;i < todo;i++) { const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; const ALfloat fade1 = densityStep*fadeCount; + const ALfloat gfade0 = oldMidGain + oldMidStep*fadeCount; + const ALfloat gfade1 = midStep*fadeCount; temps[j][i] = FadedDelayLineOut(&main_delay, late_delay_tap0++, late_delay_tap1++, j, fade0, fade1) + FadedDelayLineOut(&late_delay, late_feedb_tap0++, late_feedb_tap1++, j, - 1.0f-fader, fader); - fader += FadeStep; + gfade0, gfade1); fadeCount += 1.0f; } LateT60Filter(temps[j], todo, &State->Late.T60[j]); @@ -1503,6 +1509,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c State->LateDelayTap[c][0] = State->LateDelayTap[c][1]; State->Late.VecAp.Offset[c][0] = State->Late.VecAp.Offset[c][1]; State->Late.Offset[c][0] = State->Late.Offset[c][1]; + State->Late.T60[c].MidGain[0] = State->Late.T60[c].MidGain[1]; } State->Late.DensityGain[0] = State->Late.DensityGain[1]; } -- cgit v1.2.3 From 68a8c42176989e0f9b1014aa43d3ed6959dd02cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 07:20:46 -0700 Subject: Calcualte and use the maximum reverb update size Instead of requiring it to be at least as big as MAX_UPDATE_SAMPLES, which may not be true in some situations. --- Alc/effects/reverb.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 1b8a08fe..ca8eb359 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -311,6 +311,9 @@ typedef struct ALreverbState { /* Indicates the cross-fade point for delay line reads [0,FADE_SAMPLES]. */ ALsizei FadeCount; + /* Maximum number of samples to process at once. */ + ALsizei MaxUpdate[2]; + /* The current write offset for all delay lines. */ ALsizei Offset; @@ -413,6 +416,8 @@ static void ALreverbState_Construct(ALreverbState *state) } state->FadeCount = 0; + state->MaxUpdate[0] = MAX_UPDATE_SAMPLES; + state->MaxUpdate[1] = MAX_UPDATE_SAMPLES; state->Offset = 0; } @@ -774,11 +779,6 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co /* Calculate the delay offset for each delay line. */ Late->Offset[i][1] = float2int(length*frequency + 0.5f); - /* Late reverb is processed in chunks, so ensure the feedback delays - * are long enough to avoid needing to read what's written in a given - * update. - */ - assert(Late->Offset[i][1] >= MAX_UPDATE_SAMPLES); /* Approximate the absorption that the vector all-pass would exhibit * given the current diffusion so we don't have to process a full T60 @@ -948,6 +948,9 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, State); + /* Calculate the max update size from the smallest relevant delay. */ + State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, State->Late.Offset[0][1]); + /* Determine if delay-line cross-fading is required. TODO: Add some fuzz * for the float comparisons? The math should be stable enough that the * result should be the same if nothing's changed, and changes in the float @@ -1447,10 +1450,14 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c /* Process reverb for these samples. */ for(base = 0;base < SamplesToDo;) { - ALsizei todo = mini(SamplesToDo-base, MAX_UPDATE_SAMPLES); + ALsizei todo = SamplesToDo - base; /* If cross-fading, don't do more samples than there are to fade. */ if(FADE_SAMPLES-fadeCount > 0) + { todo = mini(todo, FADE_SAMPLES-fadeCount); + todo = mini(todo, State->MaxUpdate[0]); + } + todo = mini(todo, State->MaxUpdate[1]); /* Convert B-Format to A-Format for processing. */ memset(afmt, 0, sizeof(*afmt)*NUM_LINES); @@ -1512,6 +1519,7 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c State->Late.T60[c].MidGain[0] = State->Late.T60[c].MidGain[1]; } State->Late.DensityGain[0] = State->Late.DensityGain[1]; + State->MaxUpdate[0] = State->MaxUpdate[1]; } } else -- cgit v1.2.3 From 0d4b68239a1d296a8e2f95042cf1893531655bb8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 08:30:57 -0700 Subject: Include the mid-band decay with the density gain --- Alc/effects/reverb.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index ca8eb359..c7390843 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1338,7 +1338,6 @@ static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsiz ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; - const ALfloat densityGain = State->Late.DensityGain[0]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei i, j; @@ -1352,10 +1351,11 @@ static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsiz { ALsizei late_delay_tap = offset - State->LateDelayTap[j][0]; ALsizei late_feedb_tap = offset - State->Late.Offset[j][0]; - ALfloat mid_gain = State->Late.T60[j].MidGain[0]; + ALfloat midGain = State->Late.T60[j].MidGain[0]; + const ALfloat densityGain = State->Late.DensityGain[0] * midGain; for(i = 0;i < todo;i++) temps[j][i] = DelayLineOut(&main_delay, late_delay_tap++, j)*densityGain + - DelayLineOut(&late_delay, late_feedb_tap++, j)*mid_gain; + DelayLineOut(&late_delay, late_feedb_tap++, j)*midGain; LateT60Filter(temps[j], todo, &State->Late.T60[j]); } @@ -1386,10 +1386,6 @@ static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI late_delay = State->Late.Delay; const DelayLineI main_delay = State->Delay; - const ALfloat oldDensityGain = State->Late.DensityGain[0]; - const ALfloat densityGain = State->Late.DensityGain[1]; - const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; - const ALfloat densityStep = densityGain / FADE_SAMPLES; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei i, j; @@ -1402,6 +1398,10 @@ static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei const ALfloat midGain = State->Late.T60[j].MidGain[1]; const ALfloat oldMidStep = -oldMidGain / FADE_SAMPLES; const ALfloat midStep = midGain / FADE_SAMPLES; + const ALfloat oldDensityGain = State->Late.DensityGain[0] * oldMidGain; + const ALfloat densityGain = State->Late.DensityGain[1] * midGain; + const ALfloat oldDensityStep = -oldDensityGain / FADE_SAMPLES; + const ALfloat densityStep = densityGain / FADE_SAMPLES; ALsizei late_delay_tap0 = offset - State->LateDelayTap[j][0]; ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; -- cgit v1.2.3 From 01cc0cd7871477adcb405ea5a416ab569b25ffda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 13:01:03 -0700 Subject: Pass the appropriate /arch switch for x86 MSVC --- CMakeLists.txt | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6ed6d42..884006fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -433,24 +433,42 @@ IF(HAVE_MFPU_NEON_SWITCH) ENDIF() SET(FPMATH_SET "0") -IF(HAVE_MSSE_SWITCH AND CMAKE_SIZEOF_VOID_P MATCHES "4") - OPTION(ALSOFT_ENABLE_SSE_CODEGEN "Enable SSE code generation instead of x87 for 32-bit targets." TRUE) - IF(HAVE_MSSE2_SWITCH) +IF(CMAKE_SIZEOF_VOID_P MATCHES "4") + IF(SSE_SWITCH OR MSVC) + OPTION(ALSOFT_ENABLE_SSE_CODEGEN "Enable SSE code generation instead of x87 for 32-bit targets." TRUE) + ENDIF() + IF(SSE2_SWITCH OR MSVC) OPTION(ALSOFT_ENABLE_SSE2_CODEGEN "Enable SSE2 code generation instead of x87 for 32-bit targets." TRUE) ENDIF() - IF(HAVE_MSSE2_SWITCH AND ALSOFT_ENABLE_SSE2_CODEGEN) - CHECK_C_COMPILER_FLAG("${SSE2_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE_2) - IF(ALSOFT_ENABLE_SSE2_CODEGEN AND HAVE_MFPMATH_SSE_2) - SET(C_FLAGS ${C_FLAGS} ${SSE2_SWITCH} -mfpmath=sse) - SET(FPMATH_SET 2) + IF(ALSOFT_ENABLE_SSE2_CODEGEN) + IF(SSE2_SWITCH) + CHECK_C_COMPILER_FLAG("${SSE2_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE_2) + IF(HAVE_MFPMATH_SSE_2) + SET(C_FLAGS ${C_FLAGS} ${SSE2_SWITCH} -mfpmath=sse) + SET(FPMATH_SET 2) + ENDIF() + ELSEIF(MSVC) + CHECK_C_COMPILER_FLAG("/arch:SSE2" HAVE_ARCH_SSE2) + IF(HAVE_ARCH_SSE2) + SET(C_FLAGS ${C_FLAGS} "/arch:SSE2") + SET(FPMATH_SET 2) + ENDIF() ENDIF() ENDIF() IF(ALSOFT_ENABLE_SSE_CODEGEN AND NOT FPMATH_SET) - CHECK_C_COMPILER_FLAG("${SSE_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE) - IF(ALSOFT_ENABLE_SSE_CODEGEN AND HAVE_MFPMATH_SSE) - SET(C_FLAGS ${C_FLAGS} ${SSE_SWITCH} -mfpmath=sse) - SET(FPMATH_SET 1) + IF(SSE_SWITCH) + CHECK_C_COMPILER_FLAG("${SSE_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE) + IF(HAVE_MFPMATH_SSE) + SET(C_FLAGS ${C_FLAGS} ${SSE_SWITCH} -mfpmath=sse) + SET(FPMATH_SET 1) + ENDIF() + ELSEIF(MSVC) + CHECK_C_COMPILER_FLAG("/arch:SSE" HAVE_ARCH_SSE) + IF(HAVE_ARCH_SSE) + SET(C_FLAGS ${C_FLAGS} "/arch:SSE") + SET(FPMATH_SET 1) + ENDIF() ENDIF() ENDIF() ENDIF() -- cgit v1.2.3 From 0a8398dd99a78db876ee7b16ab4c49d09daaee93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 17:35:57 -0700 Subject: Update a comment --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 0711d611..e5203d6e 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -648,7 +648,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo voice->Flags |= VOICE_HAS_NFC; } - /* A scalar of 3 for plain stereo results in +/-30 degrees being + /* A scalar of 1.5 for plain stereo results in +/-60 degrees being * moved to +/-90 degrees for direct right and left speaker * responses. */ -- cgit v1.2.3 From 30bd84a93575930f5cf747d76692be3d6a9393f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 31 Aug 2018 17:45:59 -0700 Subject: Fix a typo in the changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 7e6a5009..84939b53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,7 +20,7 @@ openal-soft-1.19.0: Renamed the MMDevAPI backend to WASAPI. - Added support fot 24-bit, dual-ear HRTF data sets. The built-in data set + Added support for 24-bit, dual-ear HRTF data sets. The built-in data set has been updated to 24-bit. Added a 24- to 48-point band-limited Sinc resampler. -- cgit v1.2.3 From b854f4037f551bbe42030f155084a2a5c0a1addc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Sep 2018 18:15:56 -0700 Subject: Read the whole Features string for neon support --- Alc/helpers.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index 53d85a86..e7f12a5f 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -223,22 +223,32 @@ void FillCPUCaps(int capfilter) ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); else { + al_string features = AL_STRING_INIT_STATIC(); char buf[256]; + while(fgets(buf, sizeof(buf), file) != NULL) { - size_t len; - char *str; - if(strncmp(buf, "Features\t:", 10) != 0) continue; - len = strlen(buf); - while(len > 0 && isspace(buf[len-1])) - buf[--len] = 0; + alstr_copy_cstr(&features, buf+10); + while(VECTOR_BACK(features) != '\n') + { + if(fgets(buf, sizeof(buf), file) == NULL) + break; + alstr_append_cstr(&features, buf); + } + break; + } + fclose(file); + file = NULL; - TRACE("Got features string:%s\n", buf+10); + if(!alstr_empty(features)) + { + const char *str = alstr_get_cstr(features); + while(isspace(str[0])) ++str; - str = buf; + TRACE("Got features string:%s\n", str); while((str=strstr(str, "neon")) != NULL) { if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4]))) @@ -246,13 +256,11 @@ void FillCPUCaps(int capfilter) caps |= CPU_CAP_NEON; break; } - str++; + ++str; } - break; } - fclose(file); - file = NULL; + alstr_reset(&features); } #endif -- cgit v1.2.3 From 3b4f28d173d21bad20f28ec41f594f88459596dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 2 Sep 2018 21:15:21 -0700 Subject: Avoid double-resizing when appending a char to a string --- Alc/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/helpers.c b/Alc/helpers.c index e7f12a5f..d2cb6253 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -1105,8 +1105,8 @@ void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_ void alstr_append_char(al_string *str, const al_string_char_type c) { size_t len = alstr_length(*str); - VECTOR_RESIZE(*str, len, len+2); - VECTOR_PUSH_BACK(*str, c); + VECTOR_RESIZE(*str, len+1, len+2); + VECTOR_BACK(*str) = c; VECTOR_ELEM(*str, len+1) = 0; } -- cgit v1.2.3 From fce86815f494b981f3cbbba290f5399c9907dee7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Sep 2018 12:18:06 -0700 Subject: Extract SIMD values right before using them --- Alc/mixer/mixer_neon.c | 12 +++++++----- Alc/mixer/mixer_sse2.c | 15 +++++++-------- Alc/mixer/mixer_sse41.c | 15 +++++++-------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 9aa279a2..4feb431d 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -32,8 +32,12 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), for(i = 0;numsamples-i > 3;i += 4) { - const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]}; - const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]}; + const int pos0 = vgetq_lane_s32(pos4, 0); + const int pos1 = vgetq_lane_s32(pos4, 1); + const int pos2 = vgetq_lane_s32(pos4, 2); + const int pos3 = vgetq_lane_s32(pos4, 3); + const float32x4_t val1 = (float32x4_t){src[pos0], src[pos1], src[pos2], src[pos3]}; + const float32x4_t val2 = (float32x4_t){src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]}; /* val1 + (val2-val1)*mu */ const float32x4_t r0 = vsubq_f32(val2, val1); @@ -45,8 +49,6 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), frac4 = vaddq_s32(frac4, increment4); pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS)); frac4 = vandq_s32(frac4, fracMask4); - - vst1q_s32(pos_, pos4); } if(i < numsamples) @@ -55,7 +57,7 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), * four samples, so the lowest element is the next position to * resample. */ - ALint pos = pos_[0]; + int pos = vgetq_lane_s32(pos4, 0); frac = vgetq_lane_s32(frac4, 0); do { dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index e0198022..83aaf7f2 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -49,8 +49,12 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), for(i = 0;numsamples-i > 3;i += 4) { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0] ], src[pos_.i[1] ], src[pos_.i[2] ], src[pos_.i[3] ]); - const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); + const int pos0 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); + const int pos1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); + const int pos2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2))); + const int pos3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3))); + const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); + const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]); /* val1 + (val2-val1)*mu */ const __m128 r0 = _mm_sub_ps(val2, val1); @@ -62,17 +66,12 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), frac4 = _mm_add_epi32(frac4, increment4); pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); frac4 = _mm_and_si128(frac4, fracMask4); - - pos_.i[0] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); - pos_.i[1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); - pos_.i[2] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(2, 2, 2, 2))); - pos_.i[3] = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(3, 3, 3, 3))); } /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - pos = pos_.i[0]; + pos = _mm_cvtsi128_si32(pos4); frac = _mm_cvtsi128_si32(frac4); for(;i < numsamples;i++) diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c index 98a3ef74..396b7c7c 100644 --- a/Alc/mixer/mixer_sse41.c +++ b/Alc/mixer/mixer_sse41.c @@ -50,8 +50,12 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), for(i = 0;numsamples-i > 3;i += 4) { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); - const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); + const int pos0 = _mm_extract_epi32(pos4, 0); + const int pos1 = _mm_extract_epi32(pos4, 1); + const int pos2 = _mm_extract_epi32(pos4, 2); + const int pos3 = _mm_extract_epi32(pos4, 3); + const __m128 val1 = _mm_setr_ps(src[pos0 ], src[pos1 ], src[pos2 ], src[pos3 ]); + const __m128 val2 = _mm_setr_ps(src[pos0+1], src[pos1+1], src[pos2+1], src[pos3+1]); /* val1 + (val2-val1)*mu */ const __m128 r0 = _mm_sub_ps(val2, val1); @@ -63,17 +67,12 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), frac4 = _mm_add_epi32(frac4, increment4); pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); frac4 = _mm_and_si128(frac4, fracMask4); - - pos_.i[0] = _mm_extract_epi32(pos4, 0); - pos_.i[1] = _mm_extract_epi32(pos4, 1); - pos_.i[2] = _mm_extract_epi32(pos4, 2); - pos_.i[3] = _mm_extract_epi32(pos4, 3); } /* NOTE: These four elements represent the position *after* the last four * samples, so the lowest element is the next position to resample. */ - pos = pos_.i[0]; + pos = _mm_cvtsi128_si32(pos4); frac = _mm_cvtsi128_si32(frac4); for(;i < numsamples;i++) -- cgit v1.2.3 From 0f243b927cde10dab3adcf3fde99bf05a34080cc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Sep 2018 17:07:43 -0700 Subject: Slightly restructure some loops --- Alc/mixer/mixer_neon.c | 35 ++++++++++++++++------------------- Alc/mixer/mixer_sse2.c | 19 +++++++++---------- Alc/mixer/mixer_sse41.c | 19 +++++++++---------- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 4feb431d..db61fd41 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -19,18 +19,17 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); alignas(16) ALint pos_[4]; alignas(16) ALsizei frac_[4]; - int32x4_t pos4; - int32x4_t frac4; - ALsizei i; + int32x4_t pos4, frac4; + ALsizei todo, pos, i; ASSUME(numsamples > 0); InitiatePositionArrays(frac, increment, frac_, pos_, 4); - frac4 = vld1q_s32(frac_); pos4 = vld1q_s32(pos_); - for(i = 0;numsamples-i > 3;i += 4) + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) { const int pos0 = vgetq_lane_s32(pos4, 0); const int pos1 = vgetq_lane_s32(pos4, 1); @@ -51,21 +50,19 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), frac4 = vandq_s32(frac4, fracMask4); } - if(i < numsamples) + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ + pos = vgetq_lane_s32(pos4, 0); + frac = vgetq_lane_s32(frac4, 0); + + for(;i < numsamples;++i) { - /* NOTE: These four elements represent the position *after* the last - * four samples, so the lowest element is the next position to - * resample. - */ - int pos = vgetq_lane_s32(pos4, 0); - frac = vgetq_lane_s32(frac4, 0); - do { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } while(++i < numsamples); + dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; } return dst; } diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index 83aaf7f2..629e0ec7 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -34,20 +34,19 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALsizei i[4]; float f[4]; } frac_; + ALint pos_[4]; + ALsizei frac_[4]; __m128i frac4, pos4; - ALint pos; - ALsizei i; + ALsizei todo, pos, i; ASSUME(numsamples > 0); - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); + pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - for(i = 0;numsamples-i > 3;i += 4) + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) { const int pos0 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(0, 0, 0, 0))); const int pos1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(pos4, _MM_SHUFFLE(1, 1, 1, 1))); @@ -74,7 +73,7 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), pos = _mm_cvtsi128_si32(pos4); frac = _mm_cvtsi128_si32(frac4); - for(;i < numsamples;i++) + for(;i < numsamples;++i) { dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c index 396b7c7c..128acadf 100644 --- a/Alc/mixer/mixer_sse41.c +++ b/Alc/mixer/mixer_sse41.c @@ -35,20 +35,19 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - union { alignas(16) ALint i[4]; float f[4]; } pos_; - union { alignas(16) ALsizei i[4]; float f[4]; } frac_; + ALint pos_[4]; + ALsizei frac_[4]; __m128i frac4, pos4; - ALint pos; - ALsizei i; + ALsizei todo, pos, i; ASSUME(numsamples > 0); - InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + InitiatePositionArrays(frac, increment, frac_, pos_, 4); + frac4 = _mm_setr_epi32(frac_[0], frac_[1], frac_[2], frac_[3]); + pos4 = _mm_setr_epi32(pos_[0], pos_[1], pos_[2], pos_[3]); - frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); - pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); - - for(i = 0;numsamples-i > 3;i += 4) + todo = numsamples & ~3; + for(i = 0;i < todo;i += 4) { const int pos0 = _mm_extract_epi32(pos4, 0); const int pos1 = _mm_extract_epi32(pos4, 1); @@ -75,7 +74,7 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), pos = _mm_cvtsi128_si32(pos4); frac = _mm_cvtsi128_si32(frac4); - for(;i < numsamples;i++) + for(;i < numsamples;++i) { dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); -- cgit v1.2.3 From 4c32a0aba7b1e10946d3f938e945e7b6f1e98e55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 3 Sep 2018 21:09:31 -0700 Subject: Update changelog about 32-bit using SSE2 by default --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 84939b53..6134e113 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,9 @@ openal-soft-1.19.0: Increased the number of virtual channels for decoding Ambisonics to HRTF output. + Changed 32-bit x86 builds to use SSE2 math by default for performance. + Build-time options are available to use just SSE1 or x87 instead. + Replaced the 4-point Sinc resampler with a more efficient cubic resampler. Renamed the MMDevAPI backend to WASAPI. -- cgit v1.2.3 From 96aacac10ca852fc30fd7f72f3e3c6ddbe02858c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Sep 2018 14:35:18 -0700 Subject: Release 1.19.0 --- CMakeLists.txt | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 884006fd..f6d0037e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,8 +102,8 @@ IF(NOT LIBTYPE) ENDIF() SET(LIB_MAJOR_VERSION "1") -SET(LIB_MINOR_VERSION "18") -SET(LIB_REVISION "2") +SET(LIB_MINOR_VERSION "19") +SET(LIB_REVISION "0") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") diff --git a/appveyor.yml b/appveyor.yml index 0e5b7ce4..6d826eed 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.18.2.{build} +version: 1.19.0.{build} environment: matrix: -- cgit v1.2.3 From 7394dd512dd36e7bf105b065c9b773b0d9f5ace5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 18:45:24 -0700 Subject: Rename ALCsndioBackend --- Alc/ALc.c | 8 ++--- Alc/backends/base.h | 2 +- Alc/backends/sndio.c | 92 ++++++++++++++++++++++++++-------------------------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 535f9475..1b47777e 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -79,7 +79,7 @@ static struct BackendInfo BackendList[] = { { "solaris", ALCsolarisBackendFactory_getFactory }, #endif #ifdef HAVE_SNDIO - { "sndio", ALCsndioBackendFactory_getFactory }, + { "sndio", SndioBackendFactory_getFactory }, #endif #ifdef HAVE_OSS { "oss", ALCossBackendFactory_getFactory }, @@ -656,9 +656,9 @@ static const struct { DECL(AL_DEDICATED_GAIN), - DECL(AL_AUTOWAH_ATTACK_TIME), - DECL(AL_AUTOWAH_RELEASE_TIME), - DECL(AL_AUTOWAH_RESONANCE), + DECL(AL_AUTOWAH_ATTACK_TIME), + DECL(AL_AUTOWAH_RELEASE_TIME), + DECL(AL_AUTOWAH_RESONANCE), DECL(AL_AUTOWAH_PEAK_GAIN), DECL(AL_NUM_RESAMPLERS_SOFT), diff --git a/Alc/backends/base.h b/Alc/backends/base.h index ba92b4ac..e6f624c2 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -142,7 +142,7 @@ ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); ALCbackendFactory *ALCjackBackendFactory_getFactory(void); ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); -ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); +ALCbackendFactory *SndioBackendFactory_getFactory(void); ALCbackendFactory *ALCqsaBackendFactory_getFactory(void); ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 5aea457b..90d0866f 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -35,7 +35,7 @@ -typedef struct ALCsndioBackend { +typedef struct SndioPlayback { DERIVE_FROM_TYPE(ALCbackend); struct sio_hdl *sndHandle; @@ -45,40 +45,40 @@ typedef struct ALCsndioBackend { ATOMIC(int) killNow; althrd_t thread; -} ALCsndioBackend; +} SndioPlayback; -static int ALCsndioBackend_mixerProc(void *ptr); +static int SndioPlayback_mixerProc(void *ptr); -static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device); -static void ALCsndioBackend_Destruct(ALCsndioBackend *self); -static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name); -static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self); -static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self); -static void ALCsndioBackend_stop(ALCsndioBackend *self); -static DECLARE_FORWARD2(ALCsndioBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ALCuint, availableSamples) -static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ClockLatency, getClockLatency) -static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, lock) -static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(ALCsndioBackend) +static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device); +static void SndioPlayback_Destruct(SndioPlayback *self); +static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name); +static ALCboolean SndioPlayback_reset(SndioPlayback *self); +static ALCboolean SndioPlayback_start(SndioPlayback *self); +static void SndioPlayback_stop(SndioPlayback *self); +static DECLARE_FORWARD2(SndioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(SndioPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) -DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend); +DEFINE_ALCBACKEND_VTABLE(SndioPlayback); static const ALCchar sndio_device[] = "SndIO Default"; -static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device) +static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(ALCsndioBackend, ALCbackend, self); + SET_VTABLE2(SndioPlayback, ALCbackend, self); self->sndHandle = NULL; self->mix_data = NULL; ATOMIC_INIT(&self->killNow, AL_TRUE); } -static void ALCsndioBackend_Destruct(ALCsndioBackend *self) +static void SndioPlayback_Destruct(SndioPlayback *self) { if(self->sndHandle) sio_close(self->sndHandle); @@ -91,9 +91,9 @@ static void ALCsndioBackend_Destruct(ALCsndioBackend *self) } -static int ALCsndioBackend_mixerProc(void *ptr) +static int SndioPlayback_mixerProc(void *ptr) { - ALCsndioBackend *self = (ALCsndioBackend*)ptr; + SndioPlayback *self = (SndioPlayback*)ptr; ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALsizei frameSize; size_t wrote; @@ -109,9 +109,9 @@ static int ALCsndioBackend_mixerProc(void *ptr) ALsizei len = self->data_size; ALubyte *WritePtr = self->mix_data; - ALCsndioBackend_lock(self); + SndioPlayback_lock(self); aluMixData(device, WritePtr, len/frameSize); - ALCsndioBackend_unlock(self); + SndioPlayback_unlock(self); while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire)) { wrote = sio_write(self->sndHandle, WritePtr, len); @@ -133,7 +133,7 @@ static int ALCsndioBackend_mixerProc(void *ptr) } -static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) +static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; @@ -154,7 +154,7 @@ static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name) return ALC_NO_ERROR; } -static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self) +static ALCboolean SndioPlayback_reset(SndioPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; struct sio_par par; @@ -239,7 +239,7 @@ static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self) return ALC_TRUE; } -static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) +static ALCboolean SndioPlayback_start(SndioPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; @@ -256,7 +256,7 @@ static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) } ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); - if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success) + if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success) { sio_stop(self->sndHandle); return ALC_FALSE; @@ -265,7 +265,7 @@ static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self) return ALC_TRUE; } -static void ALCsndioBackend_stop(ALCsndioBackend *self) +static void SndioPlayback_stop(SndioPlayback *self) { int res; @@ -281,42 +281,42 @@ static void ALCsndioBackend_stop(ALCsndioBackend *self) } -typedef struct ALCsndioBackendFactory { +typedef struct SndioBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCsndioBackendFactory; -#define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } } +} SndioBackendFactory; +#define SNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(SndioBackendFactory, ALCbackendFactory) } } -ALCbackendFactory *ALCsndioBackendFactory_getFactory(void); +ALCbackendFactory *SndioBackendFactory_getFactory(void); -static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory *self); -static DECLARE_FORWARD(ALCsndioBackendFactory, ALCbackendFactory, void, deinit) -static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory *self, ALCbackend_Type type); -static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory *self, enum DevProbe type); -static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); -DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsndioBackendFactory); +static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); +static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); +static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type); +static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); -ALCbackendFactory *ALCsndioBackendFactory_getFactory(void) +ALCbackendFactory *SndioBackendFactory_getFactory(void) { - static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER; + static SndioBackendFactory factory = SNDIOBACKENDFACTORY_INITIALIZER; return STATIC_CAST(ALCbackendFactory, &factory); } -static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self)) +static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) { /* No dynamic loading */ return ALC_TRUE; } -static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type) +static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type) { if(type == ALCbackend_Playback) return ALC_TRUE; return ALC_FALSE; } -static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type) +static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -328,12 +328,12 @@ static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), e } } -static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) { if(type == ALCbackend_Playback) { - ALCsndioBackend *backend; - NEW_OBJ(backend, ALCsndioBackend)(device); + SndioPlayback *backend; + NEW_OBJ(backend, SndioPlayback)(device); if(!backend) return NULL; return STATIC_CAST(ALCbackend, backend); } -- cgit v1.2.3 From 212cb8e298ccfd42e8d44cc2a20108513507e29e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 20:08:24 -0700 Subject: Implement capture support for SoundIO --- Alc/backends/sndio.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 266 insertions(+), 6 deletions(-) diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 90d0866f..062e6732 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -27,12 +27,14 @@ #include "alMain.h" #include "alu.h" #include "threads.h" +#include "ringbuffer.h" #include "backends/base.h" #include +static const ALCchar sndio_device[] = "SndIO Default"; typedef struct SndioPlayback { @@ -65,9 +67,6 @@ DECLARE_DEFAULT_ALLOCATORS(SndioPlayback) DEFINE_ALCBACKEND_VTABLE(SndioPlayback); -static const ALCchar sndio_device[] = "SndIO Default"; - - static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -281,6 +280,261 @@ static void SndioPlayback_stop(SndioPlayback *self) } +typedef struct SndioCapture { + DERIVE_FROM_TYPE(ALCbackend); + + struct sio_hdl *sndHandle; + + ll_ringbuffer_t *ring; + + ATOMIC(int) killNow; + althrd_t thread; +} SndioCapture; + +static int SndioCapture_recordProc(void *ptr); + +static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device); +static void SndioCapture_Destruct(SndioCapture *self); +static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name); +static DECLARE_FORWARD(SndioCapture, ALCbackend, ALCboolean, reset) +static ALCboolean SndioCapture_start(SndioCapture *self); +static void SndioCapture_stop(SndioCapture *self); +static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples); +static ALCuint SndioCapture_availableSamples(SndioCapture *self); +static DECLARE_FORWARD(SndioCapture, ALCbackend, ClockLatency, getClockLatency) +static DECLARE_FORWARD(SndioCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(SndioCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(SndioCapture) + +DEFINE_ALCBACKEND_VTABLE(SndioCapture); + + +static void SndioCapture_Construct(SndioCapture *self, ALCdevice *device) +{ + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(SndioCapture, ALCbackend, self); + + self->sndHandle = NULL; + self->ring = NULL; + ATOMIC_INIT(&self->killNow, AL_TRUE); +} + +static void SndioCapture_Destruct(SndioCapture *self) +{ + if(self->sndHandle) + sio_close(self->sndHandle); + self->sndHandle = NULL; + + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static int SndioCapture_recordProc(void* ptr) +{ + SndioCapture *self = (SndioCapture*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALsizei frameSize; + + SetRTPriority(); + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); + + while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) + { + ll_ringbuffer_data_t data[2]; + size_t total, todo; + + ll_ringbuffer_get_write_vector(self->ring, data); + todo = data[0].len + data[1].len; + if(todo == 0) + { + static char junk[4096]; + sio_read(self->sndHandle, junk, minz(sizeof(junk)/frameSize, device->UpdateSize)*frameSize); + continue; + } + + total = 0; + data[0].len *= frameSize; + data[1].len *= frameSize; + todo = minz(todo, device->UpdateSize) * frameSize; + while(total < todo) + { + size_t got; + + if(!data[0].len) + data[0] = data[1]; + + got = sio_read(self->sndHandle, data[0].buf, minz(todo-total, data[0].len)); + if(!got) + { + SndioCapture_lock(self); + aluHandleDisconnect(device, "Failed to read capture samples"); + SndioCapture_unlock(self); + break; + } + + data[0].buf += got; + data[0].len -= got; + total += got; + } + ll_ringbuffer_write_advance(self->ring, total / frameSize); + } + + return 0; +} + + +static ALCenum SndioCapture_open(SndioCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + struct sio_par par; + + if(!name) + name = sndio_device; + else if(strcmp(name, sndio_device) != 0) + return ALC_INVALID_VALUE; + + self->sndHandle = sio_open(NULL, SIO_REC, 0); + if(self->sndHandle == NULL) + { + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + sio_initpar(&par); + + switch(device->FmtType) + { + case DevFmtByte: + par.bps = 1; + par.sig = 1; + break; + case DevFmtUByte: + par.bps = 1; + par.sig = 0; + break; + case DevFmtShort: + par.bps = 2; + par.sig = 1; + break; + case DevFmtUShort: + par.bps = 2; + par.sig = 0; + break; + case DevFmtInt: + par.bps = 4; + par.sig = 1; + break; + case DevFmtUInt: + par.bps = 4; + par.sig = 0; + break; + case DevFmtFloat: + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + par.bits = par.bps * 8; + par.le = SIO_LE_NATIVE; + par.msb = SIO_LE_NATIVE ? 0 : 1; + par.rchan = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); + par.rate = device->Frequency; + + par.appbufsz = maxu(device->UpdateSize*device->NumUpdates, (device->Frequency+9)/10); + par.round = clampu(par.appbufsz/device->NumUpdates, (device->Frequency+99)/100, + (device->Frequency+19)/20); + + device->UpdateSize = par.round; + device->NumUpdates = maxu(par.appbufsz/par.round, 1); + + if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_INVALID_VALUE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_INVALID_VALUE; + } + + if(!((device->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) || + (device->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) || + (device->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) || + (device->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) || + (device->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) || + (device->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) || + ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)par.rchan || + device->Frequency != par.rate) + { + ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n", + DevFmtTypeString(device->FmtType), DevFmtChannelsString(device->FmtChans), + device->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate); + return ALC_INVALID_VALUE; + } + + self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, par.bps*par.rchan, 0); + if(!self->ring) + { + ERR("Failed to allocate %u-byte ringbuffer\n", + device->UpdateSize*device->NumUpdates*par.bps*par.rchan); + return ALC_OUT_OF_MEMORY; + } + + SetDefaultChannelOrder(device); + + alstr_copy_cstr(&device->DeviceName, name); + + return ALC_NO_ERROR; +} + +static ALCboolean SndioCapture_start(SndioCapture *self) +{ + if(!sio_start(self->sndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); + if(althrd_create(&self->thread, SndioCapture_recordProc, self) != althrd_success) + { + sio_stop(self->sndHandle); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void SndioCapture_stop(SndioCapture *self) +{ + int res; + + if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + return; + althrd_join(self->thread, &res); + + if(!sio_stop(self->sndHandle)) + ERR("Error stopping device\n"); +} + +static ALCenum SndioCapture_captureSamples(SndioCapture *self, void *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->ring, buffer, samples); + return ALC_NO_ERROR; +} + +static ALCuint SndioCapture_availableSamples(SndioCapture *self) +{ + return ll_ringbuffer_read_space(self->ring); +} + + typedef struct SndioBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } SndioBackendFactory; @@ -295,14 +549,12 @@ static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe t static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); - ALCbackendFactory *SndioBackendFactory_getFactory(void) { static SndioBackendFactory factory = SNDIOBACKENDFACTORY_INITIALIZER; return STATIC_CAST(ALCbackendFactory, &factory); } - static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) { /* No dynamic loading */ @@ -311,7 +563,7 @@ static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self)) static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type) { - if(type == ALCbackend_Playback) + if(type == ALCbackend_Playback || type == ALCbackend_Capture) return ALC_TRUE; return ALC_FALSE; } @@ -324,6 +576,7 @@ static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum De AppendAllDevicesList(sndio_device); break; case CAPTURE_DEVICE_PROBE: + AppendCaptureDeviceList(sndio_device); break; } } @@ -337,6 +590,13 @@ static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED if(!backend) return NULL; return STATIC_CAST(ALCbackend, backend); } + if(type == ALCbackend_Capture) + { + SndioCapture *backend; + NEW_OBJ(backend, SndioCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } return NULL; } -- cgit v1.2.3 From 46cfedb1171ace7c21bd1d95c1c75a8274892d3d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 22:02:37 -0700 Subject: Pass the device name list to the backend probe method --- Alc/ALc.c | 13 +------------ Alc/backends/alsa.c | 17 +++++++++-------- Alc/backends/base.h | 5 +++-- Alc/backends/coreaudio.c | 8 +++----- Alc/backends/dsound.c | 19 ++++++++++--------- Alc/backends/jack.c | 4 ++-- Alc/backends/loopback.c | 4 ++-- Alc/backends/null.c | 7 +++---- Alc/backends/opensl.c | 7 ++----- Alc/backends/oss.c | 31 +++++++++++-------------------- Alc/backends/portaudio.c | 9 +++------ Alc/backends/pulseaudio.c | 21 +++++++++++---------- Alc/backends/qsa.c | 31 +++++++++++++------------------ Alc/backends/sdl2.c | 9 +++++---- Alc/backends/sndio.c | 8 +++----- Alc/backends/solaris.c | 6 +++--- Alc/backends/wasapi.c | 19 ++++++++++--------- Alc/backends/wave.c | 6 +++--- Alc/backends/winmm.c | 24 +++++++++--------------- OpenAL32/Include/alMain.h | 3 --- 20 files changed, 106 insertions(+), 145 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 1b47777e..27c36477 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1314,7 +1314,7 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum if(backendinfo->getFactory) { ALCbackendFactory *factory = backendinfo->getFactory(); - V(factory,probe)(type); + V(factory,probe)(type, list); } UnlockLists(); @@ -1324,17 +1324,6 @@ static void ProbeAllDevicesList(void) static void ProbeCaptureDeviceList(void) { ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, CAPTURE_DEVICE_PROBE); } -static void AppendDevice(const ALCchar *name, al_string *devnames) -{ - size_t len = strlen(name); - if(len > 0) - alstr_append_range(devnames, name, name+len+1); -} -void AppendAllDevicesList(const ALCchar *name) -{ AppendDevice(name, &alcAllDevicesList); } -void AppendCaptureDeviceList(const ALCchar *name) -{ AppendDevice(name, &alcCaptureDeviceList); } - /************************************************ * Device format information diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c index 409be7fa..a967fff0 100644 --- a/Alc/backends/alsa.c +++ b/Alc/backends/alsa.c @@ -1375,11 +1375,6 @@ static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self) } -static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } -static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } - typedef struct ALCalsaBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCalsaBackendFactory; @@ -1417,19 +1412,25 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS return ALC_FALSE; } -static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { +#define APPEND_OUTNAME(i) do { \ + if(!alstr_empty((i)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((i)->name), \ + VECTOR_END((i)->name)+1); \ +} while(0) case ALL_DEVICE_PROBE: probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } } diff --git a/Alc/backends/base.h b/Alc/backends/base.h index e6f624c2..0de4e590 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -3,6 +3,7 @@ #include "alMain.h" #include "threads.h" +#include "alstring.h" #ifdef __cplusplus @@ -115,7 +116,7 @@ struct ALCbackendFactoryVtable { ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type); - void (*const probe)(ALCbackendFactory *self, enum DevProbe type); + void (*const probe)(ALCbackendFactory *self, enum DevProbe type, al_string *outnames); ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type); }; @@ -124,7 +125,7 @@ struct ALCbackendFactoryVtable { 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, void, probe, enum DevProbe, al_string*) \ DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \ \ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index a8787f7b..5945834c 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -752,7 +752,7 @@ ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void); static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self); static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type); -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type); +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory); @@ -776,15 +776,13 @@ static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFac return ALC_FALSE; } -static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(ca_device); - break; case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(ca_device); + alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device)); break; } } diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c index 6bab641c..c368cffb 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.c @@ -969,11 +969,6 @@ done: } -static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } -static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } - typedef struct ALCdsoundBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCdsoundBackendFactory; @@ -984,7 +979,7 @@ ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory *self); static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory *self); static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory *self, ALCbackend_Type type); -static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type); +static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory); @@ -1028,7 +1023,7 @@ static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* return ALC_FALSE; } -static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { HRESULT hr, hrcom; @@ -1036,12 +1031,17 @@ static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), hrcom = CoInitialize(NULL); switch(type) { +#define APPEND_OUTNAME(e) do { \ + if(!alstr_empty((e)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ + VECTOR_END((e)->name)+1); \ +} while(0) case ALL_DEVICE_PROBE: clear_devlist(&PlaybackDevices); hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: @@ -1049,8 +1049,9 @@ static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } if(SUCCEEDED(hrcom)) CoUninitialize(); diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index 67e3c106..fdbe93f2 100644 --- a/Alc/backends/jack.c +++ b/Alc/backends/jack.c @@ -571,12 +571,12 @@ static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUS return ALC_FALSE; } -static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(jackDevice); + alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice)); break; case CAPTURE_DEVICE_PROBE: diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c index 9186a92f..e9940086 100644 --- a/Alc/backends/loopback.c +++ b/Alc/backends/loopback.c @@ -87,7 +87,7 @@ 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 void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory); @@ -110,7 +110,7 @@ static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(sel return ALC_FALSE; } -static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type)) +static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) { } diff --git a/Alc/backends/null.c b/Alc/backends/null.c index 2c2db54e..d1c110e8 100644 --- a/Alc/backends/null.c +++ b/Alc/backends/null.c @@ -171,7 +171,7 @@ 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 void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory); @@ -195,14 +195,13 @@ static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUS return ALC_FALSE; } -static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(nullDevice); - break; case CAPTURE_DEVICE_PROBE: + alstr_append_range(outnames, nullDevice, nullDevice+sizeof(nullDevice)); break; } } diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 262fdaef..50fe77d8 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -1030,16 +1030,13 @@ static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* return ALC_FALSE; } -static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(opensl_device); - break; - case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(opensl_device); + alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device)); break; } } diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c index c0c98c43..71faad25 100644 --- a/Alc/backends/oss.c +++ b/Alc/backends/oss.c @@ -786,7 +786,7 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void); static ALCboolean ALCossBackendFactory_init(ALCossBackendFactory *self); static void ALCossBackendFactory_deinit(ALCossBackendFactory *self); static ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory *self, ALCbackend_Type type); -static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type); +static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory); @@ -820,40 +820,31 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self), return ALC_FALSE; } -void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type) +void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - struct oss_device *cur; + struct oss_device *cur = NULL; switch(type) { case ALL_DEVICE_PROBE: ALCossListFree(&oss_playback); ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT); cur = &oss_playback; - while(cur != NULL) - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(cur->path, &buf) == 0) -#endif - AppendAllDevicesList(cur->handle); - cur = cur->next; - } break; case CAPTURE_DEVICE_PROBE: ALCossListFree(&oss_capture); ALCossListPopulate(&oss_capture, DSP_CAP_INPUT); cur = &oss_capture; - while(cur != NULL) - { + break; + } + while(cur != NULL) + { #ifdef HAVE_STAT - struct stat buf; - if(stat(cur->path, &buf) == 0) + struct stat buf; + if(stat(cur->path, &buf) == 0) #endif - AppendCaptureDeviceList(cur->handle); - cur = cur->next; - } - break; + alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1); + cur = cur->next; } } diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c index 9b0d3487..6a6cfa31 100644 --- a/Alc/backends/portaudio.c +++ b/Alc/backends/portaudio.c @@ -484,9 +484,8 @@ typedef struct ALCportBackendFactory { static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); -static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type); +static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); @@ -518,15 +517,13 @@ static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUS return ALC_FALSE; } -static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(pa_device); - break; case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(pa_device); + alstr_append_range(outnames, pa_device, pa_device+sizeof(pa_device)); break; } } diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index 74d1a149..b34d7abc 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -1760,9 +1760,8 @@ typedef struct ALCpulseBackendFactory { static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory *self); static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory *self); static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory *self, ALCbackend_Type type); -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory *self, enum DevProbe type); +static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type); - DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory); @@ -1835,23 +1834,25 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN return ALC_FALSE; } -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { +#define APPEND_OUTNAME(e) do { \ + if(!alstr_empty((e)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ + VECTOR_END((e)->name)+1); \ +} while(0) case ALL_DEVICE_PROBE: ALCpulsePlayback_probeDevices(); -#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(alstr_get_cstr((e)->name)) - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST); -#undef APPEND_ALL_DEVICES_LIST + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: ALCpulseCapture_probeDevices(); -#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(alstr_get_cstr((e)->name)) - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST); -#undef APPEND_CAPTURE_DEVICE_LIST + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } } @@ -1899,7 +1900,7 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN return ALC_FALSE; } -static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type)) +static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames)) { } diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c index 8f87779b..81645096 100644 --- a/Alc/backends/qsa.c +++ b/Alc/backends/qsa.c @@ -119,6 +119,9 @@ static void deviceList(int type, vector_DevMap *devmap) if(max_cards < 0) return; +#define FREE_NAME(iter) free((iter)->name) + VECTOR_FOR_EACH(DevMap, *devmap, FREE_NAME); +#undef FREE_NAME VECTOR_RESIZE(*devmap, 0, max_cards+1); entry.name = strdup(qsaDevice); @@ -989,7 +992,7 @@ typedef struct ALCqsaBackendFactory { static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self)); static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self)); static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type); -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type); +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames); static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory); @@ -1016,33 +1019,25 @@ static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED return ALC_FALSE; } -static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch (type) { +#define APPEND_OUTNAME(e) do { \ + const char *n_ = (e)->name; \ + if(n_ && n_[0]) \ + alstr_append_range(outnames, n_, n_+strlen(n_)+1); \ +} while(0) case ALL_DEVICE_PROBE: -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); - VECTOR_RESIZE(DeviceNameMap, 0, 0); -#undef FREE_NAME - deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); -#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name) - VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE); -#undef APPEND_DEVICE + VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: -#define FREE_NAME(iter) free((iter)->name) - VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); - VECTOR_RESIZE(CaptureNameMap, 0, 0); -#undef FREE_NAME - deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); -#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name) - VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE); -#undef APPEND_DEVICE + VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } } diff --git a/Alc/backends/sdl2.c b/Alc/backends/sdl2.c index cf005024..3495e6bf 100644 --- a/Alc/backends/sdl2.c +++ b/Alc/backends/sdl2.c @@ -221,7 +221,7 @@ ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void); static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self); static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self); static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type); -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type); +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory); @@ -252,7 +252,7 @@ static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUS return ALC_FALSE; } -static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type) +static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { int num_devices, i; al_string name; @@ -263,12 +263,13 @@ static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enu AL_STRING_INIT(name); num_devices = SDL_GetNumAudioDevices(SDL_FALSE); - AppendAllDevicesList(defaultDeviceName); + alstr_append_range(outnames, defaultDeviceName, defaultDeviceName+sizeof(defaultDeviceName)); for(i = 0;i < num_devices;++i) { alstr_copy_cstr(&name, DEVNAME_PREFIX); alstr_append_cstr(&name, SDL_GetAudioDeviceName(i, SDL_FALSE)); - AppendAllDevicesList(alstr_get_cstr(name)); + if(!alstr_empty(name)) + alstr_append_range(outnames, VECTOR_BEGIN(name), VECTOR_END(name)+1); } alstr_reset(&name); } diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c index 062e6732..dd174cba 100644 --- a/Alc/backends/sndio.c +++ b/Alc/backends/sndio.c @@ -545,7 +545,7 @@ ALCbackendFactory *SndioBackendFactory_getFactory(void); static ALCboolean SndioBackendFactory_init(SndioBackendFactory *self); static DECLARE_FORWARD(SndioBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory *self, ALCbackend_Type type); -static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type); +static void SndioBackendFactory_probe(SndioBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory); @@ -568,15 +568,13 @@ static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(s return ALC_FALSE; } -static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type) +static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(sndio_device); - break; case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(sndio_device); + alstr_append_range(outnames, sndio_device, sndio_device+sizeof(sndio_device)); break; } } diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c index f1c4aeaa..71282204 100644 --- a/Alc/backends/solaris.c +++ b/Alc/backends/solaris.c @@ -302,7 +302,7 @@ ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type); +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); @@ -327,7 +327,7 @@ static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory return ALC_FALSE; } -static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { @@ -337,7 +337,7 @@ static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self struct stat buf; if(stat(solaris_driver, &buf) == 0) #endif - AppendAllDevicesList(solaris_device); + alstr_append_range(outnames, solaris_device, solaris_device+sizeof(solaris_device)); } break; diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c index 50471f6b..971a1f72 100644 --- a/Alc/backends/wasapi.c +++ b/Alc/backends/wasapi.c @@ -1919,11 +1919,6 @@ ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, } -static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(alstr_get_cstr(entry->name)); } -static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); } - typedef struct ALCwasapiBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCwasapiBackendFactory; @@ -1932,7 +1927,7 @@ typedef struct ALCwasapiBackendFactory { static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory *self); static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory *self); static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory *self, ALCbackend_Type type); -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type); +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); @@ -1989,7 +1984,7 @@ static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* return ALC_FALSE; } -static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { ThreadRequest req = { NULL, 0 }; @@ -2003,13 +1998,19 @@ static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), hr = WaitForResponse(&req); if(SUCCEEDED(hr)) switch(type) { +#define APPEND_OUTNAME(e) do { \ + if(!alstr_empty((e)->name)) \ + alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \ + VECTOR_END((e)->name)+1); \ +} while(0) case ALL_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: - VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } CloseHandle(req.FinishedEvt); req.FinishedEvt = NULL; diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c index 557c2bf2..390b2a5f 100644 --- a/Alc/backends/wave.c +++ b/Alc/backends/wave.c @@ -403,7 +403,7 @@ ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type); +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); @@ -427,12 +427,12 @@ static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUS return ALC_FALSE; } -static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { case ALL_DEVICE_PROBE: - AppendAllDevicesList(waveDevice); + alstr_append_range(outnames, waveDevice, waveDevice+sizeof(waveDevice)); break; case CAPTURE_DEVICE_PROBE: break; diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c index 2f4c65df..0d4a02b8 100644 --- a/Alc/backends/winmm.c +++ b/Alc/backends/winmm.c @@ -700,17 +700,6 @@ static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) } -static inline void AppendAllDevicesList2(const al_string *name) -{ - if(!alstr_empty(*name)) - AppendAllDevicesList(alstr_get_cstr(*name)); -} -static inline void AppendCaptureDeviceList2(const al_string *name) -{ - if(!alstr_empty(*name)) - AppendCaptureDeviceList(alstr_get_cstr(*name)); -} - typedef struct ALCwinmmBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCwinmmBackendFactory; @@ -719,7 +708,7 @@ typedef struct ALCwinmmBackendFactory { static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type); +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type, al_string *outnames); static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); @@ -749,19 +738,24 @@ static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UN return ALC_FALSE; } -static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type) +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { switch(type) { +#define APPEND_OUTNAME(n) do { \ + if(!alstr_empty(*(n))) \ + alstr_append_range(outnames, VECTOR_BEGIN(*(n)), VECTOR_END(*(n))+1); \ +} while(0) case ALL_DEVICE_PROBE: ProbePlaybackDevices(); - VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2); + VECTOR_FOR_EACH(const al_string, PlaybackDevices, APPEND_OUTNAME); break; case CAPTURE_DEVICE_PROBE: ProbeCaptureDevices(); - VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2); + VECTOR_FOR_EACH(const al_string, CaptureDevices, APPEND_OUTNAME); break; +#undef APPEND_OUTNAME } } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 74dba1ad..d25f62b2 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -856,9 +856,6 @@ void ALCcontext_ProcessUpdates(ALCcontext *context); void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends); -void AppendAllDevicesList(const ALCchar *name); -void AppendCaptureDeviceList(const ALCchar *name); - extern ALint RTPrioLevel; void SetRTPriority(void); -- cgit v1.2.3 From fa7993fe3e526e0bb69fa9cb9055ee3f501c36b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 22:32:48 -0700 Subject: Load .alsoftrc from the app bundle root on macOS Not sure what priority this should have. Currently it loads after system-level configs, and before user-level configs. --- Alc/alconfig.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Alc/alconfig.c b/Alc/alconfig.c index 5dbf59d2..c7c66653 100644 --- a/Alc/alconfig.c +++ b/Alc/alconfig.c @@ -36,6 +36,9 @@ #include #include #endif +#ifdef __APPLE__ +#include +#endif #include "alMain.h" #include "alconfig.h" @@ -478,6 +481,26 @@ void ReadALConfig(void) alstr_clear(&fname); } +#ifdef __APPLE__ + CFBundleRef mainBundle = CFBundleGetMainBundle(); + if(mainBundle) + { + unsigned char fileName[MAX_PATH]; + CFURLRef configURL; + + if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), NULL)) && + CFURLGetFileSystemRepresentation(configURL, true, fileName, sizeof(fileName))) + { + f = al_fopen((const char*)fileName, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } + } +#endif + if((str=getenv("HOME")) != NULL && *str) { alstr_copy_cstr(&fname, str); -- cgit v1.2.3 From 9054f4143424d2a7a34f6b0c79cda7a1fbf0b847 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 22:52:34 -0700 Subject: PATH_MAX not MAX_PATH --- Alc/alconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/alconfig.c b/Alc/alconfig.c index c7c66653..3d0ed140 100644 --- a/Alc/alconfig.c +++ b/Alc/alconfig.c @@ -485,7 +485,7 @@ void ReadALConfig(void) CFBundleRef mainBundle = CFBundleGetMainBundle(); if(mainBundle) { - unsigned char fileName[MAX_PATH]; + unsigned char fileName[PATH_MAX]; CFURLRef configURL; if((configURL=CFBundleCopyResourceURL(mainBundle, CFSTR(".alsoftrc"), CFSTR(""), NULL)) && -- cgit v1.2.3 From 275658b6db9129f56ca49f1a9a21ea898e0835a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 7 Sep 2018 23:01:17 -0700 Subject: Some suggested changes for iOS --- Alc/backends/coreaudio.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c index 5945834c..adb01fa6 100644 --- a/Alc/backends/coreaudio.c +++ b/Alc/backends/coreaudio.c @@ -28,7 +28,6 @@ #include "alu.h" #include "ringbuffer.h" -#include #include #include #include @@ -112,7 +111,11 @@ static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCch /* open the default output unit */ desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else desc.componentSubType = kAudioUnitSubType_DefaultOutput; +#endif desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; @@ -451,7 +454,6 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar AudioStreamBasicDescription outputFormat; // The AudioUnit output format AURenderCallbackStruct input; AudioComponentDescription desc; - AudioDeviceID inputDevice; UInt32 outputFrameCount; UInt32 propertySize; AudioObjectPropertyAddress propertyAddress; @@ -465,7 +467,11 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar return ALC_INVALID_VALUE; desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else desc.componentSubType = kAudioUnitSubType_HALOutput; +#endif desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; @@ -504,7 +510,9 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar goto error; } +#if !TARGET_OS_IOS // Get the default input device + AudioDeviceID inputDevice = kAudioDeviceUnknown; propertySize = sizeof(AudioDeviceID); propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; @@ -517,7 +525,6 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar ERR("AudioObjectGetPropertyData failed\n"); goto error; } - if(inputDevice == kAudioDeviceUnknown) { ERR("No input device found\n"); @@ -531,6 +538,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar ERR("AudioUnitSetProperty failed\n"); goto error; } +#endif // set capture callback input.inputProc = ALCcoreAudioCapture_RecordProc; -- cgit v1.2.3 From 634b13a6305be44486f0b82b5d042cb4505ee2c7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Sep 2018 02:10:35 -0700 Subject: Handle the early reflection delay separate from late refeed --- Alc/effects/reverb.c | 97 ++++++++++++++++++++++------------------------------ 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c7390843..08239565 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -949,7 +949,9 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte State); /* Calculate the max update size from the smallest relevant delay. */ - State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, State->Late.Offset[0][1]); + State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, + mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) + ); /* Determine if delay-line cross-fading is required. TODO: Add some fuzz * for the float comparisons? The math should be stable enough that the @@ -1000,22 +1002,14 @@ static inline ALfloat FadedDelayLineOut(const DelayLineI *Delay, const ALsizei o } -static inline ALvoid DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, - const ALfloat *restrict in, ALsizei count) +static inline void DelayLineIn(const DelayLineI *Delay, ALsizei offset, const ALsizei c, + const ALfloat *restrict in, ALsizei count) { ALsizei i; for(i = 0;i < count;i++) Delay->Line[(offset++)&Delay->Mask][c] = *(in++); } -static inline ALvoid DelayLineIn4Rev(const DelayLineI *Delay, ALsizei offset, const ALfloat in[NUM_LINES]) -{ - ALsizei i; - offset &= Delay->Mask; - for(i = 0;i < NUM_LINES;i++) - Delay->Line[offset][i] = in[NUM_LINES-1-i]; -} - /* Applies a scattering matrix to the 4-line (vector) input. This is used * for both the below vector all-pass model and to perform modal feed-back * delay network (FDN) mixing. @@ -1180,8 +1174,6 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; const DelayLineI main_delay = State->Delay; - ALsizei early_feedb_tap[NUM_LINES]; - ALfloat early_feedb_coeff[NUM_LINES]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei late_feed_tap; @@ -1205,35 +1197,32 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const */ VectorAllpass_Unfaded(temps, offset, mixX, mixY, todo, &State->Early.VecAp); + /* Apply a delay and bounce to generate secondary reflections, combine with + * the primary reflections and write out the result for mixing. + */ for(j = 0;j < NUM_LINES;j++) { - early_feedb_tap[j] = offset - State->Early.Offset[j][0]; - early_feedb_coeff[j] = State->Early.Coeff[j][0]; + ALint early_feedb_tap = offset - State->Early.Offset[j][0]; + ALfloat early_feedb_coeff = State->Early.Coeff[j][0]; + + for(i = 0;i < todo;i++) + out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + + temps[j][i]; + DelayLineIn(&early_delay, offset, 3-j, temps[j], todo); } + + /* Also write the result back to the main delay line for the late reverb + * stage to pick up at the appropriate time, appplying a scatter and + * bounce to improve the initial diffusion in the late reverb. + */ late_feed_tap = offset - State->LateFeedTap; for(i = 0;i < todo;i++) { ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[j] = temps[j][i]; - - /* Apply a delay and bounce to generate secondary reflections, combine - * with the primary reflections and write out the result for mixing. - */ - DelayLineIn4Rev(&early_delay, offset, f); - for(j = 0;j < NUM_LINES;j++) - { - f[j] += DelayLineOut(&early_delay, early_feedb_tap[j]++, j) * early_feedb_coeff[j]; - out[j][i] = f[j]; - } + f[j] = out[j][i]; - /* Also write the result back to the main delay line for the late - * reverb stage to pick up at the appropriate time, appplying a scatter - * and bounce to improve the initial diffusion in the late reverb. - */ VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); - offset++; } } static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, @@ -1242,10 +1231,6 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; const DelayLineI early_delay = State->Early.Delay; const DelayLineI main_delay = State->Delay; - ALsizei feedb_tap[NUM_LINES][2]; - ALfloat feedb_oldCoeff[NUM_LINES]; - ALfloat feedb_oldCoeffStep[NUM_LINES]; - ALfloat feedb_newCoeffStep[NUM_LINES]; const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei late_feed_tap; @@ -1278,35 +1263,33 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL for(j = 0;j < NUM_LINES;j++) { - feedb_tap[j][0] = offset - State->Early.Offset[j][0]; - feedb_tap[j][1] = offset - State->Early.Offset[j][1]; - feedb_oldCoeff[j] = State->Early.Coeff[j][0]; - feedb_oldCoeffStep[j] = -feedb_oldCoeff[j] / FADE_SAMPLES; - feedb_newCoeffStep[j] = State->Early.Coeff[j][1] / FADE_SAMPLES; + ALint feedb_tap0 = offset - State->Early.Offset[j][0]; + ALint feedb_tap1 = offset - State->Early.Offset[j][1]; + ALfloat feedb_oldCoeff = State->Early.Coeff[j][0]; + ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; + ALfloat feedb_newCoeffStep = State->Early.Coeff[j][1] / FADE_SAMPLES; + + fadeCount = fade * FADE_SAMPLES; + for(i = 0;i < todo;i++) + { + const ALfloat fade0 = feedb_oldCoeff + feedb_oldCoeffStep*fadeCount; + const ALfloat fade1 = feedb_newCoeffStep*fadeCount; + out[j][i] = FadedDelayLineOut(&early_delay, + feedb_tap0++, feedb_tap1++, j, fade0, fade1 + ) + temps[j][i]; + fadeCount += 1.0f; + } + DelayLineIn(&early_delay, offset, 3-j, temps[j], todo); } + late_feed_tap = offset - State->LateFeedTap; - fadeCount = fade * FADE_SAMPLES; for(i = 0;i < todo;i++) { ALfloat f[NUM_LINES]; - - for(j = 0;j < NUM_LINES;j++) - f[j] = temps[j][i]; - - DelayLineIn4Rev(&early_delay, offset, f); for(j = 0;j < NUM_LINES;j++) - { - const ALfloat fade0 = feedb_oldCoeff[j] + feedb_oldCoeffStep[j]*fadeCount; - const ALfloat fade1 = feedb_newCoeffStep[j]*fadeCount; - f[j] += FadedDelayLineOut(&early_delay, - feedb_tap[j][0]++, feedb_tap[j][1]++, j, fade0, fade1 - ); - out[j][i] = f[j]; - } - fadeCount += 1.0f; + f[j] = out[j][i]; VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); - offset++; } } -- cgit v1.2.3 From 4bdab0051fd6c7307ccfc6a07c23b95ae670fc63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Sep 2018 03:17:14 -0700 Subject: Combine identical loops into a separate function --- Alc/effects/reverb.c | 67 ++++++++++++++++------------------------------------ 1 file changed, 21 insertions(+), 46 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 08239565..0d5e5172 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1059,17 +1059,24 @@ static inline void VectorPartialScatter(ALfloat *restrict out, const ALfloat *re #define VectorScatterDelayIn(delay, o, in, xcoeff, ycoeff) \ VectorPartialScatter((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) -/* Same as above, but reverses the input. */ -static inline void VectorPartialScatterRev(ALfloat *restrict out, const ALfloat *restrict in, - const ALfloat xCoeff, const ALfloat yCoeff) +/* Utilizes the above, but reverses the input channels. */ +static inline void VectorScatterRevDelayIn(const DelayLineI *Delay, ALint offset, + const ALfloat xCoeff, const ALfloat yCoeff, + const ALfloat (*restrict in)[MAX_UPDATE_SAMPLES], + const ALsizei count) { - out[0] = xCoeff*in[3] + yCoeff*(in[0] + -in[1] + in[2] ); - out[1] = xCoeff*in[2] + yCoeff*(in[0] + in[1] + -in[3]); - out[2] = xCoeff*in[1] + yCoeff*(in[0] + -in[2] + in[3]); - out[3] = xCoeff*in[0] + yCoeff*( -in[1] + -in[2] + -in[3]); + const DelayLineI delay = *Delay; + ALsizei i, j; + + for(i = 0;i < count;++i) + { + ALfloat f[NUM_LINES]; + for(j = 0;j < NUM_LINES;j++) + f[NUM_LINES-1-j] = in[j][i]; + + VectorScatterDelayIn(&delay, offset++, f, xCoeff, yCoeff); + } } -#define VectorScatterRevDelayIn(delay, o, in, xcoeff, ycoeff) \ - VectorPartialScatterRev((delay)->Line[(o)&(delay)->Mask], in, xcoeff, ycoeff) /* This applies a Gerzon multiple-in/multiple-out (MIMO) vector all-pass * filter to the 4-line input. @@ -1216,14 +1223,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const * bounce to improve the initial diffusion in the late reverb. */ late_feed_tap = offset - State->LateFeedTap; - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[j] = out[j][i]; - - VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); - } + VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) @@ -1283,14 +1283,7 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL } late_feed_tap = offset - State->LateFeedTap; - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[j] = out[j][i]; - - VectorScatterRevDelayIn(&main_delay, late_feed_tap++, f, mixX, mixY); - } + VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } /* Applies the two T60 damping filter sections. */ @@ -1350,18 +1343,8 @@ static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsiz for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[j] = temps[j][i]; - - /* Finally, scatter and bounce the results to refeed the feedback - * buffer. - */ - VectorScatterRevDelayIn(&late_delay, offset, f, mixX, mixY); - offset++; - } + /* Finally, scatter and bounce the results to refeed the feedback buffer. */ + VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); } static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) @@ -1411,15 +1394,7 @@ static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei for(j = 0;j < NUM_LINES;j++) memcpy(out[j], temps[j], todo*sizeof(ALfloat)); - for(i = 0;i < todo;i++) - { - ALfloat f[NUM_LINES]; - for(j = 0;j < NUM_LINES;j++) - f[j] = temps[j][i]; - - VectorScatterRevDelayIn(&late_delay, offset, f, mixX, mixY); - offset++; - } + VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); } static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) -- cgit v1.2.3 From d1f8b78dd418c1527bd26da9fbf6af1f3a430079 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Sep 2018 03:19:41 -0700 Subject: Avoid a couple line count assumptions --- Alc/effects/reverb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 0d5e5172..c033e4f0 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1215,7 +1215,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const for(i = 0;i < todo;i++) out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + temps[j][i]; - DelayLineIn(&early_delay, offset, 3-j, temps[j], todo); + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); } /* Also write the result back to the main delay line for the late reverb @@ -1279,7 +1279,7 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL ) + temps[j][i]; fadeCount += 1.0f; } - DelayLineIn(&early_delay, offset, 3-j, temps[j], todo); + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); } late_feed_tap = offset - State->LateFeedTap; -- cgit v1.2.3 From b13396cce273c2154893976a9e33b87ae7e9d085 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 10 Sep 2018 13:30:20 -0700 Subject: Separate the delay line feeding from reading Since it feeds a different line than it reads, the feeding could overwrite what's subsequently read. --- Alc/effects/reverb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index c033e4f0..2a6aea35 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1215,8 +1215,9 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const for(i = 0;i < todo;i++) out[j][i] = DelayLineOut(&early_delay, early_feedb_tap++, j)*early_feedb_coeff + temps[j][i]; - DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); } + for(j = 0;j < NUM_LINES;j++) + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); /* Also write the result back to the main delay line for the late reverb * stage to pick up at the appropriate time, appplying a scatter and @@ -1279,8 +1280,9 @@ static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const AL ) + temps[j][i]; fadeCount += 1.0f; } - DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); } + for(j = 0;j < NUM_LINES;j++) + DelayLineIn(&early_delay, offset, NUM_LINES-1-j, temps[j], todo); late_feed_tap = offset - State->LateFeedTap; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); -- cgit v1.2.3 From 99737469e2678a6169462c8488b6f6080c7857b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Sep 2018 18:39:50 -0700 Subject: Ensure the max reverb update size is a multiple of 4 It's not an issue for the final mix, but if one loop has an unaligned count, the next loop will have unaligned input and output buffer targets which can crash the SSE mixers. --- Alc/effects/reverb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 2a6aea35..a32b1de4 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -948,9 +948,11 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, State); - /* Calculate the max update size from the smallest relevant delay. */ + /* Calculate the max update size from the smallest relevant delay, ensuring + * the update size is a multiple of 4 for SIMD. + */ State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, - mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) + mini(State->Early.Offset[0][1], State->Late.Offset[0][1])&~3 ); /* Determine if delay-line cross-fading is required. TODO: Add some fuzz -- cgit v1.2.3 From db452a19dafd30b72255529911087edfec0d43b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Sep 2018 19:05:49 -0700 Subject: The last reverb loop update doesn't need an aligned count. --- Alc/effects/reverb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a32b1de4..4459abf2 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -948,11 +948,9 @@ static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Conte props->Reverb.ReflectionsGain*gain, props->Reverb.LateReverbGain*gain, State); - /* Calculate the max update size from the smallest relevant delay, ensuring - * the update size is a multiple of 4 for SIMD. - */ + /* Calculate the max update size from the smallest relevant delay. */ State->MaxUpdate[1] = mini(MAX_UPDATE_SAMPLES, - mini(State->Early.Offset[0][1], State->Late.Offset[0][1])&~3 + mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) ); /* Determine if delay-line cross-fading is required. TODO: Add some fuzz @@ -1420,6 +1418,11 @@ static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, c todo = mini(todo, State->MaxUpdate[0]); } todo = mini(todo, State->MaxUpdate[1]); + /* If this is not the final update, ensure the update size is a + * multiple of 4 for the SIMD mixers. + */ + if(todo < SamplesToDo-base) + todo &= ~3; /* Convert B-Format to A-Format for processing. */ memset(afmt, 0, sizeof(*afmt)*NUM_LINES); -- cgit v1.2.3 From a6734c7a91b1e2f2ef19ba163ceb2cb14571a9dd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Sep 2018 14:53:35 -0700 Subject: Check the effect slot list size only when there's no free entries The list can contain (reuable) NULL entries, so the max - current_size doesn't indicate how many can be allocated. --- OpenAL32/alAuxEffectSlot.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index 815a8d5a..b293b6a5 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -122,12 +122,6 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo LockEffectSlotList(context); device = context->Device; - if(device->AuxiliaryEffectSlotMax - VECTOR_SIZE(context->EffectSlotList) < (ALuint)n) - { - UnlockEffectSlotList(context); - SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, "Exceeding %u auxiliary effect slot limit", - device->AuxiliaryEffectSlotMax); - } for(cur = 0;cur < n;cur++) { ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList); @@ -142,6 +136,13 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo } if(iter == end) { + if(device->AuxiliaryEffectSlotMax == VECTOR_SIZE(context->EffectSlotList)) + { + UnlockEffectSlotList(context); + alDeleteAuxiliaryEffectSlots(cur, effectslots); + SETERR_GOTO(context, AL_OUT_OF_MEMORY, done, + "Exceeding %u auxiliary effect slot limit", device->AuxiliaryEffectSlotMax); + } VECTOR_PUSH_BACK(context->EffectSlotList, NULL); iter = &VECTOR_BACK(context->EffectSlotList); } -- cgit v1.2.3 From 8bacb5dfb8ef910586fcf5b5cd89526ec81061e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Sep 2018 17:38:55 -0700 Subject: Fix buffer queue mixing logic In particular, the source sample position was reduced by the size of the next buffer list item when one is completed, rather than the size of the one it just completed. --- Alc/mixvoice.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 2d935ce5..276d5bd9 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -487,6 +487,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize while(tmpiter && SrcBufferSize > FilledAmt) { ALsizei SizeToDo = SrcBufferSize - FilledAmt; + ALsizei CompLen = 0; ALsizei i; for(i = 0;i < tmpiter->num_buffers;i++) @@ -499,23 +500,24 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize const ALubyte *Data = ALBuffer->data; Data += (pos*NumChannels + chan)*SampleSize; - DataSize = minu(SizeToDo, DataSize - pos); + DataSize = mini(SizeToDo, DataSize - pos); + CompLen = maxi(CompLen, DataSize); + LoadSamples(&SrcData[FilledAmt], Data, NumChannels, ALBuffer->FmtType, DataSize); } } - if(pos > tmpiter->max_samples) + if(UNLIKELY(!CompLen)) pos -= tmpiter->max_samples; else { - FilledAmt += tmpiter->max_samples - pos; + FilledAmt += CompLen; + if(SrcBufferSize <= FilledAmt) + break; pos = 0; } - if(SrcBufferSize > FilledAmt) - { - tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); - if(!tmpiter) tmpiter = BufferLoopItem; - } + tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire); + if(!tmpiter) tmpiter = BufferLoopItem; } } @@ -729,8 +731,10 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize if(BufferListItem->max_samples > DataPosInt) break; + DataPosInt -= BufferListItem->max_samples; + buffers_done += BufferListItem->num_buffers; - BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire); + BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_relaxed); if(!BufferListItem && !(BufferListItem=BufferLoopItem)) { isplaying = false; @@ -738,8 +742,6 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize DataPosFrac = 0; break; } - - DataPosInt -= BufferListItem->max_samples; } } while(isplaying && OutPos < SamplesToDo); -- cgit v1.2.3 From 7f4441ffbe072c45ea5a141fc126d81095fe7fca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Sep 2018 01:43:02 -0700 Subject: Handle the bsinc C resampler like the others --- Alc/ALu.c | 2 +- Alc/mixer/mixer_c.c | 79 ++++++++++++++++++++++---------------------------- Alc/mixer/mixer_neon.c | 2 +- Alc/mixer/mixer_sse.c | 2 +- OpenAL32/Include/alu.h | 2 +- 5 files changed, 38 insertions(+), 49 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index e5203d6e..182b226f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -357,7 +357,7 @@ void BsincPrepare(const ALuint increment, BsincState *state, const BSincTable *t state->sf = sf; state->m = table->m[si]; - state->l = -((state->m/2) - 1); + state->l = (state->m/2) - 1; state->filter = table->Tab + table->filterOffset[si]; } diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 25149e00..2dcd6c6b 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -9,12 +9,37 @@ #include "defs.h" -static inline ALfloat do_point(const ALfloat *restrict vals, ALsizei UNUSED(frac)) +static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei UNUSED(frac)) { return vals[0]; } -static inline ALfloat do_lerp(const ALfloat *restrict vals, ALsizei frac) +static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat do_cubic(const ALfloat *restrict vals, ALsizei frac) +static inline ALfloat do_cubic(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei frac) { return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); } +static inline ALfloat do_bsinc(const InterpState *state, const ALfloat *restrict vals, ALsizei frac) +{ + const ALfloat *fil, *scd, *phd, *spd; + ALsizei j_f, pi; + ALfloat pf, r; + + ASSUME(state->bsinc.m > 0); + + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<bsinc.filter + state->bsinc.m*pi*4, 16); + scd = ASSUME_ALIGNED(fil + state->bsinc.m, 16); + phd = ASSUME_ALIGNED(scd + state->bsinc.m, 16); + spd = ASSUME_ALIGNED(phd + state->bsinc.m, 16); + + // Apply the scale and phase interpolated filter. + r = 0.0f; + for(j_f = 0;j_f < state->bsinc.m;j_f++) + r += (fil[j_f] + state->bsinc.sf*scd[j_f] + pf*(phd[j_f] + state->bsinc.sf*spd[j_f])) * vals[j_f]; + return r; +} const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment), @@ -30,16 +55,19 @@ const ALfloat *Resample_copy_C(const InterpState* UNUSED(state), } #define DECL_TEMPLATE(Tag, Sampler, O) \ -const ALfloat *Resample_##Tag##_C(const InterpState* UNUSED(state), \ +const ALfloat *Resample_##Tag##_C(const InterpState *state, \ const ALfloat *restrict src, ALsizei frac, ALint increment, \ ALfloat *restrict dst, ALsizei numsamples) \ { \ + const InterpState istate = *state; \ ALsizei i; \ \ + ASSUME(numsamples > 0); \ + \ src -= O; \ for(i = 0;i < numsamples;i++) \ { \ - dst[i] = Sampler(src, frac); \ + dst[i] = Sampler(&istate, src, frac); \ \ frac += increment; \ src += frac>>FRACTIONBITS; \ @@ -51,49 +79,10 @@ const ALfloat *Resample_##Tag##_C(const InterpState* UNUSED(state), \ DECL_TEMPLATE(point, do_point, 0) DECL_TEMPLATE(lerp, do_lerp, 0) DECL_TEMPLATE(cubic, do_cubic, 1) +DECL_TEMPLATE(bsinc, do_bsinc, istate.bsinc.l) #undef DECL_TEMPLATE -const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, - ALsizei frac, ALint increment, ALfloat *restrict dst, - ALsizei dstlen) -{ - const ALfloat *fil, *scd, *phd, *spd; - const ALfloat *const filter = state->bsinc.filter; - const ALfloat sf = state->bsinc.sf; - const ALsizei m = state->bsinc.m; - ALsizei j_f, pi, i; - ALfloat pf, r; - - ASSUME(m > 0); - - src += state->bsinc.l; - for(i = 0;i < dstlen;i++) - { - // Calculate the phase index and factor. -#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) - pi = frac >> FRAC_PHASE_BITDIFF; - pf = (frac & ((1<>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} - static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2], const ALsizei IrSize, diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index db61fd41..0b8996fd 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -82,7 +82,7 @@ const ALfloat *Resample_bsinc_Neon(const InterpState *state, ASSUME(m > 0); ASSUME(dstlen > 0); - src += state->bsinc.l; + src -= state->bsinc.l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index d7d54993..78cf26f1 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -27,7 +27,7 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr ASSUME(m > 0); ASSUME(dstlen > 0); - src += state->bsinc.l; + src -= state->bsinc.l; for(i = 0;i < dstlen;i++) { // Calculate the phase index and factor. diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index c3e6ba12..8c395ded 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -74,7 +74,7 @@ extern enum Resampler ResamplerDefault; typedef struct BsincState { ALfloat sf; /* Scale interpolation factor. */ ALsizei m; /* Coefficient count. */ - ALint l; /* Left coefficient offset. */ + ALsizei l; /* Left coefficient offset. */ /* Filter coefficients, followed by the scale, phase, and scale-phase * delta coefficients. Starting at phase index 0, each subsequent phase * index follows contiguously. -- cgit v1.2.3 From b77e6096b8ed26b8fee24a18820c0592eeee87b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Sep 2018 22:49:52 -0700 Subject: Fix some potential race conditions with OpenSL For playback, increment the ring buffer's write pointer before queueing audio, to handle cases where the callback is invoked, advancing the read pointer, before the write pointer is advanced. For capture, limit the number of re-queued chunks to the number of fully read chunks. --- Alc/backends/opensl.c | 104 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 50fe77d8..9815b390 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -206,6 +206,9 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self) self->mEngineObj = NULL; self->mEngine = NULL; + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + alsem_destroy(&self->mSem); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); @@ -251,19 +254,16 @@ static int ALCopenslPlayback_mixerProc(void *arg) result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player); PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY"); } + + ALCopenslPlayback_lock(self); if(SL_RESULT_SUCCESS != result) - { - ALCopenslPlayback_lock(self); aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result); - ALCopenslPlayback_unlock(self); - return 1; - } - ALCopenslPlayback_lock(self); - while(!ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && + while(SL_RESULT_SUCCESS == result && + !ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - size_t todo, len0, len1; + size_t todo; if(ll_ringbuffer_write_space(self->mRing) == 0) { @@ -292,34 +292,33 @@ static int ALCopenslPlayback_mixerProc(void *arg) } ll_ringbuffer_get_write_vector(self->mRing, data); - todo = data[0].len+data[1].len; - - len0 = minu(todo, data[0].len); - len1 = minu(todo-len0, data[1].len); - aluMixData(device, data[0].buf, len0*device->UpdateSize); - for(size_t i = 0;i < len0;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS == result) - ll_ringbuffer_write_advance(self->mRing, 1); + aluMixData(device, data[0].buf, data[0].len*device->UpdateSize); + if(data[1].len > 0) + aluMixData(device, data[1].buf, data[1].len*device->UpdateSize); - data[0].buf += device->UpdateSize*self->mFrameSize; - } + todo = data[0].len+data[1].len; + ll_ringbuffer_write_advance(self->mRing, todo); - if(len1 > 0) + for(size_t i = 0;i < todo;i++) { - aluMixData(device, data[1].buf, len1*device->UpdateSize); - for(size_t i = 0;i < len1;i++) + if(!data[0].len) { - result = VCALL(bufferQueue,Enqueue)(data[1].buf, device->UpdateSize*self->mFrameSize); - PRINTERR(result, "bufferQueue->Enqueue"); - if(SL_RESULT_SUCCESS == result) - ll_ringbuffer_write_advance(self->mRing, 1); + data[0] = data[1]; + data[1].buf = NULL; + data[1].len = 0; + } - data[1].buf += device->UpdateSize*self->mFrameSize; + result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) + { + aluHandleDisconnect(device, "Failed to queue audio: 0x%08x", result); + break; } + + data[0].len--; + data[0].buf += device->UpdateSize*self->mFrameSize; } } ALCopenslPlayback_unlock(self); @@ -398,6 +397,9 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) VCALL0(self->mBufferQueueObj,Destroy)(); self->mBufferQueueObj = NULL; + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + sampleRate = device->Frequency; if(!(device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL) { @@ -546,6 +548,18 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE); PRINTERR(result, "bufferQueue->Realize"); } + if(SL_RESULT_SUCCESS == result) + { + self->mRing = ll_ringbuffer_create(device->NumUpdates, + self->mFrameSize*device->UpdateSize, true + ); + if(!self->mRing) + { + ERR("Out of memory allocating ring buffer %ux%u %u\n", device->UpdateSize, + device->NumUpdates, self->mFrameSize); + result = SL_RESULT_MEMORY_FAILURE; + } + } if(SL_RESULT_SUCCESS != result) { @@ -561,13 +575,10 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self) { - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; SLAndroidSimpleBufferQueueItf bufferQueue; SLresult result; - ll_ringbuffer_free(self->mRing); - self->mRing = ll_ringbuffer_create(device->NumUpdates, self->mFrameSize*device->UpdateSize, - true); + ll_ringbuffer_reset(self->mRing); result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -634,9 +645,6 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self) } while(SL_RESULT_SUCCESS == result && state.count > 0); PRINTERR(result, "bufferQueue->GetState"); } - - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; } static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self) @@ -713,9 +721,6 @@ static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device static void ALCopenslCapture_Destruct(ALCopenslCapture *self) { - ll_ringbuffer_free(self->mRing); - self->mRing = NULL; - if(self->mRecordObj != NULL) VCALL0(self->mRecordObj,Destroy)(); self->mRecordObj = NULL; @@ -725,6 +730,9 @@ static void ALCopenslCapture_Destruct(ALCopenslCapture *self) self->mEngineObj = NULL; self->mEngine = NULL; + ll_ringbuffer_free(self->mRing); + self->mRing = NULL; + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); } @@ -843,8 +851,9 @@ static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name if(SL_RESULT_SUCCESS == result) { - self->mRing = ll_ringbuffer_create(device->NumUpdates, device->UpdateSize*self->mFrameSize, - false); + self->mRing = ll_ringbuffer_create(device->NumUpdates, + device->UpdateSize*self->mFrameSize, false + ); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); @@ -972,14 +981,25 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * i += rem; } + if(!advance) + return ALC_NO_ERROR; ll_ringbuffer_read_advance(self->mRing, advance); result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue); PRINTERR(result, "recordObj->GetInterface"); - /* Enqueue any newly-writable chunks in the ring buffer. */ + /* Enqueue any newly-writable chunks in the ring buffer. Limit the number + * of enqueued chunks to the number of fully read chunks. + */ ll_ringbuffer_get_write_vector(self->mRing, data); + if(data[0].len > advance) + { + data[0].len = advance; + data[1].len = 0; + } + else if(data[1].len > advance-data[0].len) + data[1].len = advance-data[0].len; for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) { result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); -- cgit v1.2.3 From 952ff84b994b72ec39e97e2441a422085884932a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Sep 2018 23:43:23 -0700 Subject: Properly queue buffers for OpenSL capture --- Alc/backends/opensl.c | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index 9815b390..aa2a1a6e 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -950,14 +950,16 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * SLAndroidSimpleBufferQueueItf bufferQueue; ll_ringbuffer_data_t data[2]; SLresult result; - size_t advance; ALCuint i; + result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &bufferQueue); + PRINTERR(result, "recordObj->GetInterface"); + /* Read the desired samples from the ring buffer then advance its read * pointer. */ ll_ringbuffer_get_read_vector(self->mRing, data); - advance = 0; for(i = 0;i < samples;) { ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset); @@ -970,7 +972,11 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * { /* Finished a chunk, reset the offset and advance the read pointer. */ self->mSplOffset = 0; - advance++; + + ll_ringbuffer_read_advance(self->mRing, 1); + result = VCALL(bufferQueue,Enqueue)(data[0].buf, chunk_size); + PRINTERR(result, "bufferQueue->Enqueue"); + if(SL_RESULT_SUCCESS != result) break; data[0].len--; if(!data[0].len) @@ -981,35 +987,6 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid * i += rem; } - if(!advance) - return ALC_NO_ERROR; - ll_ringbuffer_read_advance(self->mRing, advance); - - result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &bufferQueue); - PRINTERR(result, "recordObj->GetInterface"); - - /* Enqueue any newly-writable chunks in the ring buffer. Limit the number - * of enqueued chunks to the number of fully read chunks. - */ - ll_ringbuffer_get_write_vector(self->mRing, data); - if(data[0].len > advance) - { - data[0].len = advance; - data[1].len = 0; - } - else if(data[1].len > advance-data[0].len) - data[1].len = advance-data[0].len; - for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } - for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++) - { - result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size); - PRINTERR(result, "bufferQueue->Enqueue"); - } if(SL_RESULT_SUCCESS != result) { -- cgit v1.2.3 From 9ef4dd42474c3ecc266362df47fd5a6cca8dcbb4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Sep 2018 19:08:13 -0700 Subject: Use ALsizei for the source resample position --- Alc/mixer/defs.h | 2 +- Alc/mixer/mixer_neon.c | 3 +-- Alc/mixer/mixer_sse2.c | 3 +-- Alc/mixer/mixer_sse41.c | 3 +-- Alc/mixvoice.c | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Alc/mixer/defs.h b/Alc/mixer/defs.h index fe19cef4..8f6e3755 100644 --- a/Alc/mixer/defs.h +++ b/Alc/mixer/defs.h @@ -62,7 +62,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, ALsizei InPos, ALsizei BufferSize); /* SSE resamplers */ -inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size) +inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALsizei *restrict pos_arr, ALsizei size) { ALsizei i; diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index 0b8996fd..ca274b07 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -17,8 +17,7 @@ const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state), const int32x4_t increment4 = vdupq_n_s32(increment*4); const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE); const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK); - alignas(16) ALint pos_[4]; - alignas(16) ALsizei frac_[4]; + alignas(16) ALsizei pos_[4], frac_[4]; int32x4_t pos4, frac4; ALsizei todo, pos, i; diff --git a/Alc/mixer/mixer_sse2.c b/Alc/mixer/mixer_sse2.c index 629e0ec7..9cbaeb0a 100644 --- a/Alc/mixer/mixer_sse2.c +++ b/Alc/mixer/mixer_sse2.c @@ -34,8 +34,7 @@ const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state), const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - ALint pos_[4]; - ALsizei frac_[4]; + alignas(16) ALsizei pos_[4], frac_[4]; __m128i frac4, pos4; ALsizei todo, pos, i; diff --git a/Alc/mixer/mixer_sse41.c b/Alc/mixer/mixer_sse41.c index 128acadf..e92a3dd0 100644 --- a/Alc/mixer/mixer_sse41.c +++ b/Alc/mixer/mixer_sse41.c @@ -35,8 +35,7 @@ const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state), const __m128i increment4 = _mm_set1_epi32(increment*4); const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - ALint pos_[4]; - ALsizei frac_[4]; + alignas(16) ALsizei pos_[4], frac_[4]; __m128i frac4, pos4; ALsizei todo, pos, i; diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index 276d5bd9..a2365886 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -45,7 +45,7 @@ static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); -extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size); +extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALsizei *restrict pos_arr, ALsizei size); /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */ -- cgit v1.2.3 From 48b7745a49296bd70e16fbf8eeed2d47c84e72a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Sep 2018 19:53:25 -0700 Subject: Add macros for commonly used square roots --- Alc/ALu.c | 16 +++++++--------- Alc/effects/reverb.c | 13 ++++++------- Alc/panning.c | 6 +++--- common/math_defs.h | 6 ++++++ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 182b226f..ab7a7219 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -656,14 +656,14 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ - ComputeDryPanGains(&Device->Dry, coeffs, DryGain*1.414213562f, + ComputeDryPanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, voice->Direct.Params[0].Gains.Target); for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; if(Slot) - ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, - coeffs, WetGain[i]*1.414213562f, voice->Send[i].Params[0].Gains.Target + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs, + WetGain[i]*SQRTF_2, voice->Send[i].Params[0].Gains.Target ); } } @@ -672,8 +672,6 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo /* Local B-Format sources have their XYZ channels rotated according * to the orientation. */ - const ALfloat sqrt_2 = sqrtf(2.0f); - const ALfloat sqrt_3 = sqrtf(3.0f); ALfloat N[3], V[3], U[3]; aluMatrixf matrix; @@ -717,10 +715,10 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo */ aluMatrixfSet(&matrix, // ACN0 ACN1 ACN2 ACN3 - sqrt_2, 0.0f, 0.0f, 0.0f, // Ambi W - 0.0f, -N[0]*sqrt_3, N[1]*sqrt_3, -N[2]*sqrt_3, // Ambi X - 0.0f, U[0]*sqrt_3, -U[1]*sqrt_3, U[2]*sqrt_3, // Ambi Y - 0.0f, -V[0]*sqrt_3, V[1]*sqrt_3, -V[2]*sqrt_3 // Ambi Z + SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W + 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X + 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y + 0.0f, -V[0]*SQRTF_3, V[1]*SQRTF_3, -V[2]*SQRTF_3 // Ambi Z ); voice->Direct.Buffer = Device->FOAOut.Buffer; diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 4459abf2..6fdd53cd 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -802,7 +802,6 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co */ static aluMatrixf GetTransformFromVector(const ALfloat *vec) { - const ALfloat sqrt_3 = 1.732050808f; aluMatrixf focus; ALfloat norm[3]; ALfloat mag; @@ -817,9 +816,9 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) mag = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); if(mag > 1.0f) { - norm[0] = vec[0] / mag * -sqrt_3; - norm[1] = vec[1] / mag * sqrt_3; - norm[2] = vec[2] / mag * sqrt_3; + norm[0] = vec[0] / mag * -SQRTF_3; + norm[1] = vec[1] / mag * SQRTF_3; + norm[2] = vec[2] / mag * SQRTF_3; mag = 1.0f; } else @@ -828,9 +827,9 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) * term. There's no need to renormalize the magnitude since it would * just be reapplied in the matrix. */ - norm[0] = vec[0] * -sqrt_3; - norm[1] = vec[1] * sqrt_3; - norm[2] = vec[2] * sqrt_3; + norm[0] = vec[0] * -SQRTF_3; + norm[1] = vec[1] * SQRTF_3; + norm[2] = vec[2] * SQRTF_3; } aluMatrixfSet(&focus, diff --git a/Alc/panning.c b/Alc/panning.c index d114295b..ce0550cf 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -75,9 +75,9 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf /* Zeroth-order */ coeffs[0] = 1.0f; /* ACN 0 = 1 */ /* First-order */ - coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ - coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ - coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ + coeffs[1] = SQRTF_3 * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = SQRTF_3 * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = SQRTF_3 * x; /* ACN 3 = sqrt(3) * X */ /* Second-order */ coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ diff --git a/common/math_defs.h b/common/math_defs.h index 99cc62ec..aa79b695 100644 --- a/common/math_defs.h +++ b/common/math_defs.h @@ -18,6 +18,12 @@ #define FLT_EPSILON (1.19209290e-07f) #endif +#define SQRT_2 1.41421356237309504880 +#define SQRT_3 1.73205080756887719318 + +#define SQRTF_2 1.41421356237309504880f +#define SQRTF_3 1.73205080756887719318f + #ifndef HUGE_VALF static const union msvc_inf_hack { unsigned char b[4]; -- cgit v1.2.3 From 6eb980d1b23bec90226b2012a0346f7be8407fdd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Sep 2018 21:09:19 -0700 Subject: Remove a couple duplicate functions --- Alc/ALu.c | 2 +- Alc/panning.c | 29 ++--------------------------- OpenAL32/Include/alu.h | 12 +++++------- 3 files changed, 8 insertions(+), 35 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index ab7a7219..0d0dab12 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -732,7 +732,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo if(Slot) { for(c = 0;c < num_channels;c++) - ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, + ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c], WetGain[i], voice->Send[i].Params[c].Gains.Target ); } diff --git a/Alc/panning.c b/Alc/panning.c index ce0550cf..6bd42709 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -152,7 +152,7 @@ void CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALf } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALsizei i, j; @@ -167,7 +167,7 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL gains[i] = 0.0f; } -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { ALsizei i; @@ -177,31 +177,6 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con gains[i] = 0.0f; } -void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i, j; - - for(i = 0;i < numchans;i++) - { - float gain = 0.0f; - for(j = 0;j < 4;j++) - gain += chancoeffs[i][j] * mtx[j]; - gains[i] = clampf(gain, 0.0f, 1.0f) * ingain; - } - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - -void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - ALsizei i; - - for(i = 0;i < numchans;i++) - gains[i] = chanmap[i].Scale * mtx[chanmap[i].Index] * ingain; - for(;i < MAX_OUTPUT_CHANNELS;i++) - gains[i] = 0.0f; -} - static inline const char *GetLabelFromChannel(enum Channel channel) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8c395ded..8ee4edfe 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -491,8 +491,9 @@ inline float ScaleAzimuthFront(float azimuth, float scale) } -void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); + /** * ComputeDryPanGains * @@ -507,9 +508,6 @@ inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX else ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains); } - -void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** * ComputeFirstOrderGains * @@ -520,9 +518,9 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { if(foa->CoeffCount > 0) - ComputeFirstOrderGainsMC(foa->Ambi.Coeffs, foa->NumChannels, mtx, ingain, gains); + ComputePanningGainsMC(foa->Ambi.Coeffs, foa->NumChannels, 4, mtx, ingain, gains); else - ComputeFirstOrderGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains); + ComputePanningGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains); } -- cgit v1.2.3 From ea95a8adef036602770546fb14bcaf713ec40b8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Sep 2018 21:31:46 -0700 Subject: Combine nearly-duplicate structures --- Alc/ALu.c | 6 +++--- Alc/panning.c | 10 +++++----- OpenAL32/Include/alMain.h | 19 +++++-------------- OpenAL32/Include/alu.h | 4 ++-- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 0d0dab12..4d966ba3 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -644,7 +644,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo NfcFilterAdjust(&voice->Direct.Params[0].NFCtrlFilter, w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; voice->Flags |= VOICE_HAS_NFC; } @@ -888,7 +888,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; voice->Flags |= VOICE_HAS_NFC; } @@ -949,7 +949,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo NfcFilterAdjust(&voice->Direct.Params[c].NFCtrlFilter, w0); for(i = 0;i < MAX_AMBI_ORDER+1;i++) - voice->Direct.ChannelsPerOrder[i] = Device->Dry.NumChannelsPerOrder[i]; + voice->Direct.ChannelsPerOrder[i] = Device->NumChannelsPerOrder[i]; voice->Flags |= VOICE_HAS_NFC; } diff --git a/Alc/panning.c b/Alc/panning.c index 6bd42709..0ddfd07e 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -41,8 +41,8 @@ extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -extern inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputeDryPanGains(const MixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputeFirstOrderGains(const MixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { @@ -396,9 +396,9 @@ static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei orde TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist); for(i = 0;i < order+1;i++) - device->Dry.NumChannelsPerOrder[i] = chans_per_order[i]; + device->NumChannelsPerOrder[i] = chans_per_order[i]; for(;i < MAX_AMBI_ORDER+1;i++) - device->Dry.NumChannelsPerOrder[i] = 0; + device->NumChannelsPerOrder[i] = 0; } } @@ -943,7 +943,7 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; for(i = 0;i < MAX_AMBI_ORDER+1;i++) - device->Dry.NumChannelsPerOrder[i] = 0; + device->NumChannelsPerOrder[i] = 0; device->AvgSpeakerDist = 0.0f; memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay)); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index d25f62b2..f90108d6 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -582,7 +582,7 @@ typedef struct DistanceComp { */ #define BUFFERSIZE 2048 -typedef struct DryMixParams { +typedef struct MixParams { AmbiConfig Ambi; /* Number of coefficients in each Ambi.Coeffs to mix together (4 for first- * order, 9 for second-order, etc). If the count is 0, Ambi.Map is used @@ -592,17 +592,7 @@ typedef struct DryMixParams { ALfloat (*Buffer)[BUFFERSIZE]; ALsizei NumChannels; - ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; -} DryMixParams; - -typedef struct BFMixParams { - AmbiConfig Ambi; - /* Will only be 4 or 0. */ - ALsizei CoeffCount; - - ALfloat (*Buffer)[BUFFERSIZE]; - ALsizei NumChannels; -} BFMixParams; +} MixParams; typedef struct RealMixParams { enum Channel ChannelName[MAX_OUTPUT_CHANNELS]; @@ -691,10 +681,11 @@ struct ALCdevice_struct { alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; /* The "dry" path corresponds to the main output. */ - DryMixParams Dry; + MixParams Dry; + ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]; /* First-order ambisonics output, to be upsampled to the dry buffer if different. */ - BFMixParams FOAOut; + MixParams FOAOut; /* "Real" output, which will be written to the device buffer. May alias the * dry buffer. diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 8ee4edfe..ac0c866f 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -500,7 +500,7 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, con * Computes panning gains using the given channel decoder coefficients and the * pre-calculated direction or angle coefficients. */ -inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +inline void ComputeDryPanGains(const MixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { if(dry->CoeffCount > 0) ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, @@ -515,7 +515,7 @@ inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX * a 1x4 'slice' of a transform matrix for the input channel, used to scale and * orient the sound samples. */ -inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +inline void ComputeFirstOrderGains(const MixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { if(foa->CoeffCount > 0) ComputePanningGainsMC(foa->Ambi.Coeffs, foa->NumChannels, 4, mtx, ingain, gains); -- cgit v1.2.3 From 5c6b8eda4f4defc85faf76edb2772f6b340c7c1a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 19 Sep 2018 22:18:46 -0700 Subject: Remove another duplicate function --- Alc/ALu.c | 16 +++++++--------- Alc/bformatdec.c | 2 +- Alc/effects/autowah.c | 4 ++-- Alc/effects/chorus.c | 4 ++-- Alc/effects/compressor.c | 3 +-- Alc/effects/dedicated.c | 2 +- Alc/effects/distortion.c | 3 +-- Alc/effects/echo.c | 4 ++-- Alc/effects/equalizer.c | 18 +++++++++--------- Alc/effects/fshifter.c | 2 +- Alc/effects/modulator.c | 4 ++-- Alc/effects/pshifter.c | 2 +- Alc/effects/reverb.c | 8 ++++---- Alc/panning.c | 3 +-- OpenAL32/Include/alAuxEffectSlot.h | 4 ++-- OpenAL32/Include/alu.h | 22 +++++----------------- 16 files changed, 42 insertions(+), 59 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 4d966ba3..2af32439 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -656,7 +656,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo Elev, Spread, coeffs); /* NOTE: W needs to be scaled by sqrt(2) due to FuMa normalization. */ - ComputeDryPanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, + ComputePanGains(&Device->Dry, coeffs, DryGain*SQRTF_2, voice->Direct.Params[0].Gains.Target); for(i = 0;i < NumSends;i++) { @@ -724,8 +724,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo voice->Direct.Buffer = Device->FOAOut.Buffer; voice->Direct.Channels = Device->FOAOut.NumChannels; for(c = 0;c < num_channels;c++) - ComputeFirstOrderGains(&Device->FOAOut, matrix.m[c], DryGain, - voice->Direct.Params[c].Gains.Target); + ComputePanGains(&Device->FOAOut, matrix.m[c], DryGain, + voice->Direct.Params[c].Gains.Target); for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; @@ -911,9 +911,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo continue; } - ComputeDryPanGains(&Device->Dry, - coeffs, DryGain * downmix_gain, voice->Direct.Params[c].Gains.Target - ); + ComputePanGains(&Device->Dry, coeffs, DryGain * downmix_gain, + voice->Direct.Params[c].Gains.Target); } for(i = 0;i < NumSends;i++) @@ -974,9 +973,8 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo chans[c].elevation, Spread, coeffs ); - ComputeDryPanGains(&Device->Dry, - coeffs, DryGain, voice->Direct.Params[c].Gains.Target - ); + ComputePanGains(&Device->Dry, coeffs, DryGain, + voice->Direct.Params[c].Gains.Target); for(i = 0;i < NumSends;i++) { const ALeffectslot *Slot = SendSlots[i]; diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c index 58898083..5233d06f 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.c @@ -438,7 +438,7 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat { ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f }; CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[k]); + ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]); } /* Combine the matrices that do the in->virt and virt->out conversions diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c index 28b366b1..ba1180ef 100644 --- a/Alc/effects/autowah.c +++ b/Alc/effects/autowah.c @@ -130,8 +130,8 @@ static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *con STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Chans[i].TargetGains); + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); } static ALvoid ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c index ffb2b572..f2861cf5 100644 --- a/Alc/effects/chorus.c +++ b/Alc/effects/chorus.c @@ -149,9 +149,9 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte /* Gains for left and right sides */ CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target); CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); + ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target); phase = props->Chorus.Phase; rate = props->Chorus.Rate; diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c index af60777a..2b4a76b0 100644 --- a/Alc/effects/compressor.c +++ b/Alc/effects/compressor.c @@ -99,8 +99,7 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontex STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < 4;i++) - ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Gain[i]); + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, state->Gain[i]); } static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c index 62a3894f..0e1fd389 100644 --- a/Alc/effects/dedicated.c +++ b/Alc/effects/dedicated.c @@ -102,7 +102,7 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels; - ComputeDryPanGains(&device->Dry, coeffs, Gain, state->TargetGains); + ComputePanGains(&device->Dry, coeffs, Gain, state->TargetGains); } } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index f4e9969c..de8da4fe 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -104,8 +104,7 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex ); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * props->Distortion.Gain, - state->Gain); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.Gain, state->Gain); } static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index 676b17e8..4570fcb1 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -141,11 +141,11 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, /* First tap panning */ CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target); /* Second tap panning */ CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target); } static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 8ff56fb5..17106127 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -76,12 +76,12 @@ typedef struct ALequalizerState { DERIVE_FROM_TYPE(ALeffectState); struct { + /* Effect parameters */ + BiquadFilter filter[4]; + /* Effect gains for each channel */ ALfloat CurrentGains[MAX_OUTPUT_CHANNELS]; ALfloat TargetGains[MAX_OUTPUT_CHANNELS]; - - /* Effect parameters */ - BiquadFilter filter[4]; } Chans[MAX_EFFECT_CHANNELS]; ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; @@ -128,12 +128,6 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext ALfloat gain, f0norm; ALuint i; - STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; - STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; - for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Chans[i].TargetGains); - /* Calculate coefficients for the each type of filter. Note that the shelf * filters' gain is for the reference frequency, which is the centerpoint * of the transition band. @@ -174,6 +168,12 @@ static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]); BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]); } + + STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; + STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; + for(i = 0;i < MAX_EFFECT_CHANNELS;i++) + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); } static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/fshifter.c b/Alc/effects/fshifter.c index 5aa08453..7d72472a 100644 --- a/Alc/effects/fshifter.c +++ b/Alc/effects/fshifter.c @@ -144,7 +144,7 @@ static ALvoid ALfshifterState_update(ALfshifterState *state, const ALCcontext *c } CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } static ALvoid ALfshifterState_process(ALfshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c index 9855b1b8..e368adb8 100644 --- a/Alc/effects/modulator.c +++ b/Alc/effects/modulator.c @@ -158,8 +158,8 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer; STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels; for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i], - slot->Params.Gain, state->Chans[i].TargetGains); + ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain, + state->Chans[i].TargetGains); } static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c index f27c413c..ed18e9a8 100644 --- a/Alc/effects/pshifter.c +++ b/Alc/effects/pshifter.c @@ -208,7 +208,7 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE); CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs); - ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); + ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains); } static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 6fdd53cd..a5de52f9 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -868,15 +868,15 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection MATRIX_MULT(transform, rot, A2B); memset(&State->Early.PanGain, 0, sizeof(State->Early.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], earlyGain, - State->Early.PanGain[i]); + ComputePanGains(&Device->FOAOut, transform.m[i], earlyGain, + State->Early.PanGain[i]); rot = GetTransformFromVector(LateReverbPan); MATRIX_MULT(transform, rot, A2B); memset(&State->Late.PanGain, 0, sizeof(State->Late.PanGain)); for(i = 0;i < MAX_EFFECT_CHANNELS;i++) - ComputeFirstOrderGains(&Device->FOAOut, transform.m[i], lateGain, - State->Late.PanGain[i]); + ComputePanGains(&Device->FOAOut, transform.m[i], lateGain, + State->Late.PanGain[i]); #undef MATRIX_MULT } diff --git a/Alc/panning.c b/Alc/panning.c index 0ddfd07e..2c0f3bf2 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -41,8 +41,7 @@ extern inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]); extern inline float ScaleAzimuthFront(float azimuth, float scale); -extern inline void ComputeDryPanGains(const MixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); -extern inline void ComputeFirstOrderGains(const MixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); +extern inline void ComputePanGains(const MixParams *dry, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = { diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h index c4d662f1..03ee97d6 100644 --- a/OpenAL32/Include/alAuxEffectSlot.h +++ b/OpenAL32/Include/alAuxEffectSlot.h @@ -145,8 +145,8 @@ typedef struct ALeffectslot { * * Channel 3 is OpenAL -Z * sqrt(3) * Consequently, effects that only want to work with mono input can use * channel 0 by itself. Effects that want multichannel can process the - * ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for - * first-order device output (FOAOut). + * ambisonics signal and make a B-Format source pan for first-order device + * output (FOAOut). */ alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE]; } ALeffectslot; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index ac0c866f..c572fd71 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -495,12 +495,14 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]); /** - * ComputeDryPanGains + * ComputePanGains * * Computes panning gains using the given channel decoder coefficients and the - * pre-calculated direction or angle coefficients. + * pre-calculated direction or angle coefficients. For B-Format sources, the + * coeffs are a 'slice' of a transform matrix for the input channel, used to + * scale and orient the sound samples. */ -inline void ComputeDryPanGains(const MixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +inline void ComputePanGains(const MixParams *dry, const ALfloat*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { if(dry->CoeffCount > 0) ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount, @@ -508,20 +510,6 @@ inline void ComputeDryPanGains(const MixParams *dry, const ALfloat coeffs[MAX_AM else ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains); } -/** - * ComputeFirstOrderGains - * - * Sets channel gains for a first-order ambisonics input channel. The matrix is - * a 1x4 'slice' of a transform matrix for the input channel, used to scale and - * orient the sound samples. - */ -inline void ComputeFirstOrderGains(const MixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) -{ - if(foa->CoeffCount > 0) - ComputePanningGainsMC(foa->Ambi.Coeffs, foa->NumChannels, 4, mtx, ingain, gains); - else - ComputePanningGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains); -} ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo); -- cgit v1.2.3 From cb8545346d227ba85a4a98c3897b5cdb1ea86d26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Sep 2018 19:58:01 -0700 Subject: Always start the event thread with the context --- Alc/ALc.c | 20 ++++++++++-------- OpenAL32/Include/alMain.h | 3 +++ OpenAL32/event.c | 53 +++++++++++++++-------------------------------- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 27c36477..89c0fc63 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2665,6 +2665,11 @@ static ALvoid InitContext(ALCcontext *Context) listener->Params.MetersPerUnit; listener->Params.SourceDistanceModel = Context->SourceDistanceModel; listener->Params.DistanceModel = Context->DistanceModel; + + + Context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); + if(althrd_create(&Context->EventThread, EventThread, Context) != althrd_success) + ERR("Failed to start event thread! Expect problems.\n"); } @@ -2675,6 +2680,7 @@ static ALvoid InitContext(ALCcontext *Context) */ static void FreeContext(ALCcontext *context) { + static const AsyncEvent kill_evt = { 0 }; ALlistener *listener = context->Listener; struct ALeffectslotArray *auxslots; struct ALeffectslotProps *eprops; @@ -2686,6 +2692,11 @@ static void FreeContext(ALCcontext *context) TRACE("%p\n", context); + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) + althrd_yield(); + alsem_post(&context->EventSem); + althrd_join(context->EventThread, NULL); + if((cprops=ATOMIC_LOAD(&context->Update, almemory_order_acquire)) != NULL) { TRACE("Freed unapplied context update %p\n", cprops); @@ -2773,15 +2784,6 @@ static void FreeContext(ALCcontext *context) } TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); - if(ATOMIC_EXCHANGE(&context->EnabledEvts, 0, almemory_order_acq_rel)) - { - static const AsyncEvent kill_evt = { 0 }; - while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) - althrd_yield(); - alsem_post(&context->EventSem); - althrd_join(context->EventThread, NULL); - } - almtx_destroy(&context->EventCbLock); almtx_destroy(&context->EventThrdLock); alsem_destroy(&context->EventSem); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f90108d6..f1bc4469 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -892,6 +892,9 @@ inline void UnlockEffectSlotList(ALCcontext *context) { almtx_unlock(&context->EffectSlotLock); } +int EventThread(void *arg); + + vector_al_string SearchDataFiles(const char *match, const char *subdir); #ifdef __cplusplus diff --git a/OpenAL32/event.c b/OpenAL32/event.c index 12636489..b719c371 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -9,16 +9,12 @@ #include "ringbuffer.h" -static int EventThread(void *arg) +int EventThread(void *arg) { ALCcontext *context = arg; + bool quitnow = false; - /* Clear all pending posts on the semaphore. */ - while(alsem_trywait(&context->EventSem) == althrd_success) - { - } - - while(1) + while(!quitnow) { ALbitfieldSOFT enabledevts; AsyncEvent evt; @@ -28,14 +24,17 @@ static int EventThread(void *arg) alsem_wait(&context->EventSem); continue; } - if(!evt.EnumType) - break; almtx_lock(&context->EventCbLock); - enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); - if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) - context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), - evt.Message, context->EventParam); + do { + quitnow = !evt.EnumType; + if(quitnow) break; + + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); + if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) + context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), + evt.Message, context->EventParam); + } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0); almtx_unlock(&context->EventCbLock); } return 0; @@ -46,7 +45,6 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A ALCcontext *context; ALbitfieldSOFT enabledevts; ALbitfieldSOFT flags = 0; - bool isrunning; ALsizei i; context = GetContextRef(); @@ -77,10 +75,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A almtx_lock(&context->EventThrdLock); if(enable) { - if(!context->AsyncEvents) - context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false); enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags, almemory_order_acq_rel, almemory_order_acquire) == 0) { @@ -88,33 +83,19 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A * just try again. */ } - if(!isrunning && flags) - althrd_create(&context->EventThread, EventThread, context); } else { enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); - isrunning = !!enabledevts; while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags, almemory_order_acq_rel, almemory_order_acquire) == 0) { } - if(isrunning && !(enabledevts&~flags)) - { - static const AsyncEvent kill_evt = { 0 }; - while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) - althrd_yield(); - alsem_post(&context->EventSem); - althrd_join(context->EventThread, NULL); - } - else - { - /* Wait to ensure the event handler sees the changed flags before - * returning. - */ - almtx_lock(&context->EventCbLock); - almtx_unlock(&context->EventCbLock); - } + /* Wait to ensure the event handler sees the changed flags before + * returning. + */ + almtx_lock(&context->EventCbLock); + almtx_unlock(&context->EventCbLock); } almtx_unlock(&context->EventThrdLock); -- cgit v1.2.3 From ebbbeb0d660e442324c2b563c7b59e9f74ad15e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Sep 2018 21:59:38 -0700 Subject: Put user events in a union structure --- Alc/ALc.c | 2 +- Alc/ALu.c | 30 ++++++++++++++---------------- Alc/mixvoice.c | 11 +++++------ OpenAL32/Include/alMain.h | 18 ++++++++++++++---- OpenAL32/alSource.c | 11 +++++------ OpenAL32/event.c | 7 ++++--- 6 files changed, 43 insertions(+), 36 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 89c0fc63..57ae4ace 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2680,7 +2680,7 @@ static ALvoid InitContext(ALCcontext *Context) */ static void FreeContext(ALCcontext *context) { - static const AsyncEvent kill_evt = { 0 }; + static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); ALlistener *listener = context->Listener; struct ALeffectslotArray *auxslots; struct ALeffectslotProps *eprops; diff --git a/Alc/ALu.c b/Alc/ALu.c index 2af32439..c8c583ef 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -211,32 +211,31 @@ void aluInit(void) static void SendSourceStoppedEvent(ALCcontext *context, ALuint id) { + AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); ALbitfieldSOFT enabledevt; - AsyncEvent evt; size_t strpos; ALuint scale; enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(!(enabledevt&EventType_SourceStateChange)) return; - evt.EnumType = EventType_SourceStateChange; - evt.Type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.ObjectId = id; - evt.Param = AL_STOPPED; + evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.u.user.id = id; + evt.u.user.param = AL_STOPPED; /* Normally snprintf would be used, but this is called from the mixer and * that function's not real-time safe, so we have to construct it manually. */ - strcpy(evt.Message, "Source ID "); strpos = 10; + strcpy(evt.u.user.msg, "Source ID "); strpos = 10; scale = 1000000000; while(scale > 0 && scale > id) scale /= 10; while(scale > 0) { - evt.Message[strpos++] = '0' + ((id/scale)%10); + evt.u.user.msg[strpos++] = '0' + ((id/scale)%10); scale /= 10; } - strcpy(evt.Message+strpos, " state changed to AL_STOPPED"); + strcpy(evt.u.user.msg+strpos, " state changed to AL_STOPPED"); if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) alsem_post(&context->EventSem); @@ -1846,25 +1845,24 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) { + AsyncEvent evt = ASYNC_EVENT(EventType_Disconnected); ALCcontext *ctx; - AsyncEvent evt; va_list args; int msglen; if(!ATOMIC_EXCHANGE(&device->Connected, AL_FALSE, almemory_order_acq_rel)) return; - evt.EnumType = EventType_Disconnected; - evt.Type = AL_EVENT_TYPE_DISCONNECTED_SOFT; - evt.ObjectId = 0; - evt.Param = 0; + evt.u.user.type = AL_EVENT_TYPE_DISCONNECTED_SOFT; + evt.u.user.id = 0; + evt.u.user.param = 0; va_start(args, msg); - msglen = vsnprintf(evt.Message, sizeof(evt.Message), msg, args); + msglen = vsnprintf(evt.u.user.msg, sizeof(evt.u.user.msg), msg, args); va_end(args); - if(msglen < 0 || (size_t)msglen >= sizeof(evt.Message)) - evt.Message[sizeof(evt.Message)-1] = 0; + if(msglen < 0 || (size_t)msglen >= sizeof(evt.u.user.msg)) + evt.u.user.msg[sizeof(evt.u.user.msg)-1] = 0; ctx = ATOMIC_LOAD_SEQ(&device->ContextList); while(ctx) diff --git a/Alc/mixvoice.c b/Alc/mixvoice.c index a2365886..d019b898 100644 --- a/Alc/mixvoice.c +++ b/Alc/mixvoice.c @@ -197,12 +197,11 @@ void aluInitMixer(void) static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type, ALuint objid, ALuint param, const char *msg) { - AsyncEvent evt; - evt.EnumType = enumtype; - evt.Type = type; - evt.ObjectId = objid; - evt.Param = param; - strcpy(evt.Message, msg); + AsyncEvent evt = ASYNC_EVENT(enumtype); + evt.u.user.type = type; + evt.u.user.id = objid; + evt.u.user.param = param; + strcpy(evt.u.user.msg, msg); if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1) alsem_post(&context->EventSem); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f1bc4469..86ac49dc 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -750,6 +750,10 @@ struct ALCdevice_struct { enum { + /* End event thread processing. */ + EventType_KillThread = 0, + + /* User event types. */ EventType_SourceStateChange = 1<<0, EventType_BufferCompleted = 1<<1, EventType_Error = 1<<2, @@ -760,11 +764,17 @@ enum { typedef struct AsyncEvent { unsigned int EnumType; - ALenum Type; - ALuint ObjectId; - ALuint Param; - ALchar Message[1008]; + union { + char dummy; + struct { + ALenum type; + ALuint id; + ALuint param; + ALchar msg[1008]; + } user; + } u; } AsyncEvent; +#define ASYNC_EVENT(t) { t, { 0 } } struct ALCcontext_struct { RefCount ref; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 5ce439c7..81d8c262 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -229,17 +229,16 @@ static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context) /** Can only be called while the mixer is locked! */ static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state) { + AsyncEvent evt = ASYNC_EVENT(EventType_SourceStateChange); ALbitfieldSOFT enabledevt; - AsyncEvent evt; enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(!(enabledevt&EventType_SourceStateChange)) return; - evt.EnumType = EventType_SourceStateChange; - evt.Type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; - evt.ObjectId = id; - evt.Param = state; - snprintf(evt.Message, sizeof(evt.Message), "Source ID %u state changed to %s", id, + evt.u.user.type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT; + evt.u.user.id = id; + evt.u.user.param = state; + snprintf(evt.u.user.msg, sizeof(evt.u.user.msg), "Source ID %u state changed to %s", id, (state==AL_INITIAL) ? "AL_INITIAL" : (state==AL_PLAYING) ? "AL_PLAYING" : (state==AL_PAUSED) ? "AL_PAUSED" : diff --git a/OpenAL32/event.c b/OpenAL32/event.c index b719c371..a76746bd 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -27,13 +27,14 @@ int EventThread(void *arg) almtx_lock(&context->EventCbLock); do { - quitnow = !evt.EnumType; + quitnow = evt.EnumType == EventType_KillThread; if(quitnow) break; enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) - context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message), - evt.Message, context->EventParam); + context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, + (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam + ); } while(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) != 0); almtx_unlock(&context->EventCbLock); } -- cgit v1.2.3 From 84a90b7cc39a797781566ceebd6de40c495808aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Sep 2018 22:44:58 -0700 Subject: Stop the event thread when releasing the context To ensure no user callback gets called after alcDestroyContext. --- Alc/ALc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 57ae4ace..7d3e3649 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2680,7 +2680,6 @@ static ALvoid InitContext(ALCcontext *Context) */ static void FreeContext(ALCcontext *context) { - static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); ALlistener *listener = context->Listener; struct ALeffectslotArray *auxslots; struct ALeffectslotProps *eprops; @@ -2692,11 +2691,6 @@ static void FreeContext(ALCcontext *context) TRACE("%p\n", context); - while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) - althrd_yield(); - alsem_post(&context->EventSem); - althrd_join(context->EventThread, NULL); - if((cprops=ATOMIC_LOAD(&context->Update, almemory_order_acquire)) != NULL) { TRACE("Freed unapplied context update %p\n", cprops); @@ -2809,6 +2803,7 @@ static void FreeContext(ALCcontext *context) */ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) { + static const AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread); ALCcontext *origctx, *newhead; bool ret = true; @@ -2841,6 +2836,11 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) ret = !!newhead; V0(device->Backend,unlock)(); + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) + althrd_yield(); + alsem_post(&context->EventSem); + althrd_join(context->EventThread, NULL); + ALCcontext_DecRef(context); return ret; } -- cgit v1.2.3 From f21e2df4cf0d51fda31f5607e1bf966459d9bf9d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 20 Sep 2018 22:53:16 -0700 Subject: Remove an unnecessary mutex --- Alc/ALc.c | 2 -- OpenAL32/Include/alMain.h | 1 - OpenAL32/event.c | 2 -- 3 files changed, 5 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 7d3e3649..9a1051c9 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2638,7 +2638,6 @@ static ALvoid InitContext(ALCcontext *Context) Context->MetersPerUnit = AL_DEFAULT_METERS_PER_UNIT; ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed); ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE); - almtx_init(&Context->EventThrdLock, almtx_plain); alsem_init(&Context->EventSem, 0); Context->AsyncEvents = NULL; ATOMIC_INIT(&Context->EnabledEvts, 0); @@ -2779,7 +2778,6 @@ static void FreeContext(ALCcontext *context) TRACE("Freed "SZFMT" listener property object%s\n", count, (count==1)?"":"s"); almtx_destroy(&context->EventCbLock); - almtx_destroy(&context->EventThrdLock); alsem_destroy(&context->EventSem); ll_ringbuffer_free(context->AsyncEvents); diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 86ac49dc..3a08e8c1 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -827,7 +827,6 @@ struct ALCcontext_struct { ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots; - almtx_t EventThrdLock; althrd_t EventThread; alsem_t EventSem; struct ll_ringbuffer *AsyncEvents; diff --git a/OpenAL32/event.c b/OpenAL32/event.c index a76746bd..c0bf4204 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -73,7 +73,6 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]); } - almtx_lock(&context->EventThrdLock); if(enable) { enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed); @@ -98,7 +97,6 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A almtx_lock(&context->EventCbLock); almtx_unlock(&context->EventCbLock); } - almtx_unlock(&context->EventThrdLock); done: ALCcontext_DecRef(context); -- cgit v1.2.3 From b6d0ff02c2ec52d2c12a58f2be83b4c3eaa93afe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Sep 2018 02:37:37 -0700 Subject: Use an internal event to more timely release old effect states --- Alc/ALu.c | 38 +++++++++++++++++++++++++++++++++----- OpenAL32/Include/alMain.h | 4 ++++ OpenAL32/alAuxEffectSlot.c | 3 +++ OpenAL32/event.c | 7 +++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index c8c583ef..3f61338f 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -462,12 +462,40 @@ static bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool f slot->Params.AirAbsorptionGainHF = 1.0f; } - /* Swap effect states. No need to play with the ref counts since they - * keep the same number of refs. - */ state = props->State; - props->State = slot->Params.EffectState; - slot->Params.EffectState = state; + + if(state == slot->Params.EffectState) + { + /* If the effect state is the same as current, we can decrement its + * count safely to remove it from the update object (it can't reach + * 0 refs since the current params also hold a reference). + */ + DecrementRef(&state->Ref); + props->State = NULL; + } + else + { + /* Otherwise, replace it and send off the old one with a release + * event. + */ + AsyncEvent evt = ASYNC_EVENT(EventType_ReleaseEffectState); + evt.u.EffectState = slot->Params.EffectState; + + slot->Params.EffectState = state; + props->State = NULL; + + if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) != 0)) + alsem_post(&context->EventSem); + else + { + /* If writing the event failed, the queue was probably full. + * Store the old state in the property object where it can + * eventually be cleaned up sometime later (not ideal, but + * better than blocking or leaking). + */ + props->State = evt.u.EffectState; + } + } ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); } diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3a08e8c1..3e328157 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -760,6 +760,9 @@ enum { EventType_Performance = 1<<3, EventType_Deprecated = 1<<4, EventType_Disconnected = 1<<5, + + /* Internal events. */ + EventType_ReleaseEffectState = 65536, }; typedef struct AsyncEvent { @@ -772,6 +775,7 @@ typedef struct AsyncEvent { ALuint param; ALchar msg[1008]; } user; + struct ALeffectState *EffectState; } u; } AsyncEvent; #define ASYNC_EVENT(t) { t, { 0 } } diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c index b293b6a5..8141e0f6 100644 --- a/OpenAL32/alAuxEffectSlot.c +++ b/OpenAL32/alAuxEffectSlot.c @@ -753,6 +753,9 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context) /* If there was an unused update container, put it back in the * freelist. */ + if(props->State) + ALeffectState_DecRef(props->State); + props->State = NULL; ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &context->FreeEffectslotProps, props); } diff --git a/OpenAL32/event.c b/OpenAL32/event.c index c0bf4204..4c9c0be2 100644 --- a/OpenAL32/event.c +++ b/OpenAL32/event.c @@ -6,6 +6,7 @@ #include "AL/alext.h" #include "alMain.h" #include "alError.h" +#include "alAuxEffectSlot.h" #include "ringbuffer.h" @@ -30,6 +31,12 @@ int EventThread(void *arg) quitnow = evt.EnumType == EventType_KillThread; if(quitnow) break; + if(evt.EnumType == EventType_ReleaseEffectState) + { + ALeffectState_DecRef(evt.u.EffectState); + continue; + } + enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire); if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType) context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param, -- cgit v1.2.3 From 36a6b9d42a79f40108441c2b6f9ad88d45e7a98e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 21 Sep 2018 06:06:29 -0700 Subject: Adjust comment spacing --- Alc/ALu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 3f61338f..e9d8aa02 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -741,7 +741,7 @@ static void CalcPanningAndFilters(ALvoice *voice, const ALfloat Azi, const ALflo * outputs on the columns. */ aluMatrixfSet(&matrix, - // ACN0 ACN1 ACN2 ACN3 + // ACN0 ACN1 ACN2 ACN3 SQRTF_2, 0.0f, 0.0f, 0.0f, // Ambi W 0.0f, -N[0]*SQRTF_3, N[1]*SQRTF_3, -N[2]*SQRTF_3, // Ambi X 0.0f, U[0]*SQRTF_3, -U[1]*SQRTF_3, U[2]*SQRTF_3, // Ambi Y -- cgit v1.2.3 From 77a53594bad3ae39bbbeb22b19815edec24c4fa8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Sep 2018 08:26:52 -0700 Subject: Improve the gain stepping difference check Given the more stable stepping now in use, check that the total difference is enough for perceptible transition, instead of the step itself. --- Alc/mixer/mixer_c.c | 13 +++++++------ Alc/mixer/mixer_neon.c | 7 ++++--- Alc/mixer/mixer_sse.c | 7 ++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Alc/mixer/mixer_c.c b/Alc/mixer/mixer_c.c index 2dcd6c6b..14d7c669 100644 --- a/Alc/mixer/mixer_c.c +++ b/Alc/mixer/mixer_c.c @@ -108,21 +108,22 @@ void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[ ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos, ALsizei BufferSize) { - ALfloat gain, delta, step; + const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; ALsizei c; ASSUME(OutChans > 0); ASSUME(BufferSize > 0); - delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f; for(c = 0;c < OutChans;c++) { ALsizei pos = 0; - gain = CurrentGains[c]; - step = (TargetGains[c] - gain) * delta; - if(fabsf(step) > FLT_EPSILON) + ALfloat gain = CurrentGains[c]; + const ALfloat diff = TargetGains[c] - gain; + + if(fabsf(diff) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; ALfloat step_count = 0.0f; for(;pos < minsize;pos++) { @@ -158,7 +159,7 @@ void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict for(c = 0;c < InChans;c++) { - ALfloat gain = Gains[c]; + const ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer/mixer_neon.c b/Alc/mixer/mixer_neon.c index ca274b07..9bf5521a 100644 --- a/Alc/mixer/mixer_neon.c +++ b/Alc/mixer/mixer_neon.c @@ -179,11 +179,12 @@ void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffe { ALsizei pos = 0; ALfloat gain = CurrentGains[c]; - const ALfloat step = (TargetGains[c] - gain) * delta; + const ALfloat diff = TargetGains[c] - gain; - if(fabsf(step) > FLT_EPSILON) + if(fabsf(diff) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; ALfloat step_count = 0.0f; /* Mix with applying gain steps in aligned multiples of 4. */ if(LIKELY(minsize > 3)) @@ -260,7 +261,7 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restr for(c = 0;c < InChans;c++) { ALsizei pos = 0; - ALfloat gain = Gains[c]; + const ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; diff --git a/Alc/mixer/mixer_sse.c b/Alc/mixer/mixer_sse.c index 78cf26f1..725a5ebc 100644 --- a/Alc/mixer/mixer_sse.c +++ b/Alc/mixer/mixer_sse.c @@ -149,11 +149,12 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer { ALsizei pos = 0; ALfloat gain = CurrentGains[c]; - const ALfloat step = (TargetGains[c] - gain) * delta; + const ALfloat diff = TargetGains[c] - gain; - if(fabsf(step) > FLT_EPSILON) + if(fabsf(diff) > FLT_EPSILON) { ALsizei minsize = mini(BufferSize, Counter); + const ALfloat step = diff * delta; ALfloat step_count = 0.0f; /* Mix with applying gain steps in aligned multiples of 4. */ if(LIKELY(minsize > 3)) @@ -227,7 +228,7 @@ void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restri for(c = 0;c < InChans;c++) { ALsizei pos = 0; - ALfloat gain = Gains[c]; + const ALfloat gain = Gains[c]; if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; -- cgit v1.2.3 From c708f871ec63ef37f4c89f26e313c62cd3e3a245 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 22 Sep 2018 20:13:31 -0700 Subject: Update changelog --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6134e113..ca798fbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +openal-soft-1.19.1: + + Implemented capture support for the SoundIO backend. + + Fixed source buffer queues potentially not playing properly when a queue + entry completes. + + Fixed possible unexpected failures when generating auxiliary effect slots. + + Fixed a crash with certain reverb or device settings. + + Fixed OpenSL capture. + openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. -- cgit v1.2.3 From 800326d37ab1a5ae3036abd60d5eb205be3f2bc7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Sep 2018 01:11:58 -0700 Subject: Rename ALreverbState to ReverbState --- Alc/effects/reverb.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index a5de52f9..882b364f 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -274,7 +274,7 @@ typedef struct LateReverb { ALfloat PanGain[NUM_LINES][MAX_OUTPUT_CHANNELS]; } LateReverb; -typedef struct ALreverbState { +typedef struct ReverbState { DERIVE_FROM_TYPE(ALeffectState); /* All delay lines are allocated as a single buffer to reduce memory @@ -320,22 +320,22 @@ typedef struct ALreverbState { /* Temporary storage used when processing. */ alignas(16) ALfloat TempSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; alignas(16) ALfloat MixSamples[NUM_LINES][MAX_UPDATE_SAMPLES]; -} ALreverbState; +} ReverbState; -static ALvoid ALreverbState_Destruct(ALreverbState *State); -static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device); -static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); -static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); -DECLARE_DEFAULT_ALLOCATORS(ALreverbState) +static ALvoid ReverbState_Destruct(ReverbState *State); +static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device); +static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props); +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels); +DECLARE_DEFAULT_ALLOCATORS(ReverbState) -DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); +DEFINE_ALEFFECTSTATE_VTABLE(ReverbState); -static void ALreverbState_Construct(ALreverbState *state) +static void ReverbState_Construct(ReverbState *state) { ALsizei i, j; ALeffectState_Construct(STATIC_CAST(ALeffectState, state)); - SET_VTABLE2(ALreverbState, ALeffectState, state); + SET_VTABLE2(ReverbState, ALeffectState, state); state->TotalSamples = 0; state->SampleBuffer = NULL; @@ -421,7 +421,7 @@ static void ALreverbState_Construct(ALreverbState *state) state->Offset = 0; } -static ALvoid ALreverbState_Destruct(ALreverbState *State) +static ALvoid ReverbState_Destruct(ReverbState *State) { al_free(State->SampleBuffer); State->SampleBuffer = NULL; @@ -475,7 +475,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const * for all lines given the sample rate (frequency). If an allocation failure * occurs, it returns AL_FALSE. */ -static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) +static ALboolean AllocLines(const ALuint frequency, ReverbState *State) { ALuint totalSamples, i; ALfloat multiplier, length; @@ -550,7 +550,7 @@ static ALboolean AllocLines(const ALuint frequency, ALreverbState *State) return AL_TRUE; } -static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) +static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) { ALuint frequency = Device->Frequency; ALfloat multiplier; @@ -667,7 +667,7 @@ static void CalcT60DampingCoeffs(const ALfloat length, const ALfloat lfDecayTime } /* Update the offsets for the main effect delay line. */ -static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ALreverbState *State) +static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay, const ALfloat density, const ALfloat decayTime, const ALuint frequency, ReverbState *State) { ALfloat multiplier, length; ALuint i; @@ -843,7 +843,7 @@ static aluMatrixf GetTransformFromVector(const ALfloat *vec) } /* Update the early and late 3D panning gains. */ -static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ALreverbState *State) +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, const ALfloat earlyGain, const ALfloat lateGain, ReverbState *State) { aluMatrixf transform, rot; ALsizei i; @@ -880,7 +880,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection #undef MATRIX_MULT } -static ALvoid ALreverbState_update(ALreverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { const ALCdevice *Device = Context->Device; const ALlistener *Listener = Context->Listener; @@ -1174,7 +1174,7 @@ static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], * Two static specializations are used for transitional (cross-faded) delay * line processing and non-transitional processing. */ -static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const ALsizei todo, +static void EarlyReflection_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1225,7 +1225,7 @@ static void EarlyReflection_Unfaded(ALreverbState *State, ALsizei offset, const late_feed_tap = offset - State->LateFeedTap; VectorScatterRevDelayIn(&main_delay, late_feed_tap, mixX, mixY, out, todo); } -static void EarlyReflection_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, +static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1309,7 +1309,7 @@ static inline void LateT60Filter(ALfloat *restrict samples, const ALsizei todo, * Two variations are made, one for for transitional (cross-faded) delay line * processing and one for non-transitional processing. */ -static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsizei todo, +static void LateReverb_Unfaded(ReverbState *State, ALsizei offset, const ALsizei todo, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1347,7 +1347,7 @@ static void LateReverb_Unfaded(ALreverbState *State, ALsizei offset, const ALsiz /* Finally, scatter and bounce the results to refeed the feedback buffer. */ VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, out, todo); } -static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei todo, +static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei todo, const ALfloat fade, ALfloat (*restrict out)[MAX_UPDATE_SAMPLES]) { ALfloat (*restrict temps)[MAX_UPDATE_SAMPLES] = State->TempSamples; @@ -1398,7 +1398,7 @@ static void LateReverb_Faded(ALreverbState *State, ALsizei offset, const ALsizei VectorScatterRevDelayIn(&late_delay, offset, mixX, mixY, temps, todo); } -static ALvoid ALreverbState_process(ALreverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) +static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels) { ALfloat (*restrict afmt)[MAX_UPDATE_SAMPLES] = State->TempSamples; ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES] = State->MixSamples; @@ -1521,9 +1521,9 @@ typedef struct ReverbStateFactory { static ALeffectState *ReverbStateFactory_create(ReverbStateFactory* UNUSED(factory)) { - ALreverbState *state; + ReverbState *state; - NEW_OBJ0(state, ALreverbState)(); + NEW_OBJ0(state, ReverbState)(); if(!state) return NULL; return STATIC_CAST(ALeffectState, state); -- cgit v1.2.3 From db6905bf57ba2f5243f6d9a45148c8d92818b6e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Sep 2018 02:22:23 -0700 Subject: Clear reverb gain coefficients when doing a device update --- Alc/effects/reverb.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 882b364f..9e8b8dd4 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -554,6 +554,7 @@ static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) { ALuint frequency = Device->Frequency; ALfloat multiplier; + ALsizei i, j; /* Allocate the delay lines. */ if(!AllocLines(frequency, State)) @@ -566,6 +567,54 @@ static ALboolean ReverbState_deviceUpdate(ReverbState *State, ALCdevice *Device) EARLY_TAP_LENGTHS[NUM_LINES-1]*multiplier) * frequency); + /* Clear filters and gain coefficients since the delay lines were all just + * cleared (if not reallocated). + */ + for(i = 0;i < NUM_LINES;i++) + { + BiquadFilter_clear(&State->Filter[i].Lp); + BiquadFilter_clear(&State->Filter[i].Hp); + } + + for(i = 0;i < NUM_LINES;i++) + { + State->EarlyDelayCoeff[i][0] = 0.0f; + State->EarlyDelayCoeff[i][1] = 0.0f; + } + + for(i = 0;i < NUM_LINES;i++) + { + State->Early.Coeff[i][0] = 0.0f; + State->Early.Coeff[i][1] = 0.0f; + } + + State->Late.DensityGain[0] = 0.0f; + State->Late.DensityGain[1] = 0.0f; + for(i = 0;i < NUM_LINES;i++) + { + State->Late.T60[i].MidGain[0] = 0.0f; + State->Late.T60[i].MidGain[1] = 0.0f; + BiquadFilter_clear(&State->Late.T60[i].HFFilter); + BiquadFilter_clear(&State->Late.T60[i].LFFilter); + } + + for(i = 0;i < NUM_LINES;i++) + { + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + { + State->Early.CurrentGain[i][j] = 0.0f; + State->Early.PanGain[i][j] = 0.0f; + State->Late.CurrentGain[i][j] = 0.0f; + State->Late.PanGain[i][j] = 0.0f; + } + } + + /* Reset counters and offset base. */ + State->FadeCount = 0; + State->MaxUpdate[0] = MAX_UPDATE_SAMPLES; + State->MaxUpdate[1] = MAX_UPDATE_SAMPLES; + State->Offset = 0; + return AL_TRUE; } -- cgit v1.2.3 From 39c3314d0064f89147f21291ed1068cf83b18977 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 23 Sep 2018 22:59:16 -0700 Subject: Only compare the reverb params that induce a need for fading The offsets and coefficients are controlled by a relatively small set of input parameters, just with different base constants or different calculations. This lead to numerous redundant checks since if one value didn't change, others that use the same inputs wouldn't have either. --- Alc/effects/reverb.c | 64 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 9e8b8dd4..cfce5623 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -283,6 +283,15 @@ typedef struct ReverbState { ALfloat *SampleBuffer; ALuint TotalSamples; + struct { + /* Calculated parameters which indicate if cross-fading is needed after + * an update. + */ + ALfloat Density, Diffusion; + ALfloat DecayTime, HFDecayTime, LFDecayTime; + ALfloat HFReference, LFReference; + } Params; + /* Master effect filters */ struct { BiquadFilter Lp; @@ -340,6 +349,14 @@ static void ReverbState_Construct(ReverbState *state) state->TotalSamples = 0; state->SampleBuffer = NULL; + state->Params.Density = AL_EAXREVERB_DEFAULT_DENSITY; + state->Params.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + state->Params.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + state->Params.HFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + state->Params.LFDecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME*AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + state->Params.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + state->Params.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + for(i = 0;i < NUM_LINES;i++) { BiquadFilter_clear(&state->Filter[i].Lp); @@ -929,7 +946,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection #undef MATRIX_MULT } -static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) +static void ReverbState_update(ReverbState *State, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props) { const ALCdevice *Device = Context->Device; const ALlistener *Listener = Context->Listener; @@ -1001,30 +1018,31 @@ static ALvoid ReverbState_update(ReverbState *State, const ALCcontext *Context, mini(State->Early.Offset[0][1], State->Late.Offset[0][1]) ); - /* Determine if delay-line cross-fading is required. TODO: Add some fuzz - * for the float comparisons? The math should be stable enough that the - * result should be the same if nothing's changed, and changes in the float - * values should (though may not always) be matched by changes in delay - * offsets. + /* Determine if delay-line cross-fading is required. Density is essentially + * a master control for the feedback delays, so changes the offsets of many + * delay lines. */ - if(State->Late.DensityGain[1] != State->Late.DensityGain[0]) + if(State->Params.Density != props->Reverb.Density || + /* Diffusion and decay times influences the decay rate (gain) of the + * late reverb T60 filter. + */ + State->Params.Diffusion != props->Reverb.Diffusion || + State->Params.DecayTime != props->Reverb.DecayTime || + State->Params.HFDecayTime != hfDecayTime || + State->Params.LFDecayTime != lfDecayTime || + /* HF/LF References control the weighting used to calculate the density + * gain. + */ + State->Params.HFReference != props->Reverb.HFReference || + State->Params.LFReference != props->Reverb.LFReference) State->FadeCount = 0; - else for(i = 0;i < NUM_LINES;i++) - { - if(State->EarlyDelayTap[i][1] != State->EarlyDelayTap[i][0] || - State->EarlyDelayCoeff[i][1] != State->EarlyDelayCoeff[i][0] || - State->Early.VecAp.Offset[i][1] != State->Early.VecAp.Offset[i][0] || - State->Early.Offset[i][1] != State->Early.Offset[i][0] || - State->Early.Coeff[i][1] != State->Early.Coeff[i][0] || - State->LateDelayTap[i][1] != State->LateDelayTap[i][0] || - State->Late.VecAp.Offset[i][1] != State->Late.VecAp.Offset[i][0] || - State->Late.Offset[i][1] != State->Late.Offset[i][0] || - State->Late.T60[i].MidGain[1] != State->Late.T60[i].MidGain[0]) - { - State->FadeCount = 0; - break; - } - } + State->Params.Density = props->Reverb.Density; + State->Params.Diffusion = props->Reverb.Diffusion; + State->Params.DecayTime = props->Reverb.DecayTime; + State->Params.HFDecayTime = hfDecayTime; + State->Params.LFDecayTime = lfDecayTime; + State->Params.HFReference = props->Reverb.HFReference; + State->Params.LFReference = props->Reverb.LFReference; } -- cgit v1.2.3 From c69338bc0dc338db7077a2c6759222ca4703f4eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Sep 2018 10:04:14 -0700 Subject: Update the output limiter/compressor This provides better characteristics for an amplitude limiter. In particular, it utilizes the peak amplitude instead of the RMS, and the used parameters basically guarantee no output samples exceed the given threshold... almost, due to floating-point errors as the threshold is converted from dB to log-e for the envelope, then is negated and converted to linear amplitude to apply to the signal. It's quite possible for some rounding errors to creep in and not perfectly saturate the result. --- Alc/ALc.c | 8 +- Alc/ALu.c | 3 +- Alc/mastering.c | 477 ++++++++++++++++++++++++++++++++++++++++---------------- Alc/mastering.h | 111 +++++++++---- 4 files changed, 431 insertions(+), 168 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 9a1051c9..ecacf8c5 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1706,8 +1706,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) struct Compressor *CreateDeviceLimiter(const ALCdevice *device) { - return CompressorInit(0.0f, 0.0f, AL_FALSE, AL_TRUE, 0.0f, 0.0f, 0.5f, 2.0f, - 0.0f, -3.0f, 3.0f, device->Frequency); + return CompressorInit(device->RealOut.NumChannels, device->Frequency, + AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, + 0.0f, 0.0f, -0.0003f, INFINITY, 0.0f, 0.020f, 0.200f); } /* UpdateClockBase @@ -2231,7 +2232,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ if(gainLimiter != ALC_FALSE) { - if(!device->Limiter || device->Frequency != GetCompressorSampleRate(device->Limiter)) + if(!device->Limiter || device->Frequency != GetCompressorSampleRate(device->Limiter) || + device->RealOut.NumChannels != GetCompressorChannelCount(device->Limiter)) { al_free(device->Limiter); device->Limiter = CreateDeviceLimiter(device); diff --git a/Alc/ALu.c b/Alc/ALu.c index e9d8aa02..03abb116 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -1838,8 +1838,7 @@ void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples) SamplesToDo, device->RealOut.NumChannels); if(device->Limiter) - ApplyCompression(device->Limiter, device->RealOut.NumChannels, SamplesToDo, - device->RealOut.Buffer); + ApplyCompression(device->Limiter, SamplesToDo, device->RealOut.Buffer); if(device->DitherDepth > 0.0f) ApplyDither(device->RealOut.Buffer, &device->DitherSeed, device->DitherDepth, diff --git a/Alc/mastering.c b/Alc/mastering.c index 1636c8d9..78f6038d 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -7,226 +7,439 @@ #include "almalloc.h" +extern inline ALsizei GetCompressorChannelCount(const Compressor *Comp); extern inline ALuint GetCompressorSampleRate(const Compressor *Comp); -#define RMS_WINDOW_SIZE (1<<7) -#define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1) -#define RMS_VALUE_MAX (1<<24) -static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big"); - - -/* Multichannel compression is linked via one of two modes: +/* This sliding hold follows the input level with an instant attack and a + * fixed duration hold before an instant release to the next highest level. + * It is a sliding window maximum (descending maxima) implementation based on + * Richard Harter's ascending minima algorithm available at: * - * Summed - Absolute sum of all channels. - * Maxed - Absolute maximum of any channel. + * http://www.richardhartersworld.com/cri/2001/slidingmin.html */ -static void SumChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, - ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) { - ALsizei c, i; + const ALsizei mask = BUFFERSIZE - 1; + const ALsizei length = Hold->Length; + ALfloat *restrict values = Hold->Values; + ALsizei *restrict expiries = Hold->Expiries; + ALsizei lowerIndex = Hold->LowerIndex; + ALsizei upperIndex = Hold->UpperIndex; - for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] = 0.0f; + if(i >= expiries[upperIndex]) + upperIndex = (upperIndex + 1) & mask; - for(c = 0;c < NumChans;c++) + if(in >= values[upperIndex]) { - for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] += OutBuffer[c][i]; + values[upperIndex] = in; + expiries[upperIndex] = i + length; + lowerIndex = upperIndex; } + else + { + while(in >= values[lowerIndex]) + lowerIndex = (lowerIndex - 1) & mask; - for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] = fabsf(Comp->Envelope[i]); + lowerIndex = (lowerIndex + 1) & mask; + values[lowerIndex] = in; + expiries[lowerIndex] = i + length; + } + + Hold->LowerIndex = lowerIndex; + Hold->UpperIndex = upperIndex; + + return values[upperIndex]; } -static void MaxChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, - ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) { + const ALsizei mask = BUFFERSIZE - 1; + const ALsizei lowerIndex = Hold->LowerIndex; + ALsizei *restrict expiries = Hold->Expiries; + ALsizei i = Hold->UpperIndex; + + while(i != lowerIndex) + { + expiries[i] -= n; + i = (i + 1) & mask; + } + + expiries[i] -= n; +} + +/* Multichannel compression is linked via the absolute maximum of all + * channels. + */ +static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +{ + const ALsizei mask = 2*BUFFERSIZE - 1; + const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALsizei numChans = Comp->NumChans; + ALfloat *restrict sideChain = Comp->SideChain; ALsizei c, i; for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] = 0.0f; + sideChain[(index + i) & mask] = 0.0f; - for(c = 0;c < NumChans;c++) + for(c = 0;c < numChans;c++) { for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] = maxf(Comp->Envelope[i], fabsf(OutBuffer[c][i])); + { + ALsizei offset = (index + i) & mask; + + sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i])); + } } } -/* Envelope detection/sensing can be done via: - * - * RMS - Rectangular windowed root mean square of linking stage. - * Peak - Implicit output from linking stage. +/* This calculates the squared crest factor of the control signal for the + * basic automation of the attack/release times. As suggested by the paper, + * it uses an instantaneous squared peak detector and a squared RMS detector + * both with 200ms release times. */ -static void RmsDetection(Compressor *Comp, const ALsizei SamplesToDo) +static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) { - ALuint sum = Comp->RmsSum; - ALuint *window = Comp->RmsWindow; - ALsizei index = Comp->RmsIndex; + const ALsizei mask = 2*BUFFERSIZE - 1; + const ALfloat a_crest = Comp->CrestCoeff; + const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALfloat *restrict sideChain = Comp->SideChain; + ALfloat *restrict crestFactor = Comp->CrestFactor; + ALfloat y2_peak = Comp->LastPeakSq; + ALfloat y2_rms = Comp->LastRmsSq; ALsizei i; for(i = 0;i < SamplesToDo;i++) { - ALfloat sig = Comp->Envelope[i]; - - sum -= window[index]; - window[index] = fastf2i(minf(sig * sig * 65536.0f, RMS_VALUE_MAX)); - sum += window[index]; - index = (index + 1) & RMS_WINDOW_MASK; + ALfloat x_abs = sideChain[(index + i) & mask]; + ALfloat x2 = maxf(0.000001f, x_abs * x_abs); - Comp->Envelope[i] = sqrtf(sum / 65536.0f / RMS_WINDOW_SIZE); + y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); + y2_rms = lerp(x2, y2_rms, a_crest); + crestFactor[i] = y2_peak / y2_rms; } - Comp->RmsSum = sum; - Comp->RmsIndex = index; + Comp->LastPeakSq = y2_peak; + Comp->LastRmsSq = y2_rms; } -/* This isn't a very sophisticated envelope follower, but it gets the job - * done. First, it operates at logarithmic scales to keep transitions - * appropriate for human hearing. Second, it can apply adaptive (automated) - * attack/release adjustments based on the signal. +/* The side-chain starts with a simple peak detector (based on the absolute + * value of the incoming signal) and performs most of its operations in the + * log domain. */ -static void FollowEnvelope(Compressor *Comp, const ALsizei SamplesToDo) +static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) { - ALfloat attackMin = Comp->AttackMin; - ALfloat attackMax = Comp->AttackMax; - ALfloat releaseMin = Comp->ReleaseMin; - ALfloat releaseMax = Comp->ReleaseMax; - ALfloat last = Comp->EnvLast; + const ALsizei mask = 2*BUFFERSIZE - 1; + const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + ALfloat *restrict sideChain = Comp->SideChain; ALsizei i; for(i = 0;i < SamplesToDo;i++) { - ALfloat env = log10f(maxf(Comp->Envelope[i], 0.000001f)); - ALfloat slope = minf(1.0f, fabsf(env - last) / 4.5f); + ALuint offset = (index + i) & mask; + ALfloat x_abs = sideChain[offset]; - if(env > last) - last = minf(env, last + lerp(attackMin, attackMax, 1.0f - (slope * slope))); - else - last = maxf(env, last + lerp(releaseMin, releaseMax, 1.0f - (slope * slope))); + sideChain[offset] = logf(maxf(0.000001f, x_abs)); + } +} - Comp->Envelope[i] = last; +/* An optional hold can be used to extend the peak detector so it can more + * solidly detect fast transients. This is best used when operating as a + * limiter. + */ +static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) +{ + const ALsizei mask = 2*BUFFERSIZE - 1; + const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + ALfloat *restrict sideChain = Comp->SideChain; + SlidingHold *hold = Comp->Hold; + ALsizei i; + + for(i = 0;i < SamplesToDo;i++) + { + ALsizei offset = (index + i) & mask; + ALfloat x_abs = sideChain[offset]; + ALfloat x_G = logf(maxf(0.000001f, x_abs)); + + sideChain[offset] = UpdateSlidingHold(hold, i, x_G); } - Comp->EnvLast = last; + ShiftSlidingHold(hold, SamplesToDo); } -/* The envelope is converted to control gain with an optional soft knee. */ -static void EnvelopeGain(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat Slope) +/* This is the heart of the feed-forward compressor. It operates in the log + * domain (to better match human hearing) and can apply some basic automation + * to knee width, attack/release times, make-up/post gain, and clipping + * reduction. + */ +static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) { + const ALsizei mask = 2*BUFFERSIZE - 1; + const bool autoKnee = Comp->Auto.Knee; + const bool autoAttack = Comp->Auto.Attack; + const bool autoRelease = Comp->Auto.Release; + const bool autoPostGain = Comp->Auto.PostGain; + const bool autoDeclip = Comp->Auto.Declip; + const ALsizei lookAhead = Comp->LookAhead; const ALfloat threshold = Comp->Threshold; - const ALfloat knee = Comp->Knee; + const ALfloat slope = Comp->Slope; + const ALfloat attack = Comp->Attack; + const ALfloat release = Comp->Release; + const ALsizei index = Comp->SideChainIndex; + const ALfloat *restrict crestFactor = Comp->CrestFactor; + ALfloat *restrict sideChain = Comp->SideChain; + ALfloat postGain = Comp->PostGain; + ALfloat knee = Comp->Knee; + ALfloat c_est = Comp->GainEstimate; + ALfloat a_adp = Comp->AdaptCoeff; + ALfloat t_att = attack; + ALfloat t_rel = release - attack; + ALfloat a_att = expf(-1.0f / t_att); + ALfloat a_rel = expf(-1.0f / t_rel); + ALfloat y_1 = Comp->LastRelease; + ALfloat y_L = Comp->LastAttack; + ALfloat c_dev = Comp->LastGainDev; ALsizei i; - if(!(knee > 0.0f)) + for(i = 0;i < SamplesToDo;i++) { - for(i = 0;i < SamplesToDo;i++) + const ALfloat y2_crest = crestFactor[i]; + ALfloat x_G = sideChain[(index + lookAhead + i) & mask]; + ALfloat x_over = x_G - threshold; + ALfloat knee_h; + ALfloat y_G; + ALfloat x_L; + + if(autoKnee) + knee = maxf(0.0f, 2.5f * (c_dev + c_est)); + knee_h = 0.5f * knee; + + /* This is the gain computer. It applies a static compression curve + * to the control signal. + */ + if(x_over <= -knee_h) + y_G = 0.0f; + else if(fabsf(x_over) < knee_h) + y_G = (x_over + knee_h) * (x_over + knee_h) / (2.0f * knee); + else + y_G = x_over; + + x_L = -slope * y_G; + + if(autoAttack) + { + t_att = 2.0f * attack / y2_crest; + a_att = expf(-1.0f / t_att); + } + + if(autoRelease) { - ALfloat gain = Slope * (threshold - Comp->Envelope[i]); - Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain)); + t_rel = 2.0f * release / y2_crest - t_att; + a_rel = expf(-1.0f / t_rel); } + + /* Gain smoothing (ballistics) is done via a smooth decoupled peak + * detector. The attack time is subtracted from the release time + * above to compensate for the chained operating mode. + */ + y_1 = maxf(x_L, lerp(x_L, y_1, a_rel)); + y_L = lerp(y_1, y_L, a_att); + + /* Knee width and make-up gain automation make use of a smoothed + * measurement of deviation between the control signal and estimate. + * The estimate is also used to bias the measurement to hot-start its + * average. + */ + c_dev = lerp(-y_L - c_est, c_dev, a_adp); + + if(autoPostGain) + { + /* Clipping reduction is only viable when make-up gain is being + * automated. It modifies the deviation to further attenuate the + * control signal when clipping is detected. The adaptation + * time is sufficiently long enough to suppress further clipping + * at the same output level. + */ + if(autoDeclip) + { + x_G = sideChain[(index + i) & mask]; + if((x_G - c_dev - c_est - y_L) > threshold) + c_dev = x_G - c_est - y_L - threshold; + } + + postGain = -(c_dev + c_est); + } + + sideChain[(index + i) & mask] = expf(postGain - y_L); } - else - { - const ALfloat lower = threshold - (0.5f * knee); - const ALfloat upper = threshold + (0.5f * knee); - const ALfloat m = 0.5f * Slope / knee; + Comp->LastRelease = y_1; + Comp->LastAttack = y_L; + Comp->LastGainDev = c_dev; +} + +/* Combined with the hold time, a look-ahead delay can improve handling of + * fast transients by allowing the envelope time to converge prior to + * reaching the offending impulse. This is best used when operating as a + * limiter. + */ +static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +{ + const ALsizei mask = BUFFERSIZE - 1; + const ALsizei numChans = Comp->NumChans; + const ALsizei indexIn = Comp->DelayIndex; + const ALsizei indexOut = Comp->DelayIndex - Comp->LookAhead; + ALfloat (*restrict delay)[BUFFERSIZE] = Comp->Delay; + ALsizei c, i; + + for(c = 0;c < numChans;c++) + { for(i = 0;i < SamplesToDo;i++) { - ALfloat env = Comp->Envelope[i]; - ALfloat gain; - - if(env > lower && env < upper) - gain = m * (env - lower) * (lower - env); - else - gain = Slope * (threshold - env); + ALfloat sig = OutBuffer[c][i]; - Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain)); + OutBuffer[c][i] = delay[c][(indexOut + i) & mask]; + delay[c][(indexIn + i) & mask] = sig; } } -} + Comp->DelayIndex = (indexIn + SamplesToDo) & mask; +} -Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, - const ALboolean SummedLink, const ALboolean RmsSensing, - const ALfloat AttackTimeMin, const ALfloat AttackTimeMax, - const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, - const ALfloat Ratio, const ALfloat ThresholdDb, - const ALfloat KneeDb, const ALuint SampleRate) +/* The compressor is initialized with the following settings: + * + * NumChans - Number of channels to process. + * SampleRate - Sample rate to process. + * AutoKnee - Whether to automate the knee width parameter. + * AutoAttack - Whether to automate the attack time parameter. + * AutoRelease - Whether to automate the release time parameter. + * AutoPostGain - Whether to automate the make-up (post) gain parameter. + * AutoDeclip - Whether to automate clipping reduction. Ignored when + * not automating make-up gain. + * LookAheadTime - Look-ahead time (in seconds). + * HoldTime - Peak hold-time (in seconds). + * PreGainDb - Gain applied before detection (in dB). + * PostGainDb - Make-up gain applied after compression (in dB). + * ThresholdDb - Triggering threshold (in dB). + * Ratio - Compression ratio (x:1). Set to INFINITY for true + * limiting. Ignored when automating knee width. + * KneeDb - Knee width (in dB). Ignored when automating knee + * width. + * AttackTimeMin - Attack time (in seconds). Acts as a maximum when + * automating attack time. + * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when + * automating release time. + */ +Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, + const ALboolean AutoRelease, const ALboolean AutoPostGain, + const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, + const ALfloat PostGainDb, const ALfloat ThresholdDb, + const ALfloat Ratio, const ALfloat KneeDb, + const ALfloat AttackTime, const ALfloat ReleaseTime) { Compressor *Comp; + ALsizei lookAhead; + ALsizei hold; size_t size; - ALsizei i; + lookAhead = (ALsizei)minf(BUFFERSIZE, roundf(maxf(0.0f, LookAheadTime) * SampleRate)); + hold = (ALsizei)minf(BUFFERSIZE, roundf(maxf(0.0f, HoldTime) * SampleRate)); size = sizeof(*Comp); - if(RmsSensing) - size += sizeof(Comp->RmsWindow[0]) * RMS_WINDOW_SIZE; - Comp = al_calloc(16, size); - Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); - Comp->PostGain = powf(10.0f, PostGainDb / 20.0f); - Comp->SummedLink = SummedLink; - Comp->AttackMin = 1.0f / maxf(0.000001f, AttackTimeMin * SampleRate * logf(10.0f)); - Comp->AttackMax = 1.0f / maxf(0.000001f, AttackTimeMax * SampleRate * logf(10.0f)); - Comp->ReleaseMin = -1.0f / maxf(0.000001f, ReleaseTimeMin * SampleRate * logf(10.0f)); - Comp->ReleaseMax = -1.0f / maxf(0.000001f, ReleaseTimeMax * SampleRate * logf(10.0f)); - Comp->Ratio = Ratio; - Comp->Threshold = ThresholdDb / 20.0f; - Comp->Knee = maxf(0.0f, KneeDb / 20.0f); - Comp->SampleRate = SampleRate; + if(lookAhead > 0) + { + size += sizeof(*Comp->Delay) * NumChans; + if(hold > 0) + size += sizeof(*Comp->Hold); + } - Comp->RmsSum = 0; - if(RmsSensing) - Comp->RmsWindow = (ALuint*)(Comp+1); - else - Comp->RmsWindow = NULL; - Comp->RmsIndex = 0; + Comp = al_calloc(16, size); + Comp->NumChans = NumChans; + Comp->SampleRate = SampleRate; + Comp->Auto.Knee = AutoKnee; + Comp->Auto.Attack = AutoAttack; + Comp->Auto.Release = AutoRelease; + Comp->Auto.PostGain = AutoPostGain; + Comp->Auto.Declip = AutoPostGain && AutoDeclip; + Comp->LookAhead = lookAhead; + Comp->PreGain = powf(10.0f, PreGainDb / 20.0f); + Comp->PostGain = PostGainDb * logf(10.0f) / 20.0f; + Comp->Threshold = ThresholdDb * logf(10.0f) / 20.0f; + Comp->Slope = 1.0f / maxf(1.0f, Ratio) - 1.0f; + Comp->Knee = maxf(0.0f, KneeDb * logf(10.0f) / 20.0f); + Comp->Attack = maxf(1.0f, AttackTime * SampleRate); + Comp->Release = maxf(1.0f, ReleaseTime * SampleRate); + + /* Knee width automation actually treats the compressor as a limiter. By + * varying the knee width, it can effectively be seen as applying + * compression over a wide range of ratios. + */ + if(AutoKnee) + Comp->Slope = -1.0f; + + if(lookAhead > 0) + { + if(hold > 0) + { + Comp->Hold = (SlidingHold*)(Comp + 1); + Comp->Hold->Values[0] = -INFINITY; + Comp->Hold->Expiries[0] = hold; + Comp->Hold->Length = hold; + Comp->Delay = (ALfloat(*)[])(Comp->Hold + 1); + } + else + { + Comp->Delay = (ALfloat(*)[])(Comp + 1); + } + } - for(i = 0;i < BUFFERSIZE;i++) - Comp->Envelope[i] = 0.0f; - Comp->EnvLast = -6.0f; + Comp->CrestCoeff = expf(-1.0f / (0.200f * SampleRate)); // 200ms + Comp->GainEstimate = Comp->Threshold * -0.5f * Comp->Slope; + Comp->AdaptCoeff = expf(-1.0f / (2.0f * SampleRate)); // 2s return Comp; } -void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, - ALfloat (*restrict OutBuffer)[BUFFERSIZE]) +void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) { + const ALsizei mask = 2*BUFFERSIZE - 1; + const ALsizei numChans = Comp->NumChans; + const ALfloat preGain = Comp->PreGain; + const ALsizei index = Comp->SideChainIndex; + ALfloat *restrict sideChain = Comp->SideChain; ALsizei c, i; - if(Comp->PreGain != 1.0f) + if(preGain != 1.0f) { - for(c = 0;c < NumChans;c++) + for(c = 0;c < numChans;c++) { for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= Comp->PreGain; + OutBuffer[c][i] *= preGain; } } - if(Comp->SummedLink) - SumChannels(Comp, NumChans, SamplesToDo, OutBuffer); - else - MaxChannels(Comp, NumChans, SamplesToDo, OutBuffer); + LinkChannels(Comp, SamplesToDo, OutBuffer); - if(Comp->RmsWindow) - RmsDetection(Comp, SamplesToDo); - FollowEnvelope(Comp, SamplesToDo); + if(Comp->Auto.Attack || Comp->Auto.Release) + CrestDetector(Comp, SamplesToDo); - if(Comp->Ratio > 0.0f) - EnvelopeGain(Comp, SamplesToDo, 1.0f - (1.0f / Comp->Ratio)); + if(Comp->Hold) + PeakHoldDetector(Comp, SamplesToDo); else - EnvelopeGain(Comp, SamplesToDo, 1.0f); + PeakDetector(Comp, SamplesToDo); - if(Comp->PostGain != 1.0f) - { - for(i = 0;i < SamplesToDo;i++) - Comp->Envelope[i] *= Comp->PostGain; - } - for(c = 0;c < NumChans;c++) + GainCompressor(Comp, SamplesToDo); + + if(Comp->Delay) + SignalDelay(Comp, SamplesToDo, OutBuffer); + + for(c = 0;c < numChans;c++) { for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= Comp->Envelope[i]; + OutBuffer[c][i] *= sideChain[(index + i) & mask]; } + + Comp->SideChainIndex = (index + SamplesToDo) & mask; } diff --git a/Alc/mastering.h b/Alc/mastering.h index 0a7b4901..206a6c91 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -6,51 +6,100 @@ /* For BUFFERSIZE. */ #include "alMain.h" +/* These structures assume BUFFERSIZE is a power of 2. + */ +typedef struct SlidingHold +{ + ALfloat Values[BUFFERSIZE]; + ALsizei Expiries[BUFFERSIZE]; + ALsizei LowerIndex; + ALsizei UpperIndex; + ALsizei Length; +} SlidingHold; + +/* General topology and basic automation was based on the following paper: + * + * D. Giannoulis, M. Massberg and J. D. Reiss, + * "Parameter Automation in a Dynamic Range Compressor," + * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 + * + * Available (along with supplemental reading) at: + * + * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ + */ typedef struct Compressor { + ALsizei NumChans; + ALuint SampleRate; + struct { + ALuint Knee:1; + ALuint Attack:1; + ALuint Release:1; + ALuint PostGain:1; + ALuint Declip:1; + } Auto; + ALsizei LookAhead; ALfloat PreGain; ALfloat PostGain; - ALboolean SummedLink; - ALfloat AttackMin; - ALfloat AttackMax; - ALfloat ReleaseMin; - ALfloat ReleaseMax; - ALfloat Ratio; ALfloat Threshold; + ALfloat Slope; ALfloat Knee; - ALuint SampleRate; - - ALuint RmsSum; - ALuint *RmsWindow; - ALsizei RmsIndex; - ALfloat Envelope[BUFFERSIZE]; - ALfloat EnvLast; + ALfloat Attack; + ALfloat Release; + ALfloat SideChain[2*BUFFERSIZE]; + ALsizei SideChainIndex; + ALfloat CrestFactor[BUFFERSIZE]; + SlidingHold *Hold; + ALfloat (*Delay)[BUFFERSIZE]; + ALsizei DelayIndex; + ALfloat CrestCoeff; + ALfloat GainEstimate; + ALfloat AdaptCoeff; + ALfloat LastPeakSq; + ALfloat LastRmsSq; + ALfloat LastRelease; + ALfloat LastAttack; + ALfloat LastGainDev; } Compressor; -/* The compressor requires the following information for proper - * initialization: +/* The compressor is initialized with the following settings: * + * NumChans - Number of channels to process. + * SampleRate - Sample rate to process. + * AutoKnee - Whether to automate the knee width parameter. + * AutoAttack - Whether to automate the attack time parameter. + * AutoRelease - Whether to automate the release time parameter. + * AutoPostGain - Whether to automate the make-up (post) gain parameter. + * AutoDeclip - Whether to automate clipping reduction. Ignored when + * not automating make-up gain. + * LookAheadTime - Look-ahead time (in seconds). + * HoldTime - Peak hold-time (in seconds). * PreGainDb - Gain applied before detection (in dB). - * PostGainDb - Gain applied after compression (in dB). - * SummedLink - Whether to use summed (true) or maxed (false) linking. - * RmsSensing - Whether to use RMS (true) or Peak (false) sensing. - * AttackTimeMin - Minimum attack time (in seconds). - * AttackTimeMax - Maximum attack time. Automates when min != max. - * ReleaseTimeMin - Minimum release time (in seconds). - * ReleaseTimeMax - Maximum release time. Automates when min != max. - * Ratio - Compression ratio (x:1). Set to 0 for true limiter. + * PostGainDb - Make-up gain applied after compression (in dB). * ThresholdDb - Triggering threshold (in dB). - * KneeDb - Knee width (below threshold; in dB). - * SampleRate - Sample rate to process. + * Ratio - Compression ratio (x:1). Set to INFINIFTY for true + * limiting. Ignored when automating knee width. + * KneeDb - Knee width (in dB). Ignored when automating knee + * width. + * AttackTimeMin - Attack time (in seconds). Acts as a maximum when + * automating attack time. + * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when + * automating release time. */ -Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb, - const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin, - const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax, - const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb, - const ALuint SampleRate); +Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, + const ALboolean AutoKnee, const ALboolean AutoAttack, + const ALboolean AutoRelease, const ALboolean AutoPostGain, + const ALboolean AutoDeclip, const ALfloat LookAheadTime, + const ALfloat HoldTime, const ALfloat PreGainDb, + const ALfloat PostGainDb, const ALfloat ThresholdDb, + const ALfloat Ratio, const ALfloat KneeDb, + const ALfloat AttackTime, const ALfloat ReleaseTime); -void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo, +void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]); +inline ALsizei GetCompressorChannelCount(const Compressor *Comp) +{ return Comp->NumChans; } + inline ALuint GetCompressorSampleRate(const Compressor *Comp) { return Comp->SampleRate; } -- cgit v1.2.3 From 2d6309d6fc68e5c2f658b48e6e44ba10be42848e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Sep 2018 10:29:38 -0700 Subject: Don't hardcode the limiter threshold It's now calculated from the output sample type and dither depth. --- Alc/ALc.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index ecacf8c5..a65a56b6 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1704,11 +1704,11 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } -struct Compressor *CreateDeviceLimiter(const ALCdevice *device) +static struct Compressor *CreateDeviceLimiter(const ALCdevice *device, const ALfloat threshold) { return CompressorInit(device->RealOut.NumChannels, device->Frequency, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, AL_TRUE, 0.001f, 0.002f, - 0.0f, 0.0f, -0.0003f, INFINITY, 0.0f, 0.020f, 0.200f); + 0.0f, 0.0f, threshold, INFINITY, 0.0f, 0.020f, 0.200f); } /* UpdateClockBase @@ -2232,12 +2232,27 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) */ if(gainLimiter != ALC_FALSE) { - if(!device->Limiter || device->Frequency != GetCompressorSampleRate(device->Limiter) || - device->RealOut.NumChannels != GetCompressorChannelCount(device->Limiter)) + ALfloat thrshld = 1.0f; + switch(device->FmtType) { - al_free(device->Limiter); - device->Limiter = CreateDeviceLimiter(device); + case DevFmtByte: + case DevFmtUByte: + thrshld = 127.0f / 128.0f; + break; + case DevFmtShort: + case DevFmtUShort: + thrshld = 32767.0f / 32768.0f; + break; + case DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + break; } + if(device->DitherDepth > 0.0f) + thrshld -= 1.0f / device->DitherDepth; + + al_free(device->Limiter); + device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); } else { @@ -4213,7 +4228,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ERR("Unsupported ambi-format: %s\n", fmt); } - device->Limiter = CreateDeviceLimiter(device); + device->Limiter = CreateDeviceLimiter(device, 0.0f); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); @@ -4542,7 +4557,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN // Open the "backend" V(device->Backend,open)("Loopback"); - device->Limiter = CreateDeviceLimiter(device); + device->Limiter = CreateDeviceLimiter(device, 0.0f); { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); -- cgit v1.2.3 From 79314c4461333c7dfd7d425d69ffd121d6c163b6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 25 Sep 2018 23:05:27 -0700 Subject: Include the limiter's lookAhead delay in the device latency --- Alc/ALc.c | 12 +++++++++--- Alc/backends/base.c | 1 + Alc/backends/base.h | 9 +++++++++ Alc/mastering.c | 6 +++--- OpenAL32/Include/alMain.h | 1 + OpenAL32/alSource.c | 4 ++-- 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index a65a56b6..70663780 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2051,6 +2051,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) device->RealOut.NumChannels = 0; UpdateClockBase(device); + device->FixedLatency = 0; device->DitherSeed = DITHER_RNG_SEED; @@ -2253,6 +2254,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Limiter); device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); + device->FixedLatency += (ALuint)(device->Limiter->LookAhead * DEVICE_CLOCK_RES / + device->Frequency); } else { @@ -2263,6 +2266,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) aluSelectPostProcess(device); + TRACE("Fixed device latency: %uns\n", device->FixedLatency); + /* Need to delay returning failure until replacement Send arrays have been * allocated with the appropriate size. */ @@ -2422,6 +2427,7 @@ static void InitDevice(ALCdevice *device, enum DeviceType type) device->ClockBase = 0; device->SamplesDone = 0; + device->FixedLatency = 0; device->SourcesMax = 0; device->AuxiliaryEffectSlotMax = 0; @@ -3637,7 +3643,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = ALC_OUTPUT_LIMITER_SOFT; values[i++] = device->Limiter ? ALC_TRUE : ALC_FALSE; - clock = V0(device->Backend,getClockLatency)(); + clock = GetClockLatency(device); values[i++] = ALC_DEVICE_CLOCK_SOFT; values[i++] = clock.ClockTime; @@ -3663,7 +3669,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, case ALC_DEVICE_LATENCY_SOFT: almtx_lock(&device->BackendLock); - clock = V0(device->Backend,getClockLatency)(); + clock = GetClockLatency(device); almtx_unlock(&device->BackendLock); *values = clock.Latency; break; @@ -3674,7 +3680,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, else { almtx_lock(&device->BackendLock); - clock = V0(device->Backend,getClockLatency)(); + clock = GetClockLatency(device); almtx_unlock(&device->BackendLock); values[0] = clock.ClockTime; values[1] = clock.Latency; diff --git a/Alc/backends/base.c b/Alc/backends/base.c index a451fee9..9d8614b1 100644 --- a/Alc/backends/base.c +++ b/Alc/backends/base.c @@ -12,6 +12,7 @@ extern inline ALuint64 GetDeviceClockTime(ALCdevice *device); extern inline void ALCdevice_Lock(ALCdevice *device); extern inline void ALCdevice_Unlock(ALCdevice *device); +extern inline ClockLatency GetClockLatency(ALCdevice *device); /* Base ALCbackend method implementations. */ void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) diff --git a/Alc/backends/base.h b/Alc/backends/base.h index 0de4e590..03db56e9 100644 --- a/Alc/backends/base.h +++ b/Alc/backends/base.h @@ -162,6 +162,15 @@ inline void ALCdevice_Lock(ALCdevice *device) inline void ALCdevice_Unlock(ALCdevice *device) { V0(device->Backend,unlock)(); } + +inline ClockLatency GetClockLatency(ALCdevice *device) +{ + ClockLatency ret = V0(device->Backend,getClockLatency)(); + ret.Latency += device->FixedLatency; + return ret; +} + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/Alc/mastering.c b/Alc/mastering.c index 78f6038d..a957066a 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -344,10 +344,10 @@ Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, ALsizei hold; size_t size; - lookAhead = (ALsizei)minf(BUFFERSIZE, roundf(maxf(0.0f, LookAheadTime) * SampleRate)); - hold = (ALsizei)minf(BUFFERSIZE, roundf(maxf(0.0f, HoldTime) * SampleRate)); - size = sizeof(*Comp); + lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE); + hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE); + size = sizeof(*Comp); if(lookAhead > 0) { size += sizeof(*Comp->Delay) * NumChans; diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index 3e328157..dce51301 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -676,6 +676,7 @@ struct ALCdevice_struct { ALuint64 ClockBase; ALuint SamplesDone; + ALuint FixedLatency; /* Temp storage used for mixer processing. */ alignas(16) ALfloat TempBuffer[4][BUFFERSIZE]; diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 81d8c262..d7c68e4e 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1295,7 +1295,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p */ values[0] = GetSourceSecOffset(Source, Context, &srcclock); almtx_lock(&device->BackendLock); - clocktime = V0(device->Backend,getClockLatency)(); + clocktime = GetClockLatency(device); almtx_unlock(&device->BackendLock); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = (ALdouble)clocktime.Latency / 1000000000.0; @@ -1559,7 +1559,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp */ values[0] = GetSourceSampleOffset(Source, Context, &srcclock); almtx_lock(&device->BackendLock); - clocktime = V0(device->Backend,getClockLatency)(); + clocktime = GetClockLatency(device); almtx_unlock(&device->BackendLock); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = clocktime.Latency; -- cgit v1.2.3 From 1dee902a5f5c5529d494c3d95b2ef7db63ad3eba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 26 Sep 2018 08:23:48 -0700 Subject: Update changelog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index ca798fbb..d234c14f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,9 @@ openal-soft-1.19.1: Fixed OpenSL capture. + Improved output limiter response, better ensuring the sample amplitude is + clamped for output. + openal-soft-1.19.0: Implemented the ALC_SOFT_device_clock extension. -- cgit v1.2.3 From 1684b2cc5f41d03966d2a8e03c739aa9933e2348 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Sep 2018 16:42:22 -0700 Subject: Constify a couple more variables --- Alc/mastering.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index a957066a..52813a54 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -186,12 +186,12 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) const ALfloat attack = Comp->Attack; const ALfloat release = Comp->Release; const ALsizei index = Comp->SideChainIndex; + const ALfloat c_est = Comp->GainEstimate; + const ALfloat a_adp = Comp->AdaptCoeff; const ALfloat *restrict crestFactor = Comp->CrestFactor; ALfloat *restrict sideChain = Comp->SideChain; ALfloat postGain = Comp->PostGain; ALfloat knee = Comp->Knee; - ALfloat c_est = Comp->GainEstimate; - ALfloat a_adp = Comp->AdaptCoeff; ALfloat t_att = attack; ALfloat t_rel = release - attack; ALfloat a_att = expf(-1.0f / t_att); -- cgit v1.2.3 From 51a447852f17b19144e879601cdfa09a6bbdc3bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Sep 2018 18:34:21 -0700 Subject: Simplify a lower-bound clamp --- Alc/mastering.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 52813a54..e7908828 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -263,8 +263,7 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) if(autoDeclip) { x_G = sideChain[(index + i) & mask]; - if((x_G - c_dev - c_est - y_L) > threshold) - c_dev = x_G - c_est - y_L - threshold; + c_dev = maxf(c_dev, x_G - y_L - threshold - c_est); } postGain = -(c_dev + c_est); -- cgit v1.2.3 From 0396c0ecd2a10ed74cf1f75e58242b1595598b2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Sep 2018 09:47:05 -0700 Subject: Add some assumes for the limiter --- Alc/mastering.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Alc/mastering.c b/Alc/mastering.c index e7908828..306f0941 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -79,6 +79,9 @@ static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (* ALfloat *restrict sideChain = Comp->SideChain; ALsizei c, i; + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + for(i = 0;i < SamplesToDo;i++) sideChain[(index + i) & mask] = 0.0f; @@ -109,6 +112,8 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) ALfloat y2_rms = Comp->LastRmsSq; ALsizei i; + ASSUME(SamplesToDo > 0); + for(i = 0;i < SamplesToDo;i++) { ALfloat x_abs = sideChain[(index + i) & mask]; @@ -134,6 +139,8 @@ static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) ALfloat *restrict sideChain = Comp->SideChain; ALsizei i; + ASSUME(SamplesToDo > 0); + for(i = 0;i < SamplesToDo;i++) { ALuint offset = (index + i) & mask; @@ -155,6 +162,8 @@ static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) SlidingHold *hold = Comp->Hold; ALsizei i; + ASSUME(SamplesToDo > 0); + for(i = 0;i < SamplesToDo;i++) { ALsizei offset = (index + i) & mask; @@ -201,6 +210,8 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) ALfloat c_dev = Comp->LastGainDev; ALsizei i; + ASSUME(SamplesToDo > 0); + for(i = 0;i < SamplesToDo;i++) { const ALfloat y2_crest = crestFactor[i]; @@ -291,6 +302,9 @@ static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*r ALfloat (*restrict delay)[BUFFERSIZE] = Comp->Delay; ALsizei c, i; + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + for(c = 0;c < numChans;c++) { for(i = 0;i < SamplesToDo;i++) @@ -410,6 +424,9 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*res ALfloat *restrict sideChain = Comp->SideChain; ALsizei c, i; + ASSUME(SamplesToDo > 0); + ASSUME(numChans > 0); + if(preGain != 1.0f) { for(c = 0;c < numChans;c++) -- cgit v1.2.3 From 32494e72a55569b5de1d899663f0c76160e85cd9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Sep 2018 11:54:45 -0700 Subject: Don't use a ringbuffer design for the limiter's side chain Rather than continuously wrapping when used, each update uses it from the front and copies the tail to the front at the end. This allows for more effficient accesses in loops. --- Alc/mastering.c | 52 +++++++++++++++++++++------------------------------- Alc/mastering.h | 24 ++++++++++++++++-------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 306f0941..285f2f6d 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -73,8 +73,7 @@ static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) */ static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) { - const ALsizei mask = 2*BUFFERSIZE - 1; - const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALsizei index = Comp->LookAhead; const ALsizei numChans = Comp->NumChans; ALfloat *restrict sideChain = Comp->SideChain; ALsizei c, i; @@ -83,15 +82,15 @@ static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (* ASSUME(numChans > 0); for(i = 0;i < SamplesToDo;i++) - sideChain[(index + i) & mask] = 0.0f; + sideChain[index + i] = 0.0f; for(c = 0;c < numChans;c++) { + ALsizei offset = index; for(i = 0;i < SamplesToDo;i++) { - ALsizei offset = (index + i) & mask; - sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i])); + ++offset; } } } @@ -103,9 +102,8 @@ static void LinkChannels(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (* */ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei mask = 2*BUFFERSIZE - 1; const ALfloat a_crest = Comp->CrestCoeff; - const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALsizei index = Comp->LookAhead; const ALfloat *restrict sideChain = Comp->SideChain; ALfloat *restrict crestFactor = Comp->CrestFactor; ALfloat y2_peak = Comp->LastPeakSq; @@ -116,7 +114,7 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) for(i = 0;i < SamplesToDo;i++) { - ALfloat x_abs = sideChain[(index + i) & mask]; + ALfloat x_abs = sideChain[index + i]; ALfloat x2 = maxf(0.000001f, x_abs * x_abs); y2_peak = maxf(x2, lerp(x2, y2_peak, a_crest)); @@ -134,8 +132,7 @@ static void CrestDetector(Compressor *Comp, const ALsizei SamplesToDo) */ static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei mask = 2*BUFFERSIZE - 1; - const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALsizei index = Comp->LookAhead; ALfloat *restrict sideChain = Comp->SideChain; ALsizei i; @@ -143,8 +140,8 @@ static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) for(i = 0;i < SamplesToDo;i++) { - ALuint offset = (index + i) & mask; - ALfloat x_abs = sideChain[offset]; + const ALuint offset = index + i; + const ALfloat x_abs = sideChain[offset]; sideChain[offset] = logf(maxf(0.000001f, x_abs)); } @@ -156,8 +153,7 @@ static void PeakDetector(Compressor *Comp, const ALsizei SamplesToDo) */ static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei mask = 2*BUFFERSIZE - 1; - const ALsizei index = Comp->SideChainIndex + Comp->LookAhead; + const ALsizei index = Comp->LookAhead; ALfloat *restrict sideChain = Comp->SideChain; SlidingHold *hold = Comp->Hold; ALsizei i; @@ -166,9 +162,9 @@ static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) for(i = 0;i < SamplesToDo;i++) { - ALsizei offset = (index + i) & mask; - ALfloat x_abs = sideChain[offset]; - ALfloat x_G = logf(maxf(0.000001f, x_abs)); + const ALsizei offset = index + i; + const ALfloat x_abs = sideChain[offset]; + const ALfloat x_G = logf(maxf(0.000001f, x_abs)); sideChain[offset] = UpdateSlidingHold(hold, i, x_G); } @@ -183,7 +179,6 @@ static void PeakHoldDetector(Compressor *Comp, const ALsizei SamplesToDo) */ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) { - const ALsizei mask = 2*BUFFERSIZE - 1; const bool autoKnee = Comp->Auto.Knee; const bool autoAttack = Comp->Auto.Attack; const bool autoRelease = Comp->Auto.Release; @@ -194,7 +189,6 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) const ALfloat slope = Comp->Slope; const ALfloat attack = Comp->Attack; const ALfloat release = Comp->Release; - const ALsizei index = Comp->SideChainIndex; const ALfloat c_est = Comp->GainEstimate; const ALfloat a_adp = Comp->AdaptCoeff; const ALfloat *restrict crestFactor = Comp->CrestFactor; @@ -215,8 +209,8 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) for(i = 0;i < SamplesToDo;i++) { const ALfloat y2_crest = crestFactor[i]; - ALfloat x_G = sideChain[(index + lookAhead + i) & mask]; - ALfloat x_over = x_G - threshold; + const ALfloat x_G = sideChain[lookAhead + i]; + const ALfloat x_over = x_G - threshold; ALfloat knee_h; ALfloat y_G; ALfloat x_L; @@ -272,15 +266,12 @@ static void GainCompressor(Compressor *Comp, const ALsizei SamplesToDo) * at the same output level. */ if(autoDeclip) - { - x_G = sideChain[(index + i) & mask]; - c_dev = maxf(c_dev, x_G - y_L - threshold - c_est); - } + c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est); postGain = -(c_dev + c_est); } - sideChain[(index + i) & mask] = expf(postGain - y_L); + sideChain[i] = expf(postGain - y_L); } Comp->LastRelease = y_1; @@ -417,11 +408,9 @@ Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]) { - const ALsizei mask = 2*BUFFERSIZE - 1; const ALsizei numChans = Comp->NumChans; const ALfloat preGain = Comp->PreGain; - const ALsizei index = Comp->SideChainIndex; - ALfloat *restrict sideChain = Comp->SideChain; + ALfloat *restrict sideChain; ALsizei c, i; ASSUME(SamplesToDo > 0); @@ -451,11 +440,12 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*res if(Comp->Delay) SignalDelay(Comp, SamplesToDo, OutBuffer); + sideChain = Comp->SideChain; for(c = 0;c < numChans;c++) { for(i = 0;i < SamplesToDo;i++) - OutBuffer[c][i] *= sideChain[(index + i) & mask]; + OutBuffer[c][i] *= sideChain[i]; } - Comp->SideChainIndex = (index + SamplesToDo) & mask; + memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat)); } diff --git a/Alc/mastering.h b/Alc/mastering.h index 206a6c91..67738543 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -30,30 +30,38 @@ typedef struct SlidingHold typedef struct Compressor { ALsizei NumChans; ALuint SampleRate; + struct { - ALuint Knee:1; - ALuint Attack:1; - ALuint Release:1; - ALuint PostGain:1; - ALuint Declip:1; + ALuint Knee : 1; + ALuint Attack : 1; + ALuint Release : 1; + ALuint PostGain : 1; + ALuint Declip : 1; } Auto; + ALsizei LookAhead; + ALfloat PreGain; ALfloat PostGain; + ALfloat Threshold; ALfloat Slope; ALfloat Knee; + ALfloat Attack; ALfloat Release; - ALfloat SideChain[2*BUFFERSIZE]; - ALsizei SideChainIndex; - ALfloat CrestFactor[BUFFERSIZE]; + + alignas(16) ALfloat SideChain[2*BUFFERSIZE]; + alignas(16) ALfloat CrestFactor[BUFFERSIZE]; + SlidingHold *Hold; ALfloat (*Delay)[BUFFERSIZE]; ALsizei DelayIndex; + ALfloat CrestCoeff; ALfloat GainEstimate; ALfloat AdaptCoeff; + ALfloat LastPeakSq; ALfloat LastRmsSq; ALfloat LastRelease; -- cgit v1.2.3 From d5a78f0843571c55d9c7671c49c4b5a092ae951f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Sep 2018 18:48:28 -0700 Subject: Improve a couple loops Avoid masking the index with each iteration, and instead do up to when the mask would apply. This allows for better optimizations, in particular fewer instructions and better chances for vectorization. --- Alc/mastering.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 285f2f6d..fb831f46 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -18,7 +18,7 @@ extern inline ALuint GetCompressorSampleRate(const Compressor *Comp); * * http://www.richardhartersworld.com/cri/2001/slidingmin.html */ -static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) { const ALsizei mask = BUFFERSIZE - 1; const ALsizei length = Hold->Length; @@ -38,8 +38,14 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo } else { - while(in >= values[lowerIndex]) - lowerIndex = (lowerIndex - 1) & mask; + do { + do { + if(!(in >= values[lowerIndex])) + goto found_place; + } while(lowerIndex--); + lowerIndex = mask; + } while(1); + found_place: lowerIndex = (lowerIndex + 1) & mask; values[lowerIndex] = in; @@ -54,16 +60,18 @@ static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALflo static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) { - const ALsizei mask = BUFFERSIZE - 1; const ALsizei lowerIndex = Hold->LowerIndex; ALsizei *restrict expiries = Hold->Expiries; ALsizei i = Hold->UpperIndex; - while(i != lowerIndex) + if(lowerIndex < i) { - expiries[i] -= n; - i = (i + 1) & mask; + for(;i != BUFFERSIZE;i++) + expiries[i] -= n; + i = 0; } + for(;i != lowerIndex;i++) + expiries[i] -= n; expiries[i] -= n; } -- cgit v1.2.3 From 7ad4f753a42a4ff9c4ce2be0a848f8aaccb86454 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Sep 2018 19:39:49 -0700 Subject: Fix some length ranges --- Alc/mastering.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index fb831f46..b92390bb 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -356,8 +356,14 @@ Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, ALsizei hold; size_t size; - lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE); - hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE); + lookAhead = (ALsizei)clampf(roundf(LookAheadTime*SampleRate), 0.0f, BUFFERSIZE-1); + hold = (ALsizei)clampf(roundf(HoldTime*SampleRate), 0.0f, BUFFERSIZE-1); + /* The sliding hold implementation doesn't handle a length of 1. A 1-sample + * hold is useless anyway, it would only ever give back what was just given + * to it. + */ + if(hold == 1) + hold = 0; size = sizeof(*Comp); if(lookAhead > 0) -- cgit v1.2.3 From 1860b2ec8a1927ce98e516f498dbdf19419ae0a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Sep 2018 12:08:01 -0700 Subject: Make the Compressor struct opaque --- Alc/ALc.c | 4 ++-- Alc/mastering.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- Alc/mastering.h | 71 +++------------------------------------------------------ 3 files changed, 71 insertions(+), 73 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 70663780..de6a2b75 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2254,8 +2254,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) al_free(device->Limiter); device->Limiter = CreateDeviceLimiter(device, log10f(thrshld) * 20.0f); - device->FixedLatency += (ALuint)(device->Limiter->LookAhead * DEVICE_CLOCK_RES / - device->Frequency); + device->FixedLatency += (ALuint)(GetCompressorLookAhead(device->Limiter) * + DEVICE_CLOCK_RES / device->Frequency); } else { diff --git a/Alc/mastering.c b/Alc/mastering.c index b92390bb..f443de37 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -7,8 +7,67 @@ #include "almalloc.h" -extern inline ALsizei GetCompressorChannelCount(const Compressor *Comp); -extern inline ALuint GetCompressorSampleRate(const Compressor *Comp); +/* These structures assume BUFFERSIZE is a power of 2. + */ +typedef struct SlidingHold { + ALfloat Values[BUFFERSIZE]; + ALsizei Expiries[BUFFERSIZE]; + ALsizei LowerIndex; + ALsizei UpperIndex; + ALsizei Length; +} SlidingHold; + +/* General topology and basic automation was based on the following paper: + * + * D. Giannoulis, M. Massberg and J. D. Reiss, + * "Parameter Automation in a Dynamic Range Compressor," + * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 + * + * Available (along with supplemental reading) at: + * + * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ + */ +typedef struct Compressor { + ALsizei NumChans; + ALuint SampleRate; + + struct { + ALuint Knee : 1; + ALuint Attack : 1; + ALuint Release : 1; + ALuint PostGain : 1; + ALuint Declip : 1; + } Auto; + + ALsizei LookAhead; + + ALfloat PreGain; + ALfloat PostGain; + + ALfloat Threshold; + ALfloat Slope; + ALfloat Knee; + + ALfloat Attack; + ALfloat Release; + + alignas(16) ALfloat SideChain[2*BUFFERSIZE]; + alignas(16) ALfloat CrestFactor[BUFFERSIZE]; + + SlidingHold *Hold; + ALfloat (*Delay)[BUFFERSIZE]; + ALsizei DelayIndex; + + ALfloat CrestCoeff; + ALfloat GainEstimate; + ALfloat AdaptCoeff; + + ALfloat LastPeakSq; + ALfloat LastRmsSq; + ALfloat LastRelease; + ALfloat LastAttack; + ALfloat LastGainDev; +} Compressor; /* This sliding hold follows the input level with an instant attack and a @@ -342,7 +401,7 @@ static void SignalDelay(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*r * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, +Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, @@ -463,3 +522,7 @@ void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*res memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat)); } + + +ALsizei GetCompressorLookAhead(const Compressor *Comp) +{ return Comp->LookAhead; } diff --git a/Alc/mastering.h b/Alc/mastering.h index 67738543..b68b0de1 100644 --- a/Alc/mastering.h +++ b/Alc/mastering.h @@ -6,68 +6,7 @@ /* For BUFFERSIZE. */ #include "alMain.h" -/* These structures assume BUFFERSIZE is a power of 2. - */ -typedef struct SlidingHold -{ - ALfloat Values[BUFFERSIZE]; - ALsizei Expiries[BUFFERSIZE]; - ALsizei LowerIndex; - ALsizei UpperIndex; - ALsizei Length; -} SlidingHold; - -/* General topology and basic automation was based on the following paper: - * - * D. Giannoulis, M. Massberg and J. D. Reiss, - * "Parameter Automation in a Dynamic Range Compressor," - * Journal of the Audio Engineering Society, v61 (10), Oct. 2013 - * - * Available (along with supplemental reading) at: - * - * http://c4dm.eecs.qmul.ac.uk/audioengineering/compressors/ - */ -typedef struct Compressor { - ALsizei NumChans; - ALuint SampleRate; - - struct { - ALuint Knee : 1; - ALuint Attack : 1; - ALuint Release : 1; - ALuint PostGain : 1; - ALuint Declip : 1; - } Auto; - - ALsizei LookAhead; - - ALfloat PreGain; - ALfloat PostGain; - - ALfloat Threshold; - ALfloat Slope; - ALfloat Knee; - - ALfloat Attack; - ALfloat Release; - - alignas(16) ALfloat SideChain[2*BUFFERSIZE]; - alignas(16) ALfloat CrestFactor[BUFFERSIZE]; - - SlidingHold *Hold; - ALfloat (*Delay)[BUFFERSIZE]; - ALsizei DelayIndex; - - ALfloat CrestCoeff; - ALfloat GainEstimate; - ALfloat AdaptCoeff; - - ALfloat LastPeakSq; - ALfloat LastRmsSq; - ALfloat LastRelease; - ALfloat LastAttack; - ALfloat LastGainDev; -} Compressor; +struct Compressor; /* The compressor is initialized with the following settings: * @@ -93,7 +32,7 @@ typedef struct Compressor { * ReleaseTimeMin - Release time (in seconds). Acts as a maximum when * automating release time. */ -Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, +struct Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, const ALboolean AutoKnee, const ALboolean AutoAttack, const ALboolean AutoRelease, const ALboolean AutoPostGain, const ALboolean AutoDeclip, const ALfloat LookAheadTime, @@ -105,10 +44,6 @@ Compressor* CompressorInit(const ALuint NumChans, const ALuint SampleRate, void ApplyCompression(struct Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE]); -inline ALsizei GetCompressorChannelCount(const Compressor *Comp) -{ return Comp->NumChans; } - -inline ALuint GetCompressorSampleRate(const Compressor *Comp) -{ return Comp->SampleRate; } +ALsizei GetCompressorLookAhead(const struct Compressor *Comp); #endif /* MASTERING_H */ -- cgit v1.2.3 From 1d1acc0c34228f68ccfed25ec61fb6982233ab2e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Sep 2018 12:12:27 -0700 Subject: Ensure BUFFERSIZE is a power of 2 --- Alc/mastering.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index f443de37..637cd8d2 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -5,10 +5,12 @@ #include "mastering.h" #include "alu.h" #include "almalloc.h" +#include "static_assert.h" -/* These structures assume BUFFERSIZE is a power of 2. - */ +/* These structures assume BUFFERSIZE is a power of 2. */ +static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); + typedef struct SlidingHold { ALfloat Values[BUFFERSIZE]; ALsizei Expiries[BUFFERSIZE]; -- cgit v1.2.3 From ed8f44d102b6434535683a7e2d32fbac5f775b23 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Sep 2018 16:34:00 -0700 Subject: Don't scale the reverb fade counter so much --- Alc/effects/reverb.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index cfce5623..8ebc089e 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1195,6 +1195,7 @@ static void VectorAllpass_Faded(ALfloat (*restrict samples)[MAX_UPDATE_SAMPLES], ASSUME(todo > 0); + fade *= 1.0f/FADE_SAMPLES; for(j = 0;j < NUM_LINES;j++) { vap_offset[j][0] = offset-Vap->Offset[j][0]; @@ -1301,7 +1302,6 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi const ALfloat mixX = State->MixX; const ALfloat mixY = State->MixY; ALsizei late_feed_tap; - ALfloat fadeCount; ALsizei i, j; ASSUME(todo > 0); @@ -1313,8 +1313,8 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi ALfloat oldCoeff = State->EarlyDelayCoeff[j][0]; ALfloat oldCoeffStep = -oldCoeff / FADE_SAMPLES; ALfloat newCoeffStep = State->EarlyDelayCoeff[j][1] / FADE_SAMPLES; + ALfloat fadeCount = fade; - fadeCount = fade * FADE_SAMPLES; for(i = 0;i < todo;i++) { const ALfloat fade0 = oldCoeff + oldCoeffStep*fadeCount; @@ -1335,8 +1335,8 @@ static void EarlyReflection_Faded(ReverbState *State, ALsizei offset, const ALsi ALfloat feedb_oldCoeff = State->Early.Coeff[j][0]; ALfloat feedb_oldCoeffStep = -feedb_oldCoeff / FADE_SAMPLES; ALfloat feedb_newCoeffStep = State->Early.Coeff[j][1] / FADE_SAMPLES; + ALfloat fadeCount = fade; - fadeCount = fade * FADE_SAMPLES; for(i = 0;i < todo;i++) { const ALfloat fade0 = feedb_oldCoeff + feedb_oldCoeffStep*fadeCount; @@ -1440,7 +1440,8 @@ static void LateReverb_Faded(ReverbState *State, ALsizei offset, const ALsizei t ALsizei late_delay_tap1 = offset - State->LateDelayTap[j][1]; ALsizei late_feedb_tap0 = offset - State->Late.Offset[j][0]; ALsizei late_feedb_tap1 = offset - State->Late.Offset[j][1]; - ALfloat fadeCount = fade * FADE_SAMPLES; + ALfloat fadeCount = fade; + for(i = 0;i < todo;i++) { const ALfloat fade0 = oldDensityGain + oldDensityStep*fadeCount; @@ -1510,7 +1511,7 @@ static ALvoid ReverbState_process(ReverbState *State, ALsizei SamplesToDo, const if(UNLIKELY(fadeCount < FADE_SAMPLES)) { - ALfloat fade = (ALfloat)fadeCount / FADE_SAMPLES; + ALfloat fade = (ALfloat)fadeCount; /* Generate early reflections. */ EarlyReflection_Faded(State, offset, todo, fade, samples); -- cgit v1.2.3 From 052fdd67cdcb7bdade54c20b4595fc390b4d86b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 1 Oct 2018 15:59:05 -0700 Subject: Use < instead of != for some loop checks --- Alc/mastering.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 637cd8d2..e1bc4ae7 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -127,11 +127,11 @@ static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n) if(lowerIndex < i) { - for(;i != BUFFERSIZE;i++) + for(;i < BUFFERSIZE;i++) expiries[i] -= n; i = 0; } - for(;i != lowerIndex;i++) + for(;i < lowerIndex;i++) expiries[i] -= n; expiries[i] -= n; -- cgit v1.2.3 From 493c8bbc833a4b5f58c82913af913946926b194f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Oct 2018 12:25:26 -0700 Subject: Add back an inadvertently removed static --- Alc/mastering.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index e1bc4ae7..52ff5b23 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -79,7 +79,7 @@ typedef struct Compressor { * * http://www.richardhartersworld.com/cri/2001/slidingmin.html */ -ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) +static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in) { const ALsizei mask = BUFFERSIZE - 1; const ALsizei length = Hold->Length; -- cgit v1.2.3 From c39eeb963895a2eb05e17bc28c357f7d3f4ce815 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Oct 2018 12:40:26 -0700 Subject: Don't try to get the JNIEnv on Android It's currently not used. More stuff is needed anyway which may need a different approach. --- Alc/ALc.c | 69 --------------------------------------------------- Alc/backends/opensl.c | 12 +++++---- Alc/compat.h | 8 ------ 3 files changed, 7 insertions(+), 82 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index de6a2b75..47351b99 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1165,75 +1165,6 @@ static void alc_initconfig(void) } #define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) -#ifdef __ANDROID__ -#include - -static JavaVM *gJavaVM; -static pthread_key_t gJVMThreadKey; - -static void CleanupJNIEnv(void* UNUSED(ptr)) -{ - JCALL0(gJavaVM,DetachCurrentThread)(); -} - -void *Android_GetJNIEnv(void) -{ - if(!gJavaVM) - { - WARN("gJavaVM is NULL!\n"); - return NULL; - } - - /* http://developer.android.com/guide/practices/jni.html - * - * All threads are Linux threads, scheduled by the kernel. They're usually - * started from managed code (using Thread.start), but they can also be - * created elsewhere and then attached to the JavaVM. For example, a thread - * started with pthread_create can be attached with the JNI - * AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a - * thread is attached, it has no JNIEnv, and cannot make JNI calls. - * Attaching a natively-created thread causes a java.lang.Thread object to - * be constructed and added to the "main" ThreadGroup, making it visible to - * the debugger. Calling AttachCurrentThread on an already-attached thread - * is a no-op. - */ - JNIEnv *env = pthread_getspecific(gJVMThreadKey); - if(!env) - { - int status = JCALL(gJavaVM,AttachCurrentThread)(&env, NULL); - if(status < 0) - { - ERR("Failed to attach current thread\n"); - return NULL; - } - pthread_setspecific(gJVMThreadKey, env); - } - return env; -} - -/* Automatically called by JNI. */ -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void* UNUSED(reserved)) -{ - void *env; - int err; - - gJavaVM = jvm; - if(JCALL(gJavaVM,GetEnv)(&env, JNI_VERSION_1_4) != JNI_OK) - { - ERR("Failed to get JNIEnv with JNI_VERSION_1_4\n"); - return JNI_ERR; - } - - /* Create gJVMThreadKey so we can keep track of the JNIEnv assigned to each - * thread. The JNIEnv *must* be detached before the thread is destroyed. - */ - if((err=pthread_key_create(&gJVMThreadKey, CleanupJNIEnv)) != 0) - ERR("pthread_key_create failed: %d\n", err); - pthread_setspecific(gJVMThreadKey, env); - return JNI_VERSION_1_4; -} -#endif - /************************************************ * Library deinitialization diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c index aa2a1a6e..d8ae001b 100644 --- a/Alc/backends/opensl.c +++ b/Alc/backends/opensl.c @@ -391,7 +391,6 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) SLInterfaceID ids[2]; SLboolean reqs[2]; SLresult result; - JNIEnv *env; if(self->mBufferQueueObj != NULL) VCALL0(self->mBufferQueueObj,Destroy)(); @@ -401,12 +400,15 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) self->mRing = NULL; sampleRate = device->Frequency; - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL) +#if 0 + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) { /* FIXME: Disabled until I figure out how to get the Context needed for * the getSystemService call. */ -#if 0 + JNIEnv *env = Android_GetJNIEnv(); + jobject jctx = Android_GetContext(); + /* Get necessary stuff for using java.lang.Integer, * android.content.Context, and android.media.AudioManager. */ @@ -442,7 +444,7 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) /* Now make the calls. */ //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE); strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc); - jobject audMgr = JCALL(env,CallObjectMethod)(ctx_cls, ctx_getSysSvc, strobj); + jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj); strchars = JCALL(env,GetStringUTFChars)(strobj, NULL); TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr); JCALL(env,ReleaseStringUTFChars)(strobj, strchars); @@ -463,8 +465,8 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self) if(!sampleRate) sampleRate = device->Frequency; else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE); -#endif } +#endif if(sampleRate != device->Frequency) { diff --git a/Alc/compat.h b/Alc/compat.h index 093184c8..495bfdf2 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -50,14 +50,6 @@ void CloseLib(void *handle); void *GetSymbol(void *handle, const char *name); #endif -#ifdef __ANDROID__ -#define JCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS -#define JCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS - -/** Returns a JNIEnv*. */ -void *Android_GetJNIEnv(void); -#endif - #ifdef __cplusplus } /* extern "C" */ #endif -- cgit v1.2.3 From f3f94e478b0b186bd0de07e734b1d5e1222e0dee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Oct 2018 13:48:04 -0700 Subject: Don't limit output for ALC_DONT_CARE_SOFT and float samples --- Alc/ALc.c | 32 +++++++++++++++++++++++++------- OpenAL32/Include/alMain.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 47351b99..49e9a43f 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -1666,7 +1666,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { enum HrtfRequestMode hrtf_userreq = Hrtf_Default; enum HrtfRequestMode hrtf_appreq = Hrtf_Default; - ALCenum gainLimiter = device->Limiter ? ALC_TRUE : ALC_FALSE; + ALCenum gainLimiter = device->LimiterState; const ALsizei old_sends = device->NumAuxSends; ALsizei new_sends = device->NumAuxSends; enum DevFmtChannels oldChans; @@ -2156,12 +2156,32 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f, device->DitherDepth); + device->LimiterState = gainLimiter; if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val)) gainLimiter = val ? ALC_TRUE : ALC_FALSE; + /* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and - * ALC_FALSE. We default to on, so ALC_DONT_CARE_SOFT is the same as - * ALC_TRUE. + * ALC_FALSE. For ALC_DONT_CARE_SOFT, use the limiter for integer-based + * output (where samples must be clamped), and don't for floating-point + * (which can take unclamped samples). */ + if(gainLimiter == ALC_DONT_CARE_SOFT) + { + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUByte: + case DevFmtShort: + case DevFmtUShort: + case DevFmtInt: + case DevFmtUInt: + gainLimiter = ALC_TRUE; + break; + case DevFmtFloat: + gainLimiter = ALC_FALSE; + break; + } + } if(gainLimiter != ALC_FALSE) { ALfloat thrshld = 1.0f; @@ -2353,6 +2373,7 @@ static void InitDevice(ALCdevice *device, enum DeviceType type) device->Flags = 0; device->Render_Mode = NormalRender; device->AvgSpeakerDist = 0.0f; + device->LimiterState = ALC_DONT_CARE_SOFT; ATOMIC_INIT(&device->ContextList, NULL); @@ -4027,6 +4048,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->IsHeadphones = AL_FALSE; device->AmbiLayout = AmbiLayout_Default; device->AmbiScale = AmbiNorm_Default; + device->LimiterState = ALC_TRUE; device->NumUpdates = 3; device->UpdateSize = 1024; @@ -4165,8 +4187,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) ERR("Unsupported ambi-format: %s\n", fmt); } - device->Limiter = CreateDeviceLimiter(device, 0.0f); - { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { @@ -4494,8 +4514,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN // Open the "backend" V(device->Backend,open)("Loopback"); - device->Limiter = CreateDeviceLimiter(device, 0.0f); - { ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList); do { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index dce51301..0fd77491 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -622,6 +622,8 @@ struct ALCdevice_struct { enum AmbiLayout AmbiLayout; enum AmbiNorm AmbiScale; + ALCenum LimiterState; + al_string DeviceName; ATOMIC(ALCenum) LastError; -- cgit v1.2.3 From db65113c5fceb1996b71b405cce8fbea6f802e60 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Oct 2018 13:51:21 -0700 Subject: Use a 24-bit dither depth limit --- Alc/ALc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 49e9a43f..6e10897b 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2146,7 +2146,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(depth > 0) { - depth = clampi(depth, 2, 20); + depth = clampi(depth, 2, 24); device->DitherDepth = powf(2.0f, (ALfloat)(depth-1)); } } -- cgit v1.2.3 From 7a79f09a31dc8858769f5c43231e488cb972d340 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Oct 2018 17:18:50 -0700 Subject: Add a comment about waiting to kill the event thread --- Alc/ALc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Alc/ALc.c b/Alc/ALc.c index 6e10897b..8bf2e1da 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -2809,6 +2809,11 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device) ret = !!newhead; V0(device->Backend,unlock)(); + /* Make sure the context is finished and no longer processing in the mixer + * before sending the message queue kill event. The backend's lock does + * this, although waiting for a non-odd mix count would work too. + */ + while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0) althrd_yield(); alsem_post(&context->EventSem); -- cgit v1.2.3 From f589244fb6bb5b05a7aa21cc37738148cfc659ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Oct 2018 15:03:49 -0700 Subject: Allow building alffplay without experimental extensions --- examples/alffplay.cpp | 54 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 5ee1da63..4b04efc1 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -40,6 +40,13 @@ extern "C" { #include "AL/alext.h" extern "C" { +/* Undefine this to disable use of experimental extensions. Don't use for + * production code! Interfaces and behavior may change prior to being + * finalized. + */ +#define ALLOW_EXPERIMENTAL_EXTS + +#ifdef ALLOW_EXPERIMENTAL_EXTS #ifndef AL_SOFT_map_buffer #define AL_SOFT_map_buffer 1 typedef unsigned int ALbitfieldSOFT; @@ -71,6 +78,7 @@ typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname); typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values); #endif +#endif /* ALLOW_EXPERIMENTAL_EXTS */ } namespace { @@ -92,12 +100,16 @@ bool EnableWideStereo = false; LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT; LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT; +#ifdef AL_SOFT_map_buffer LPALBUFFERSTORAGESOFT alBufferStorageSOFT; LPALMAPBUFFERSOFT alMapBufferSOFT; LPALUNMAPBUFFERSOFT alUnmapBufferSOFT; +#endif +#ifdef AL_SOFT_events LPALEVENTCONTROLSOFT alEventControlSOFT; LPALEVENTCALLBACKSOFT alEventCallbackSOFT; +#endif const seconds AVNoSyncThreshold(10); @@ -263,9 +275,11 @@ struct AudioState { av_freep(&mSamples); } +#ifdef AL_SOFT_events static void AL_APIENTRY EventCallback(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam); +#endif nanoseconds getClockNoLock(); nanoseconds getClock() @@ -688,6 +702,7 @@ bool AudioState::readAudio(uint8_t *samples, int length) } +#ifdef AL_SOFT_events void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALuint param, ALsizei length, const ALchar *message, void *userParam) @@ -731,24 +746,27 @@ void AL_APIENTRY AudioState::EventCallback(ALenum eventType, ALuint object, ALui self->mSrcCond.notify_one(); } } +#endif int AudioState::handler() { - const std::array types{{ - AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, - AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT, - AL_EVENT_TYPE_DISCONNECTED_SOFT - }}; std::unique_lock lock(mSrcMutex); milliseconds sleep_time = AudioBufferTime / 3; ALenum fmt; +#ifdef AL_SOFT_events + const std::array evt_types{{ + AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, + AL_EVENT_TYPE_ERROR_SOFT, AL_EVENT_TYPE_PERFORMANCE_SOFT, AL_EVENT_TYPE_DEPRECATED_SOFT, + AL_EVENT_TYPE_DISCONNECTED_SOFT + }}; if(alEventControlSOFT) { - alEventControlSOFT(types.size(), types.data(), AL_TRUE); + alEventControlSOFT(evt_types.size(), evt_types.data(), AL_TRUE); alEventCallbackSOFT(EventCallback, this); sleep_time = AudioBufferTotalTime; } +#endif /* Find a suitable format for OpenAL. */ mDstChanLayout = 0; @@ -899,9 +917,8 @@ int AudioState::handler() if(alGetError() != AL_NO_ERROR) goto finish; - if(!alBufferStorageSOFT) - samples = av_malloc(buffer_len); - else +#ifdef AL_SOFT_map_buffer + if(alBufferStorageSOFT) { for(ALuint bufid : mBuffers) alBufferStorageSOFT(bufid, mFormat, nullptr, buffer_len, mCodecCtx->sample_rate, @@ -912,6 +929,9 @@ int AudioState::handler() samples = av_malloc(buffer_len); } } + else +#endif + samples = av_malloc(buffer_len); while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) @@ -934,15 +954,19 @@ int AudioState::handler() { ALuint bufid = mBuffers[mBufferIdx]; - uint8_t *ptr = reinterpret_cast( - samples ? samples : alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT) + uint8_t *ptr = reinterpret_cast(samples +#ifdef AL_SOFT_map_buffer + ? samples : alMapBufferSOFT(bufid, 0, buffer_len, AL_MAP_WRITE_BIT_SOFT) +#endif ); if(!ptr) break; /* Read the next chunk of data, filling the buffer, and queue it on * the source */ bool got_audio = readAudio(ptr, buffer_len); +#ifdef AL_SOFT_map_buffer if(!samples) alUnmapBufferSOFT(bufid); +#endif if(!got_audio) break; if(samples) @@ -983,11 +1007,13 @@ int AudioState::handler() finish: av_freep(&samples); +#ifdef AL_SOFT_events if(alEventControlSOFT) { - alEventControlSOFT(types.size(), types.data(), AL_FALSE); + alEventControlSOFT(evt_types.size(), evt_types.data(), AL_FALSE); alEventCallbackSOFT(nullptr, nullptr); } +#endif return 0; } @@ -1735,6 +1761,7 @@ int main(int argc, char *argv[]) alGetProcAddress("alGetSourcei64vSOFT") ); } +#ifdef AL_SOFT_map_buffer if(alIsExtensionPresent("AL_SOFTX_map_buffer")) { std::cout<< "Found AL_SOFT_map_buffer" <( alGetProcAddress("alUnmapBufferSOFT")); } +#endif +#ifdef AL_SOFT_events if(alIsExtensionPresent("AL_SOFTX_events")) { std::cout<< "Found AL_SOFT_events" <( alGetProcAddress("alEventCallbackSOFT")); } +#endif for(;fileidx < argc;++fileidx) { -- cgit v1.2.3 From 31b9c50721b9ab7e6faaf2f3ac866b3c46750427 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Oct 2018 16:16:00 -0700 Subject: Use the common init/close functions for alffplay --- CMakeLists.txt | 3 ++- examples/alffplay.cpp | 47 ++++++++++++++--------------------------------- 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6d0037e..79df5c5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1746,7 +1746,8 @@ IF(ALSOFT_EXAMPLES) PRIVATE ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) TARGET_COMPILE_OPTIONS(alffplay PRIVATE ${C_FLAGS}) TARGET_LINK_LIBRARIES(alffplay - PRIVATE ${LINKER_FLAGS} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} common OpenAL) + PRIVATE ${LINKER_FLAGS} ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} ex-common common + OpenAL) IF(ALSOFT_INSTALL) INSTALL(TARGETS alffplay diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 4b04efc1..27520a6d 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -39,6 +39,8 @@ extern "C" { #include "AL/al.h" #include "AL/alext.h" +#include "common/alhelpers.h" + extern "C" { /* Undefine this to disable use of experimental extensions. Don't use for * production code! Interfaces and behavior may change prior to being @@ -1717,41 +1719,21 @@ int main(int argc, char *argv[]) SDL_RenderPresent(renderer); /* Open an audio device */ - int fileidx = 1; - ALCdevice *device = [argc,argv,&fileidx]() -> ALCdevice* - { - ALCdevice *dev = NULL; - if(argc > 3 && strcmp(argv[1], "-device") == 0) - { - fileidx = 3; - dev = alcOpenDevice(argv[2]); - if(dev) return dev; - std::cerr<< "Failed to open \""<( - alcGetProcAddress(device, "alcGetInteger64vSOFT") - ); + { auto device = alcGetContextsDevice(alcGetCurrentContext()); + if(alcIsExtensionPresent(device, "ALC_SOFT_device_clock")) + { + std::cout<< "Found ALC_SOFT_device_clock" <( + alcGetProcAddress(device, "alcGetInteger64vSOFT") + ); + } } if(alIsExtensionPresent("AL_SOFT_source_latency")) @@ -1784,6 +1766,7 @@ int main(int argc, char *argv[]) } #endif + int fileidx = 0; for(;fileidx < argc;++fileidx) { if(strcmp(argv[fileidx], "-direct") == 0) @@ -1912,9 +1895,7 @@ int main(int argc, char *argv[]) /* Nothing more to play. Shut everything down and quit. */ movState = nullptr; - alcMakeContextCurrent(nullptr); - alcDestroyContext(context); - alcCloseDevice(device); + CloseAL(); SDL_DestroyRenderer(renderer); renderer = nullptr; -- cgit v1.2.3 From 6761218e51699f46bf25c377e65b3e9ea5e434b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Oct 2018 15:05:31 -0700 Subject: Release 1.19.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79df5c5f..39b80250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,7 @@ ENDIF() SET(LIB_MAJOR_VERSION "1") SET(LIB_MINOR_VERSION "19") -SET(LIB_REVISION "0") +SET(LIB_REVISION "1") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") SET(EXPORT_DECL "") -- cgit v1.2.3 From 4fd0cd3151fd2bab0e8035596b40ce15cd1c386b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 15 Oct 2018 16:40:57 +0000 Subject: Use GCD semaphore on macOS Unnamed POSIX semaphore doesn't work on macOS --- common/threads.c | 35 +++++++++++++++++++++++++++++++++++ common/threads.h | 8 ++++++++ 2 files changed, 43 insertions(+) diff --git a/common/threads.c b/common/threads.c index 6cfe383b..e8301297 100644 --- a/common/threads.c +++ b/common/threads.c @@ -631,6 +631,39 @@ void alcnd_destroy(alcnd_t *cond) } +#ifdef __APPLE__ + +int alsem_init(alsem_t *sem, unsigned int initial) +{ + *sem = dispatch_semaphore_create(initial); + return *sem ? althrd_success : althrd_error; +} + +void alsem_destroy(alsem_t *sem) +{ + dispatch_release(*sem); +} + +int alsem_post(alsem_t *sem) +{ + dispatch_semaphore_signal(*sem); + return althrd_success; +} + +int alsem_wait(alsem_t *sem) +{ + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); + return althrd_success; +} + +int alsem_trywait(alsem_t *sem) +{ + long value = dispatch_semaphore_wait(*sem, DISPATCH_TIME_NOW); + return value == 0 ? althrd_success : althrd_busy; +} + +#else /* !__APPLE__ */ + int alsem_init(alsem_t *sem, unsigned int initial) { if(sem_init(sem, 0, initial) == 0) @@ -665,6 +698,8 @@ int alsem_trywait(alsem_t *sem) return althrd_error; } +#endif /* __APPLE__ */ + int altss_create(altss_t *tss_id, altss_dtor_t callback) { diff --git a/common/threads.h b/common/threads.h index b0bebd8d..2d1b4e7f 100644 --- a/common/threads.h +++ b/common/threads.h @@ -130,13 +130,21 @@ inline int altss_set(altss_t tss_id, void *val) #include #include #include +#ifdef __APPLE__ +#include +#else /* !__APPLE__ */ #include +#endif /* __APPLE__ */ typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; typedef pthread_cond_t alcnd_t; +#ifdef __APPLE__ +typedef dispatch_semaphore_t alsem_t; +#else /* !__APPLE__ */ typedef sem_t alsem_t; +#endif /* __APPLE__ */ typedef pthread_key_t altss_t; typedef pthread_once_t alonce_flag; -- cgit v1.2.3 From 9a4a3d3977d9360a49f87918d5a7c00aa01971bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:22:12 -0700 Subject: Specify the correct array size for casting --- Alc/mastering.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index 52ff5b23..b0b94eea 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -466,11 +466,11 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, Comp->Hold->Values[0] = -INFINITY; Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; - Comp->Delay = (ALfloat(*)[])(Comp->Hold + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); } else { - Comp->Delay = (ALfloat(*)[])(Comp + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); } } -- cgit v1.2.3 From 25dfe4b57a0042008748bb3521a8f5efe297c5db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:25:19 -0700 Subject: Use HUGE_VALF instead of INFINITY Older MSVC lacks INFINITY, and we define a HUGE_VALF fallback when needed. --- Alc/mastering.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Alc/mastering.c b/Alc/mastering.c index b0b94eea..f6ed9242 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -6,6 +6,7 @@ #include "alu.h" #include "almalloc.h" #include "static_assert.h" +#include "math_defs.h" /* These structures assume BUFFERSIZE is a power of 2. */ @@ -463,7 +464,7 @@ Compressor* CompressorInit(const ALsizei NumChans, const ALuint SampleRate, if(hold > 0) { Comp->Hold = (SlidingHold*)(Comp + 1); - Comp->Hold->Values[0] = -INFINITY; + Comp->Hold->Values[0] = -HUGE_VALF; Comp->Hold->Expiries[0] = hold; Comp->Hold->Length = hold; Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); -- cgit v1.2.3 From 515bc4ba53c81d375e9a96dc62398c62d36d56c0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 2 Nov 2018 09:39:57 -0700 Subject: Workaround lack of roundf with early MSVC --- Alc/mastering.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Alc/mastering.c b/Alc/mastering.c index f6ed9242..6745c1c7 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -9,6 +9,18 @@ #include "math_defs.h" +/* Early MSVC lacks round/roundf */ +#if defined(_MSC_VER) && _MSC_VER < 1800 +static double round(double val) +{ + if(val < 0.0) + return ceil(val-0.5); + return floor(val+0.5); +} +#define roundf(f) ((float)round((float)(f))) +#endif + + /* These structures assume BUFFERSIZE is a power of 2. */ static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2"); -- cgit v1.2.3 From 14cf721094228b4f02af9dbfce7a93edd3bdf706 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 8 Nov 2018 14:18:34 +0400 Subject: Fix Resample_bsinc_SSE pointer casts. Regression was introduced in 5ec11a017c. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39b80250..6fea142a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,7 +402,7 @@ int main() IF(HAVE___BUILTIN_ASSUME_ALIGNED) SET(ASSUME_ALIGNED_DECL "__builtin_assume_aligned(x, y)") ELSE() - SET(ASSUME_ALIGNED_DECL "x") + SET(ASSUME_ALIGNED_DECL "(x)") ENDIF() SET(SSE_SWITCH "") -- cgit v1.2.3 From 99a55c445211fea77af6ab61cbc6a6ec4fbdc9b9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2019 00:22:19 -0800 Subject: Handle a missing default WASAPI device ID Backported fix from d1a86075 on master. --- Alc/backends/wasapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Alc/backends/wasapi.c b/Alc/backends/wasapi.c index 971a1f72..b974321b 100644 --- a/Alc/backends/wasapi.c +++ b/Alc/backends/wasapi.c @@ -328,7 +328,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve devid = get_device_id(device); if(devid) { - if(wcscmp(devid, defdevid) != 0) + if(!defdevid || wcscmp(devid, defdevid) != 0) add_device(device, devid, list); CoTaskMemFree(devid); } -- cgit v1.2.3