Compare commits

..

11 Commits

Author SHA1 Message Date
Chris Robinson ce6076091b Release 1.18.2 2017-09-24 06:41:50 -07:00
Chris Robinson dba8166b67 Update ChangeLog with JACK fix 2017-09-23 15:12:50 -07:00
Chris Robinson 4fa9c8e4b4 Restore the original JACK message callback when possible 2017-09-23 15:12:38 -07:00
Chris Robinson 912c0cc9eb Update ChangeLog 2017-09-22 07:18:31 -07:00
Daniel Scharrer 9a67aa8530 Fix build on Gentoo FreeBSD with freebsd-lib 9.1 2017-09-22 07:18:14 -07:00
Chris Robinson 45e757ea12 Update ChangeLog 2017-09-19 10:16:53 -07:00
Chris Robinson 026f96c2a3 Manually save and restore the FPU rounding mode on Windows
Apparently there is a bug with at least MinGW-W64 where fegetenv and fesetenv
do not properly save and restore the FPU rounding mode, resulting in the
rounding mode remaining as round-to-zero after certain function calls. I do not
know if this also affects MSVC, but better safe than sorry for now.
2017-09-19 10:05:41 -07:00
Chris Robinson 631624fa58 Always link to ossaudio when found 2017-09-19 10:05:41 -07:00
Chris Robinson 51e11fdb9c Handle libossaudio as an optional OSS library 2017-09-19 10:05:41 -07:00
Chris Robinson eaf3b94143 Add a check for pthread_setname_np with three parameters
As found in NetBSD.
2017-09-19 10:05:41 -07:00
Chris Robinson 84eca96dad Don't hide -msse and -mfpu=neon checks behind a not-msvc check
Apparently Clang gets reported as being MSVC on Windows, but still needs the
GCC switches to enable SSE code generation.
2017-09-19 10:05:41 -07:00
150 changed files with 20574 additions and 21897 deletions
+6 -4
View File
@@ -1,5 +1,7 @@
build*/
winbuild/
win64build/
build
winbuild
win64build
include/SLES
include/sndio.h
include/sys
openal-soft.kdev4
.kdev4/
+16 -12
View File
@@ -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
@@ -24,17 +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-r15-linux-x86_64.zip
unzip -q ~/android-ndk.zip -d ~ \
'android-ndk-r15/build/cmake/*' \
'android-ndk-r15/build/core/toolchains/arm-linux-androideabi-*/*' \
'android-ndk-r15/platforms/android-14/arch-arm/*' \
'android-ndk-r15/source.properties' \
'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \
'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/include/*' \
'android-ndk-r15/sysroot/*' \
'android-ndk-r15/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \
'android-ndk-r15/toolchains/llvm/prebuilt/linux-x86_64/*'
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:
- >
@@ -51,7 +55,7 @@ script:
- >
if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then
cmake \
-DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r15/build/cmake/android.toolchain.cmake \
-DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r14/build/cmake/android.toolchain.cmake \
-DALSOFT_REQUIRE_OPENSL=ON \
-DALSOFT_EMBED_HRTF_DATA=YES \
.
+577 -631
View File
File diff suppressed because it is too large Load Diff
+508 -601
View File
File diff suppressed because it is too large Load Diff
+36 -82
View File
@@ -36,12 +36,8 @@
#include <windows.h>
#include <shlobj.h>
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "alMain.h"
#include "alconfig.h"
#include "compat.h"
#include "bool.h"
@@ -369,9 +365,9 @@ static void LoadConfigFromFile(FILE *f)
#ifdef _WIN32
void ReadALConfig(void)
{
al_string ppath = AL_STRING_INIT_STATIC();
WCHAR buffer[MAX_PATH];
WCHAR buffer[PATH_MAX];
const WCHAR *str;
al_string ppath;
FILE *f;
if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
@@ -390,7 +386,7 @@ void ReadALConfig(void)
alstr_reset(&filepath);
}
GetProcBinary(&ppath, NULL);
ppath = GetProcPath();
if(!alstr_empty(ppath))
{
alstr_append_cstr(&ppath, "\\alsoft.ini");
@@ -423,9 +419,9 @@ void ReadALConfig(void)
#else
void ReadALConfig(void)
{
al_string confpaths = AL_STRING_INIT_STATIC();
al_string fname = AL_STRING_INIT_STATIC();
char buffer[PATH_MAX];
const char *str;
al_string ppath;
FILE *f;
str = "/etc/openal/alsoft.conf";
@@ -440,75 +436,45 @@ void ReadALConfig(void)
if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0)
str = "/etc/xdg";
alstr_copy_cstr(&confpaths, str);
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(!alstr_empty(confpaths))
while(1)
{
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;
}
char *next = strrchr(buffer, ':');
if(next) *(next++) = 0;
else next = buffer;
if(next[0] != '/')
WARN("Ignoring XDG config dir: %s\n", next);
else
{
alstr_reset(&fname);
fname = confpaths;
AL_STRING_INIT(confpaths);
}
size_t len = strlen(next);
strncpy(next+len, "/alsoft.conf", buffer+sizeof(buffer)-next-len);
buffer[sizeof(buffer)-1] = 0;
if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/')
WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname));
else
{
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");
TRACE("Loading config %s...\n", next);
f = al_fopen(next, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
alstr_clear(&fname);
if(next == buffer)
break;
}
#ifdef __APPLE__
CFBundleRef mainBundle = CFBundleGetMainBundle();
if(mainBundle)
{
unsigned char fileName[PATH_MAX];
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);
if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc");
else alstr_append_cstr(&fname, ".alsoftrc");
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
TRACE("Loading config %s...\n", alstr_get_cstr(fname));
f = al_fopen(alstr_get_cstr(fname), "r");
TRACE("Loading config %s...\n", buffer);
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -517,25 +483,17 @@ void ReadALConfig(void)
}
if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0)
{
alstr_copy_cstr(&fname, str);
if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf");
else alstr_append_cstr(&fname, "alsoft.conf");
}
snprintf(buffer, sizeof(buffer), "%s/%s", str, "alsoft.conf");
else
{
alstr_clear(&fname);
buffer[0] = 0;
if((str=getenv("HOME")) != NULL && str[0] != 0)
{
alstr_copy_cstr(&fname, str);
if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf");
else alstr_append_cstr(&fname, ".config/alsoft.conf");
}
snprintf(buffer, sizeof(buffer), "%s/.config/%s", str, "alsoft.conf");
}
if(!alstr_empty(fname))
if(buffer[0] != 0)
{
TRACE("Loading config %s...\n", alstr_get_cstr(fname));
f = al_fopen(alstr_get_cstr(fname), "r");
TRACE("Loading config %s...\n", buffer);
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -543,15 +501,12 @@ void ReadALConfig(void)
}
}
alstr_clear(&fname);
GetProcBinary(&fname, NULL);
if(!alstr_empty(fname))
ppath = GetProcPath();
if(!alstr_empty(ppath))
{
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");
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);
@@ -570,8 +525,7 @@ void ReadALConfig(void)
}
}
alstr_reset(&fname);
alstr_reset(&confpaths);
alstr_reset(&ppath);
}
#endif
+66 -44
View File
@@ -22,11 +22,8 @@
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include "ringbuffer.h"
#include "align.h"
#include "atomic.h"
#include "alMain.h"
#include "threads.h"
#include "almalloc.h"
#include "compat.h"
@@ -42,70 +39,85 @@ struct ll_ringbuffer {
size_t size;
size_t size_mask;
size_t elem_size;
int mlocked;
alignas(16) char buf[];
};
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes)
/* 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 = 0;
ALuint power_of_two;
if(sz > 0)
{
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;
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;
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 = limit_writes ? sz : power_of_two;
rb->size_mask = power_of_two - 1;
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)
{
al_free(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_mask+1)*rb->elem_size);
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);
w = (r-w-1) & rb->size_mask;
return (w > rb->size) ? rb->size : w;
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;
@@ -121,9 +133,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_mask+1)
if(cnt2 > rb->size)
{
n1 = rb->size_mask+1 - read_ptr;
n1 = rb->size - read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
@@ -144,6 +156,9 @@ 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;
@@ -159,9 +174,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_mask+1)
if(cnt2 > rb->size)
{
n1 = rb->size_mask+1 - read_ptr;
n1 = rb->size - read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
@@ -180,6 +195,8 @@ 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;
@@ -195,9 +212,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_mask+1)
if(cnt2 > rb->size)
{
n1 = rb->size_mask+1 - write_ptr;
n1 = rb->size - write_ptr;
n2 = cnt2 & rb->size_mask;
}
else
@@ -218,19 +235,22 @@ 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);
}
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2])
/* 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;
@@ -243,12 +263,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_mask+1)
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_mask+1 - r;
vec[0].len = rb->size - r;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
@@ -262,7 +282,10 @@ void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data
}
}
void ll_ringbuffer_get_write_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)
{
size_t free_cnt;
size_t cnt2;
@@ -273,15 +296,14 @@ 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_mask+1)
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_mask+1 - w;
vec[0].len = rb->size - w;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
-17
View File
@@ -1,17 +0,0 @@
#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 */
-9
View File
@@ -6,10 +6,6 @@
#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,12 +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
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ALSTRING_H */
+45 -72
View File
@@ -26,8 +26,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
@@ -438,7 +436,7 @@ typedef struct ALCplaybackAlsa {
ALvoid *buffer;
ALsizei size;
ATOMIC(ALenum) killNow;
volatile int killNow;
althrd_t thread;
} ALCplaybackAlsa;
@@ -446,8 +444,9 @@ static int ALCplaybackAlsa_mixerProc(void *ptr);
static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
static void ALCplaybackAlsa_close(ALCplaybackAlsa *self);
static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
@@ -465,19 +464,6 @@ 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;
ATOMIC_INIT(&self->killNow, AL_TRUE);
}
void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self)
{
if(self->pcmHandle)
snd_pcm_close(self->pcmHandle);
self->pcmHandle = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -497,14 +483,14 @@ static int ALCplaybackAlsa_mixerProc(void *ptr)
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
while(!self->killNow)
{
int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
ALCplaybackAlsa_lock(self);
aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
aluHandleDisconnect(device);
ALCplaybackAlsa_unlock(self);
break;
}
@@ -587,14 +573,14 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
while(!self->killNow)
{
int state = verify_state(self->pcmHandle);
if(state < 0)
{
ERR("Invalid state detected: %s\n", snd_strerror(state));
ALCplaybackAlsa_lock(self);
aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
aluHandleDisconnect(device);
ALCplaybackAlsa_unlock(self);
break;
}
@@ -714,6 +700,11 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
return ALC_NO_ERROR;
}
static void ALCplaybackAlsa_close(ALCplaybackAlsa *self)
{
snd_pcm_close(self->pcmHandle);
}
static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -912,7 +903,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
}
thread_func = ALCplaybackAlsa_mixerProc;
}
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = 0;
if(althrd_create(&self->thread, thread_func, self) != althrd_success)
{
ERR("Could not create playback thread\n");
@@ -933,8 +924,10 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
{
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
al_free(self->buffer);
@@ -978,8 +971,9 @@ typedef struct ALCcaptureAlsa {
} ALCcaptureAlsa;
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
static void ALCcaptureAlsa_close(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
@@ -997,25 +991,6 @@ 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)
{
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));
}
@@ -1123,9 +1098,8 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
if(needring)
{
self->ring = ll_ringbuffer_create(
device->UpdateSize*device->NumUpdates,
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
false
device->UpdateSize*device->NumUpdates + 1,
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->ring)
{
@@ -1146,26 +1120,26 @@ error2:
ll_ringbuffer_free(self->ring);
self->ring = NULL;
snd_pcm_close(self->pcmHandle);
self->pcmHandle = NULL;
return ALC_INVALID_VALUE;
}
static void ALCcaptureAlsa_close(ALCcaptureAlsa *self)
{
snd_pcm_close(self->pcmHandle);
ll_ringbuffer_free(self->ring);
al_free(self->buffer);
self->buffer = NULL;
}
static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
{
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));
}
int err = snd_pcm_start(self->pcmHandle);
if(err < 0)
{
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s",
snd_strerror(err));
ERR("start failed: %s\n", snd_strerror(err));
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
return ALC_FALSE;
}
@@ -1216,7 +1190,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
}
self->last_avail -= samples;
while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0)
while(device->Connected && samples > 0)
{
snd_pcm_sframes_t amt = 0;
@@ -1259,7 +1233,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
aluHandleDisconnect(device);
break;
}
/* If the amount available is less than what's asked, we lost it
@@ -1284,7 +1258,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
snd_pcm_sframes_t avail = 0;
if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture)
if(device->Connected && self->doCapture)
avail = snd_pcm_avail_update(self->pcmHandle);
if(avail < 0)
{
@@ -1300,7 +1274,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
if(avail < 0)
{
ERR("restore error: %s\n", snd_strerror(avail));
aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail));
aluHandleDisconnect(device);
}
}
@@ -1339,7 +1313,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
if(amt < 0)
{
ERR("restore error: %s\n", snd_strerror(amt));
aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
aluHandleDisconnect(device);
break;
}
avail = amt;
@@ -1375,6 +1349,11 @@ 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;
@@ -1412,25 +1391,19 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS
return ALC_FALSE;
}
static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
{
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, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
#undef APPEND_OUTNAME
}
}
-3
View File
@@ -10,9 +10,6 @@
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)
+7 -30
View File
@@ -3,13 +3,8 @@
#include "alMain.h"
#include "threads.h"
#include "alstring.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ClockLatency {
ALint64 ClockTime;
ALint64 Latency;
@@ -48,6 +43,7 @@ struct ALCbackendVtable {
void (*const Destruct)(ALCbackend*);
ALCenum (*const open)(ALCbackend*, const ALCchar*);
void (*const close)(ALCbackend*);
ALCboolean (*const reset)(ALCbackend*);
ALCboolean (*const start)(ALCbackend*);
@@ -67,6 +63,7 @@ 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) \
@@ -82,6 +79,7 @@ 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, \
@@ -116,7 +114,7 @@ struct ALCbackendFactoryVtable {
ALCboolean (*const querySupport)(ALCbackendFactory *self, ALCbackend_Type type);
void (*const probe)(ALCbackendFactory *self, enum DevProbe type, al_string *outnames);
void (*const probe)(ALCbackendFactory *self, enum DevProbe type);
ALCbackend* (*const createBackend)(ALCbackendFactory *self, ALCdevice *device, ALCbackend_Type type);
};
@@ -125,7 +123,7 @@ struct ALCbackendFactoryVtable {
DECLARE_THUNK(T, ALCbackendFactory, ALCboolean, init) \
DECLARE_THUNK(T, ALCbackendFactory, void, deinit) \
DECLARE_THUNK1(T, ALCbackendFactory, ALCboolean, querySupport, ALCbackend_Type) \
DECLARE_THUNK2(T, ALCbackendFactory, void, probe, enum DevProbe, al_string*) \
DECLARE_THUNK1(T, ALCbackendFactory, void, probe, enum DevProbe) \
DECLARE_THUNK2(T, ALCbackendFactory, ALCbackend*, createBackend, ALCdevice*, ALCbackend_Type) \
\
static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
@@ -143,36 +141,15 @@ ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *SndioBackendFactory_getFactory(void);
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
ALCbackendFactory *ALCqsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void);
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 *ALCsdl2BackendFactory_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)(); }
inline ClockLatency GetClockLatency(ALCdevice *device)
{
ClockLatency ret = V0(device->Backend,getClockLatency)();
ret.Latency += device->FixedLatency;
return ret;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AL_BACKENDS_BASE_H */
+92 -80
View File
@@ -23,11 +23,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#include "alMain.h"
#include "alu.h"
#include "ringbuffer.h"
#include <CoreServices/CoreServices.h>
#include <unistd.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
@@ -35,9 +36,56 @@
#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, sizeof(AudioBufferList) + sizeof(AudioBuffer));
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;
}
}
return 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);
}
}
typedef struct ALCcoreAudioPlayback {
DERIVE_FROM_TYPE(ALCbackend);
@@ -50,6 +98,7 @@ 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);
@@ -74,9 +123,6 @@ static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice
static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self)
{
AudioUnitUninitialize(self->audioUnit);
AudioComponentInstanceDispose(self->audioUnit);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -88,10 +134,10 @@ static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon,
ALCcoreAudioPlayback *self = inRefCon;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
ALCcoreAudioPlayback_lock(self);
ALCdevice_Lock(device);
aluMixData(device, ioData->mBuffers[0].mData,
ioData->mBuffers[0].mDataByteSize / self->frameSize);
ALCcoreAudioPlayback_unlock(self);
ALCdevice_Unlock(device);
return noErr;
}
@@ -111,11 +157,7 @@ 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;
@@ -147,6 +189,12 @@ 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;
@@ -334,6 +382,7 @@ 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);
@@ -347,59 +396,15 @@ 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);
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));
}
@@ -454,6 +459,7 @@ 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;
@@ -467,11 +473,7 @@ 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;
@@ -510,9 +512,7 @@ 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;
@@ -525,6 +525,7 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar
ERR("AudioObjectGetPropertyData failed\n");
goto error;
}
if(inputDevice == kAudioDeviceUnknown)
{
ERR("No input device found\n");
@@ -538,7 +539,6 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar
ERR("AudioUnitSetProperty failed\n");
goto error;
}
#endif
// set capture callback
input.inputProc = ALCcoreAudioCapture_RecordProc;
@@ -667,8 +667,8 @@ static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar
goto error;
self->ring = ll_ringbuffer_create(
(size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates),
self->frameSize, false
device->UpdateSize*self->sampleRateRatio*device->NumUpdates + 1,
self->frameSize
);
if(!self->ring) goto error;
@@ -680,21 +680,30 @@ 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);
@@ -715,26 +724,27 @@ static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self)
static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples)
{
union {
ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)];
AudioBufferList list;
} audiobuf = { { 0 } };
AudioBufferList *list;
UInt32 frameCount;
OSStatus err;
// If no samples are requested, just return
if(samples == 0) return ALC_NO_ERROR;
if(samples == 0)
return ALC_NO_ERROR;
// Allocate a temporary AudioBufferList to use as the return resamples data
list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
// Point the resampling buffer to the capture 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;
list->mNumberBuffers = 1;
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(self->audioConverter,
ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL
ALCcoreAudioCapture_ConvertCallback, self, &frameCount, list, NULL
);
if(err != noErr)
{
@@ -760,7 +770,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, al_string *outnames);
static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory);
@@ -784,13 +794,15 @@ static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFac
return ALC_FALSE;
}
static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(ca_device);
break;
case CAPTURE_DEVICE_PROBE:
alstr_append_range(outnames, ca_device, ca_device+sizeof(ca_device));
AppendCaptureDeviceList(ca_device);
break;
}
}
+63 -82
View File
@@ -34,7 +34,6 @@
#include "alMain.h"
#include "alu.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
#include "alstring.h"
@@ -185,15 +184,16 @@ typedef struct ALCdsoundPlayback {
IDirectSoundNotify *Notifies;
HANDLE NotifyEvent;
ATOMIC(ALenum) killNow;
volatile int killNow;
althrd_t thread;
} ALCdsoundPlayback;
static int ALCdsoundPlayback_mixerProc(void *ptr);
static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device);
static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self);
static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, Destruct)
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);
@@ -211,35 +211,6 @@ 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;
ATOMIC_INIT(&self->killNow, AL_TRUE);
}
static void ALCdsoundPlayback_Destruct(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;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -268,7 +239,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
{
ERR("Failed to get buffer caps: 0x%lx\n", err);
ALCdevice_Lock(device);
aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
return 1;
}
@@ -277,8 +248,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
FragSize = device->UpdateSize * FrameSize;
IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow)
{
// Get current play cursor
IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL);
@@ -293,7 +263,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
{
ERR("Failed to play buffer: 0x%lx\n", err);
ALCdevice_Lock(device);
aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
return 1;
}
@@ -341,7 +311,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
{
ERR("Buffer lock error: %#lx\n", err);
ALCdevice_Lock(device);
aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
return 1;
}
@@ -416,6 +386,24 @@ 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;
IDirectSound_Release(self->DS);
self->DS = NULL;
CloseHandle(self->NotifyEvent);
self->NotifyEvent = NULL;
}
static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -638,7 +626,7 @@ retry_open:
static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self)
{
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = 0;
if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
@@ -649,8 +637,10 @@ static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self)
{
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
IDirectSoundBuffer_Stop(self->Buffer);
@@ -670,8 +660,9 @@ typedef struct ALCdsoundCapture {
} ALCdsoundCapture;
static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device);
static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self);
static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, Destruct)
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,29 +679,6 @@ 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)
{
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));
}
@@ -856,8 +824,8 @@ 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,
InputType.Format.nBlockAlign, false);
self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1,
InputType.Format.nBlockAlign);
if(self->Ring == NULL)
hr = DSERR_OUTOFMEMORY;
}
@@ -886,6 +854,22 @@ 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;
}
IDirectSoundCapture_Release(self->DSC);
self->DSC = NULL;
}
static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
{
HRESULT hr;
@@ -894,8 +878,7 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
if(FAILED(hr))
{
ERR("start failed: 0x%08lx\n", hr);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
"Failure starting capture: 0x%lx", hr);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
return ALC_FALSE;
}
@@ -910,8 +893,7 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self)
if(FAILED(hr))
{
ERR("stop failed: 0x%08lx\n", hr);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
"Failure stopping capture: 0x%lx", hr);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
}
}
@@ -930,7 +912,7 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
DWORD FrameSize;
HRESULT hr;
if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
if(!device->Connected)
goto done;
FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
@@ -961,14 +943,19 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
if(FAILED(hr))
{
ERR("update failed: 0x%08lx\n", hr);
aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr);
aluHandleDisconnect(device);
}
done:
return (ALCuint)ll_ringbuffer_read_space(self->Ring);
return ll_ringbuffer_read_space(self->Ring);
}
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;
@@ -979,7 +966,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, al_string *outnames);
static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory);
@@ -1023,7 +1010,7 @@ static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory*
return ALC_FALSE;
}
static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type)
{
HRESULT hr, hrcom;
@@ -1031,17 +1018,12 @@ 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, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
@@ -1049,9 +1031,8 @@ 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, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
#undef APPEND_OUTNAME
}
if(SUCCEEDED(hrcom))
CoUninitialize();
+59 -26
View File
@@ -26,8 +26,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
@@ -150,9 +148,9 @@ typedef struct ALCjackPlayback {
jack_port_t *Port[MAX_OUTPUT_CHANNELS];
ll_ringbuffer_t *Ring;
alsem_t Sem;
alcnd_t Cond;
ATOMIC(ALenum) killNow;
volatile int killNow;
althrd_t thread;
} ALCjackPlayback;
@@ -164,6 +162,7 @@ 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);
@@ -184,14 +183,14 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
alsem_init(&self->Sem, 0);
alcnd_init(&self->Cond);
self->Client = NULL;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
self->Port[i] = NULL;
self->Ring = NULL;
ATOMIC_INIT(&self->killNow, AL_TRUE);
self->killNow = 1;
}
static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
@@ -210,7 +209,7 @@ static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
self->Client = NULL;
}
alsem_destroy(&self->Sem);
alcnd_destroy(&self->Cond);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -229,19 +228,19 @@ 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);
device->NumUpdates = (bufsize+device->UpdateSize) / 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, device->AmbiOrder),
true
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->Ring)
{
ERR("Failed to reallocate ringbuffer\n");
aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize);
aluHandleDisconnect(device);
}
ALCjackPlayback_unlock(self);
return 0;
@@ -287,7 +286,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
}
ll_ringbuffer_read_advance(self->Ring, total);
alsem_post(&self->Sem);
alcnd_signal(&self->Cond);
if(numframes > total)
{
@@ -312,16 +311,27 @@ static int ALCjackPlayback_mixerProc(void *arg)
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
ALCjackPlayback_lock(self);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow && device->Connected)
{
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)
{
ALCjackPlayback_unlock(self);
alsem_wait(&self->Sem);
ALCjackPlayback_lock(self);
alcnd_wait(&self->Cond, &STATIC_CAST(ALCbackend,self)->mMutex);
continue;
}
@@ -376,6 +386,20 @@ 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;
@@ -390,7 +414,9 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
}
/* Ignore the requested buffer metrics and just keep one JACK-sized buffer
* ready for when requested.
* 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.
*/
device->Frequency = jack_get_sample_rate(self->Client);
device->UpdateSize = jack_get_buffer_size(self->Client);
@@ -399,7 +425,8 @@ 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);
device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize;
bufsize += device->UpdateSize;
device->NumUpdates = bufsize / device->UpdateSize;
/* Force 32-bit float output. */
device->FmtType = DevFmtFloat;
@@ -434,8 +461,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
ll_ringbuffer_free(self->Ring);
self->Ring = ll_ringbuffer_create(bufsize,
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
true
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->Ring)
{
@@ -478,7 +504,7 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
}
jack_free(ports);
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = 0;
if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
{
jack_deactivate(self->Client);
@@ -492,10 +518,17 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self)
{
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
alsem_post(&self->Sem);
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);
althrd_join(self->thread, &res);
jack_deactivate(self->Client);
@@ -571,12 +604,12 @@ static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUS
return ALC_FALSE;
}
static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
alstr_append_range(outnames, jackDevice, jackDevice+sizeof(jackDevice));
AppendAllDevicesList(jackDevice);
break;
case CAPTURE_DEVICE_PROBE:
+7 -2
View File
@@ -35,6 +35,7 @@ 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);
@@ -62,6 +63,10 @@ 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);
@@ -87,7 +92,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, al_string *outnames);
static void ALCloopbackFactory_probe(ALCloopbackFactory *self, enum DevProbe type);
static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCloopbackFactory);
@@ -110,7 +115,7 @@ static ALCboolean ALCloopbackFactory_querySupport(ALCloopbackFactory* UNUSED(sel
return ALC_FALSE;
}
static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames))
static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevProbe UNUSED(type))
{
}
+254 -239
View File
@@ -41,7 +41,6 @@
#include "alMain.h"
#include "alu.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
#include "alstring.h"
@@ -71,13 +70,6 @@ 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.
@@ -344,51 +336,51 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
/* Proxy interface used by the message handler. */
struct ALCwasapiProxyVtable;
struct ALCmmdevProxyVtable;
typedef struct ALCwasapiProxy {
const struct ALCwasapiProxyVtable *vtbl;
} ALCwasapiProxy;
typedef struct ALCmmdevProxy {
const struct ALCmmdevProxyVtable *vtbl;
} ALCmmdevProxy;
struct ALCwasapiProxyVtable {
HRESULT (*const openProxy)(ALCwasapiProxy*);
void (*const closeProxy)(ALCwasapiProxy*);
struct ALCmmdevProxyVtable {
HRESULT (*const openProxy)(ALCmmdevProxy*);
void (*const closeProxy)(ALCmmdevProxy*);
HRESULT (*const resetProxy)(ALCwasapiProxy*);
HRESULT (*const startProxy)(ALCwasapiProxy*);
void (*const stopProxy)(ALCwasapiProxy*);
HRESULT (*const resetProxy)(ALCmmdevProxy*);
HRESULT (*const startProxy)(ALCmmdevProxy*);
void (*const stopProxy)(ALCmmdevProxy*);
};
#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) \
#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 ALCwasapiProxyVtable T##_ALCwasapiProxy_vtable = { \
T##_ALCwasapiProxy_openProxy, \
T##_ALCwasapiProxy_closeProxy, \
T##_ALCwasapiProxy_resetProxy, \
T##_ALCwasapiProxy_startProxy, \
T##_ALCwasapiProxy_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 ALCwasapiProxy_Construct(ALCwasapiProxy* UNUSED(self)) { }
static void ALCwasapiProxy_Destruct(ALCwasapiProxy* UNUSED(self)) { }
static void ALCmmdevProxy_Construct(ALCmmdevProxy* UNUSED(self)) { }
static void ALCmmdevProxy_Destruct(ALCmmdevProxy* UNUSED(self)) { }
static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
{
ThreadRequest *req = ptr;
IMMDeviceEnumerator *Enumerator;
ALuint deviceCount = 0;
ALCwasapiProxy *proxy;
ALCmmdevProxy *proxy;
HRESULT hr, cohr;
MSG msg;
TRACE("Starting message thread\n");
cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
cohr = CoInitialize(NULL);
if(FAILED(cohr))
{
WARN("Failed to initialize COM: 0x%08lx\n", cohr);
@@ -431,11 +423,11 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
{
case WM_USER_OpenDevice:
req = (ThreadRequest*)msg.wParam;
proxy = (ALCwasapiProxy*)msg.lParam;
proxy = (ALCmmdevProxy*)msg.lParam;
hr = cohr = S_OK;
if(++deviceCount == 1)
hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = cohr = CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = V0(proxy,openProxy)();
if(FAILED(hr))
@@ -449,7 +441,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
case WM_USER_ResetDevice:
req = (ThreadRequest*)msg.wParam;
proxy = (ALCwasapiProxy*)msg.lParam;
proxy = (ALCmmdevProxy*)msg.lParam;
hr = V0(proxy,resetProxy)();
ReturnMsgResponse(req, hr);
@@ -457,7 +449,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
case WM_USER_StartDevice:
req = (ThreadRequest*)msg.wParam;
proxy = (ALCwasapiProxy*)msg.lParam;
proxy = (ALCmmdevProxy*)msg.lParam;
hr = V0(proxy,startProxy)();
ReturnMsgResponse(req, hr);
@@ -465,7 +457,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
case WM_USER_StopDevice:
req = (ThreadRequest*)msg.wParam;
proxy = (ALCwasapiProxy*)msg.lParam;
proxy = (ALCmmdevProxy*)msg.lParam;
V0(proxy,stopProxy)();
ReturnMsgResponse(req, S_OK);
@@ -473,7 +465,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
case WM_USER_CloseDevice:
req = (ThreadRequest*)msg.wParam;
proxy = (ALCwasapiProxy*)msg.lParam;
proxy = (ALCmmdevProxy*)msg.lParam;
V0(proxy,closeProxy)();
if(--deviceCount == 0)
@@ -487,7 +479,7 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
hr = cohr = S_OK;
if(++deviceCount == 1)
hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = cohr = CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
if(SUCCEEDED(hr))
@@ -520,9 +512,9 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr)
}
typedef struct ALCwasapiPlayback {
typedef struct ALCmmdevPlayback {
DERIVE_FROM_TYPE(ALCbackend);
DERIVE_FROM_TYPE(ALCwasapiProxy);
DERIVE_FROM_TYPE(ALCmmdevProxy);
WCHAR *devid;
@@ -533,42 +525,43 @@ typedef struct ALCwasapiPlayback {
HANDLE MsgEvent;
ATOMIC(UINT32) Padding;
volatile UINT32 Padding;
ATOMIC(int) killNow;
volatile int killNow;
althrd_t thread;
} ALCwasapiPlayback;
} ALCmmdevPlayback;
static int ALCwasapiPlayback_mixerProc(void *arg);
static int ALCmmdevPlayback_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)
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);
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_ALCWASAPIPROXY_VTABLE(ALCwasapiPlayback);
DEFINE_ALCBACKEND_VTABLE(ALCwasapiPlayback);
DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevPlayback);
DEFINE_ALCBACKEND_VTABLE(ALCmmdevPlayback);
static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *device)
static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device)
{
SET_VTABLE2(ALCwasapiPlayback, ALCbackend, self);
SET_VTABLE2(ALCwasapiPlayback, ALCwasapiProxy, self);
SET_VTABLE2(ALCmmdevPlayback, ALCbackend, self);
SET_VTABLE2(ALCmmdevPlayback, ALCmmdevProxy, self);
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self));
ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
self->devid = NULL;
@@ -579,30 +572,13 @@ static void ALCwasapiPlayback_Construct(ALCwasapiPlayback *self, ALCdevice *devi
self->MsgEvent = NULL;
ATOMIC_INIT(&self->Padding, 0);
self->Padding = 0;
ATOMIC_INIT(&self->killNow, 0);
self->killNow = 0;
}
static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self)
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(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;
@@ -613,26 +589,26 @@ static void ALCwasapiPlayback_Destruct(ALCwasapiPlayback *self)
free(self->devid);
self->devid = NULL;
ALCwasapiProxy_Destruct(STATIC_CAST(ALCwasapiProxy, self));
ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg)
FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
{
ALCwasapiPlayback *self = arg;
ALCmmdevPlayback *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
UINT32 buffer_len, written;
ALuint update_size, len;
BYTE *buffer;
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = CoInitialize(NULL);
if(FAILED(hr))
{
ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr);
ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
V0(device->Backend,lock)();
aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr);
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
return 1;
}
@@ -642,18 +618,18 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg)
update_size = device->UpdateSize;
buffer_len = update_size * device->NumUpdates;
while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed))
while(!self->killNow)
{
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);
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
break;
}
ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed);
self->Padding = written;
len = buffer_len - written;
if(len < update_size)
@@ -669,22 +645,22 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg)
hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
if(SUCCEEDED(hr))
{
ALCwasapiPlayback_lock(self);
ALCmmdevPlayback_lock(self);
aluMixData(device, buffer, len);
ATOMIC_STORE(&self->Padding, written + len, almemory_order_relaxed);
ALCwasapiPlayback_unlock(self);
self->Padding = written + len;
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);
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
break;
}
}
ATOMIC_STORE(&self->Padding, 0, almemory_order_release);
self->Padding = 0;
CoUninitialize();
return 0;
@@ -730,7 +706,7 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *
return ALC_TRUE;
}
static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *deviceName)
static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName)
{
HRESULT hr = S_OK;
@@ -790,7 +766,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de
ThreadRequest req = { self->MsgEvent, 0 };
hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self)))
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());
@@ -815,7 +791,7 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de
return ALC_NO_ERROR;
}
static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self)
static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
void *ptr;
@@ -852,7 +828,24 @@ static HRESULT ALCwasapiPlayback_openProxy(ALCwasapiPlayback *self)
}
static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self)
static void ALCmmdevPlayback_close(ALCmmdevPlayback *self)
{
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;
CloseHandle(self->NotifyEvent);
self->NotifyEvent = NULL;
free(self->devid);
self->devid = NULL;
}
static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self)
{
if(self->client)
IAudioClient_Release(self->client);
@@ -864,18 +857,18 @@ static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self)
}
static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self)
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(ALCwasapiProxy, self)))
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 ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self)
static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
EndpointFormFactor formfactor = UnknownFormFactor;
@@ -1135,18 +1128,18 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self)
}
static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self)
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(ALCwasapiProxy, self)))
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 ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self)
static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self)
{
HRESULT hr;
void *ptr;
@@ -1161,8 +1154,8 @@ static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self)
if(SUCCEEDED(hr))
{
self->render = ptr;
ATOMIC_STORE(&self->killNow, 0, almemory_order_release);
if(althrd_create(&self->thread, ALCwasapiPlayback_mixerProc, self) != althrd_success)
self->killNow = 0;
if(althrd_create(&self->thread, ALCmmdevPlayback_mixerProc, self) != althrd_success)
{
if(self->render)
IAudioRenderClient_Release(self->render);
@@ -1177,21 +1170,21 @@ static HRESULT ALCwasapiPlayback_startProxy(ALCwasapiPlayback *self)
}
static void ALCwasapiPlayback_stop(ALCwasapiPlayback *self)
static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self)
{
ThreadRequest req = { self->MsgEvent, 0 };
if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self)))
if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
(void)WaitForResponse(&req);
}
static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self)
static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self)
{
int res;
if(!self->render)
return;
ATOMIC_STORE_SEQ(&self->killNow, 1);
self->killNow = 1;
althrd_join(self->thread, &res);
IAudioRenderClient_Release(self->render);
@@ -1200,24 +1193,23 @@ static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self)
}
static ClockLatency ALCwasapiPlayback_getClockLatency(ALCwasapiPlayback *self)
static ClockLatency ALCmmdevPlayback_getClockLatency(ALCmmdevPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ClockLatency ret;
ALCwasapiPlayback_lock(self);
ALCmmdevPlayback_lock(self);
ret.ClockTime = GetDeviceClockTime(device);
ret.Latency = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES /
device->Frequency;
ALCwasapiPlayback_unlock(self);
ret.Latency = self->Padding * DEVICE_CLOCK_RES / device->Frequency;
ALCmmdevPlayback_unlock(self);
return ret;
}
typedef struct ALCwasapiCapture {
typedef struct ALCmmdevCapture {
DERIVE_FROM_TYPE(ALCbackend);
DERIVE_FROM_TYPE(ALCwasapiProxy);
DERIVE_FROM_TYPE(ALCmmdevProxy);
WCHAR *devid;
@@ -1232,40 +1224,41 @@ typedef struct ALCwasapiCapture {
SampleConverter *SampleConv;
ll_ringbuffer_t *Ring;
ATOMIC(int) killNow;
volatile int killNow;
althrd_t thread;
} ALCwasapiCapture;
} ALCmmdevCapture;
static int ALCwasapiCapture_recordProc(void *arg);
static int ALCmmdevCapture_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)
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);
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_ALCWASAPIPROXY_VTABLE(ALCwasapiCapture);
DEFINE_ALCBACKEND_VTABLE(ALCwasapiCapture);
DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture);
DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture);
static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device)
static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device)
{
SET_VTABLE2(ALCwasapiCapture, ALCbackend, self);
SET_VTABLE2(ALCwasapiCapture, ALCwasapiProxy, self);
SET_VTABLE2(ALCmmdevCapture, ALCbackend, self);
SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self);
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
ALCwasapiProxy_Construct(STATIC_CAST(ALCwasapiProxy, self));
ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
self->devid = NULL;
@@ -1280,60 +1273,53 @@ static void ALCwasapiCapture_Construct(ALCwasapiCapture *self, ALCdevice *device
self->SampleConv = NULL;
self->Ring = NULL;
ATOMIC_INIT(&self->killNow, 0);
self->killNow = 0;
}
static void ALCwasapiCapture_Destruct(ALCwasapiCapture *self)
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(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);
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));
ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg)
FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg)
{
ALCwasapiCapture *self = arg;
ALCmmdevCapture *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALfloat *samples = NULL;
size_t samplesmax = 0;
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = CoInitialize(NULL);
if(FAILED(hr))
{
ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", hr);
ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
V0(device->Backend,lock)();
aluHandleDisconnect(device, "COM init failed: 0x%08lx", hr);
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
return 1;
}
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed))
while(!self->killNow)
{
UINT32 avail;
DWORD res;
@@ -1379,7 +1365,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg)
ALsizei srcframes = numsamples;
dstframes = SampleConverterInput(self->SampleConv,
&srcdata, &srcframes, data[0].buf, (ALsizei)minz(data[0].len, INT_MAX)
&srcdata, &srcframes, data[0].buf, data[0].len
);
if(srcframes > 0 && dstframes == data[0].len && data[1].len > 0)
{
@@ -1388,16 +1374,16 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg)
* 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)
&srcdata, &srcframes, data[1].buf, data[1].len
);
}
}
else
{
ALuint framesize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType,
size_t 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);
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)
@@ -1415,7 +1401,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg)
if(FAILED(hr))
{
V0(device->Backend,lock)();
aluHandleDisconnect(device, "Failed to capture samples: 0x%08lx", hr);
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
break;
}
@@ -1434,7 +1420,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg)
}
static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *deviceName)
static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName)
{
HRESULT hr = S_OK;
@@ -1494,7 +1480,7 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi
ThreadRequest req = { self->MsgEvent, 0 };
hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self)))
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());
@@ -1520,13 +1506,14 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi
ThreadRequest req = { self->MsgEvent, 0 };
hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self)))
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))
{
ALCmmdevCapture_close(self);
if(hr == E_OUTOFMEMORY)
return ALC_OUT_OF_MEMORY;
return ALC_INVALID_VALUE;
@@ -1536,7 +1523,7 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi
return ALC_NO_ERROR;
}
static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self)
static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
void *ptr;
@@ -1573,7 +1560,27 @@ static HRESULT ALCwasapiCapture_openProxy(ALCwasapiCapture *self)
}
static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self)
static void ALCmmdevCapture_close(ALCmmdevCapture *self)
{
ThreadRequest req = { self->MsgEvent, 0 };
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)
IAudioClient_Release(self->client);
@@ -1585,7 +1592,7 @@ static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self)
}
static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self)
static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE OutputType;
@@ -1810,11 +1817,10 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self)
return hr;
}
buffer_len = maxu(device->UpdateSize*device->NumUpdates, buffer_len);
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),
false
FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)
);
if(!self->Ring)
{
@@ -1833,18 +1839,18 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self)
}
static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self)
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(ALCwasapiProxy, self)))
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 ALCwasapiCapture_startProxy(ALCwasapiCapture *self)
static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self)
{
HRESULT hr;
void *ptr;
@@ -1861,8 +1867,8 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self)
if(SUCCEEDED(hr))
{
self->capture = ptr;
ATOMIC_STORE(&self->killNow, 0, almemory_order_release);
if(althrd_create(&self->thread, ALCwasapiCapture_recordProc, self) != althrd_success)
self->killNow = 0;
if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success)
{
ERR("Failed to start thread\n");
IAudioCaptureClient_Release(self->capture);
@@ -1881,21 +1887,21 @@ static HRESULT ALCwasapiCapture_startProxy(ALCwasapiCapture *self)
}
static void ALCwasapiCapture_stop(ALCwasapiCapture *self)
static void ALCmmdevCapture_stop(ALCmmdevCapture *self)
{
ThreadRequest req = { self->MsgEvent, 0 };
if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCwasapiProxy, self)))
if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
(void)WaitForResponse(&req);
}
static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self)
static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self)
{
int res;
if(!self->capture)
return;
ATOMIC_STORE_SEQ(&self->killNow, 1);
self->killNow = 1;
althrd_join(self->thread, &res);
IAudioCaptureClient_Release(self->capture);
@@ -1905,41 +1911,42 @@ static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self)
}
ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self)
ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self)
{
return (ALuint)ll_ringbuffer_read_space(self->Ring);
}
ALCenum ALCwasapiCapture_captureSamples(ALCwasapiCapture *self, ALCvoid *buffer, ALCuint samples)
ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples)
{
if(ALCwasapiCapture_availableSamples(self) < samples)
if(ALCmmdevCapture_availableSamples(self) < samples)
return ALC_INVALID_VALUE;
ll_ringbuffer_read(self->Ring, buffer, samples);
return ALC_NO_ERROR;
}
typedef struct ALCwasapiBackendFactory {
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);
} ALCwasapiBackendFactory;
#define ALCWASAPIBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwasapiBackendFactory, ALCbackendFactory) } }
} ALCmmdevBackendFactory;
#define ALCMMDEVBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCmmdevBackendFactory, 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, al_string *outnames);
static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
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(ALCwasapiBackendFactory);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCmmdevBackendFactory);
static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(self))
static BOOL MMDevApiLoad(void)
{
static HRESULT InitResult;
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
if(!ThreadHdl)
{
ThreadRequest req;
@@ -1950,17 +1957,26 @@ static ALCboolean ALCwasapiBackendFactory_init(ALCwasapiBackendFactory* UNUSED(s
ERR("Failed to create event: %lu\n", GetLastError());
else
{
ThreadHdl = CreateThread(NULL, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID);
ThreadHdl = CreateThread(NULL, 0, ALCmmdevProxy_messageHandler, &req, 0, &ThreadID);
if(ThreadHdl != NULL)
InitResult = WaitForResponse(&req);
CloseHandle(req.FinishedEvt);
}
}
return SUCCEEDED(InitResult) ? ALC_TRUE : ALC_FALSE;
return SUCCEEDED(InitResult);
}
static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self))
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);
@@ -1977,14 +1993,19 @@ static void ALCwasapiBackendFactory_deinit(ALCwasapiBackendFactory* UNUSED(self)
}
}
static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* UNUSED(self), ALCbackend_Type type)
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 ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory* UNUSED(self), enum DevProbe type)
{
ThreadRequest req = { NULL, 0 };
@@ -1998,38 +2019,32 @@ 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, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
#undef APPEND_OUTNAME
}
CloseHandle(req.FinishedEvt);
req.FinishedEvt = NULL;
}
}
static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCwasapiPlayback *backend;
NEW_OBJ(backend, ALCwasapiPlayback)(device);
ALCmmdevPlayback *backend;
NEW_OBJ(backend, ALCmmdevPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCwasapiCapture *backend;
NEW_OBJ(backend, ALCwasapiCapture)(device);
ALCmmdevCapture *backend;
NEW_OBJ(backend, ALCmmdevCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
@@ -2038,8 +2053,8 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory
}
ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void)
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void)
{
static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER;
static ALCmmdevBackendFactory factory = ALCMMDEVBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
+15 -10
View File
@@ -36,7 +36,7 @@
typedef struct ALCnullBackend {
DERIVE_FROM_TYPE(ALCbackend);
ATOMIC(int) killNow;
volatile int killNow;
althrd_t thread;
} ALCnullBackend;
@@ -45,6 +45,7 @@ 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);
@@ -65,8 +66,6 @@ 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);
}
@@ -88,8 +87,7 @@ static int ALCnullBackend_mixerProc(void *ptr)
ERR("Failed to get starting time\n");
return 1;
}
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
@@ -137,6 +135,10 @@ 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);
@@ -145,7 +147,7 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
{
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = 0;
if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
@@ -155,8 +157,10 @@ static void ALCnullBackend_stop(ALCnullBackend *self)
{
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
}
@@ -171,7 +175,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, al_string *outnames);
static void ALCnullBackendFactory_probe(ALCnullBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCnullBackendFactory);
@@ -195,13 +199,14 @@ static ALCboolean ALCnullBackendFactory_querySupport(ALCnullBackendFactory* UNUS
return ALC_FALSE;
}
static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(nullDevice);
break;
case CAPTURE_DEVICE_PROBE:
alstr_append_range(outnames, nullDevice, nullDevice+sizeof(nullDevice));
break;
}
}
+150 -85
View File
@@ -26,9 +26,8 @@
#include "alMain.h"
#include "alu.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
#include "threads.h"
#include "backends/base.h"
@@ -146,7 +145,7 @@ typedef struct ALCopenslPlayback {
SLObjectItf mBufferQueueObj;
ll_ringbuffer_t *mRing;
alsem_t mSem;
alcnd_t mCond;
ALsizei mFrameSize;
@@ -160,6 +159,7 @@ 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);
@@ -184,7 +184,7 @@ static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *devi
self->mBufferQueueObj = NULL;
self->mRing = NULL;
alsem_init(&self->mSem, 0);
alcnd_init(&self->mCond);
self->mFrameSize = 0;
@@ -197,11 +197,11 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self)
VCALL0(self->mBufferQueueObj,Destroy)();
self->mBufferQueueObj = NULL;
if(self->mOutputMix)
if(self->mOutputMix != NULL)
VCALL0(self->mOutputMix,Destroy)();
self->mOutputMix = NULL;
if(self->mEngineObj)
if(self->mEngineObj != NULL)
VCALL0(self->mEngineObj,Destroy)();
self->mEngineObj = NULL;
self->mEngine = NULL;
@@ -209,7 +209,7 @@ static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self)
ll_ringbuffer_free(self->mRing);
self->mRing = NULL;
alsem_destroy(&self->mSem);
alcnd_destroy(&self->mCond);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
@@ -230,7 +230,7 @@ static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq),
*/
ll_ringbuffer_read_advance(self->mRing, 1);
alsem_post(&self->mSem);
alcnd_signal(&self->mCond);
}
@@ -242,6 +242,7 @@ 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);
@@ -254,18 +255,25 @@ static int ALCopenslPlayback_mixerProc(void *arg)
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);
if(SL_RESULT_SUCCESS != result)
aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result);
while(SL_RESULT_SUCCESS == result &&
!ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(ATOMIC_LOAD_SEQ(&self->mKillNow) == AL_FALSE && device->Connected)
{
size_t todo;
size_t todo, len0, len1;
if(ll_ringbuffer_write_space(self->mRing) == 0)
if(ll_ringbuffer_write_space(self->mRing) <= padding)
{
SLuint32 state = 0;
@@ -278,48 +286,62 @@ static int ALCopenslPlayback_mixerProc(void *arg)
}
if(SL_RESULT_SUCCESS != result)
{
aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result);
aluHandleDisconnect(device);
break;
}
if(ll_ringbuffer_write_space(self->mRing) == 0)
/* 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)
{
ALCopenslPlayback_unlock(self);
alsem_wait(&self->mSem);
ALCopenslPlayback_lock(self);
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;
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);
len0 = minu(todo, data[0].len);
len1 = minu(todo-len0, data[1].len);
todo = data[0].len+data[1].len;
ll_ringbuffer_write_advance(self->mRing, todo);
for(size_t i = 0;i < todo;i++)
aluMixData(device, data[0].buf, len0*device->UpdateSize);
for(size_t i = 0;i < len0;i++)
{
if(!data[0].len)
{
data[0] = data[1];
data[1].buf = NULL;
data[1].len = 0;
}
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;
}
if(SL_RESULT_SUCCESS == result)
ll_ringbuffer_write_advance(self->mRing, 1);
data[0].len--;
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);
@@ -380,6 +402,20 @@ 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;
VCALL0(self->mOutputMix,Destroy)();
self->mOutputMix = NULL;
VCALL0(self->mEngineObj,Destroy)();
self->mEngineObj = NULL;
self->mEngine = NULL;
}
static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -391,24 +427,19 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self)
SLInterfaceID ids[2];
SLboolean reqs[2];
SLresult result;
JNIEnv *env;
if(self->mBufferQueueObj != NULL)
VCALL0(self->mBufferQueueObj,Destroy)();
self->mBufferQueueObj = NULL;
ll_ringbuffer_free(self->mRing);
self->mRing = NULL;
sampleRate = device->Frequency;
#if 0
if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
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.
*/
JNIEnv *env = Android_GetJNIEnv();
jobject jctx = Android_GetContext();
#if 0
/* Get necessary stuff for using java.lang.Integer,
* android.content.Context, and android.media.AudioManager.
*/
@@ -444,7 +475,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)(jctx, 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);
@@ -465,8 +496,8 @@ static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self)
if(!sampleRate) sampleRate = device->Frequency;
else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
}
#endif
}
if(sampleRate != device->Frequency)
{
@@ -550,18 +581,6 @@ 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)
{
@@ -577,10 +596,17 @@ 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_reset(self->mRing);
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);
@@ -614,7 +640,14 @@ static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE))
return;
alsem_post(&self->mSem);
/* 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);
@@ -647,6 +680,9 @@ 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)
@@ -685,6 +721,7 @@ 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);
@@ -723,6 +760,9 @@ 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;
@@ -732,9 +772,6 @@ 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));
}
@@ -853,9 +890,8 @@ 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 + 1,
device->UpdateSize * self->mFrameSize);
result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&bufferQueue);
@@ -904,6 +940,21 @@ 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;
@@ -921,8 +972,7 @@ static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self)
if(SL_RESULT_SUCCESS != result)
{
ALCopenslCapture_lock(self);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
"Failed to start capture: 0x%08x", result);
aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
ALCopenslCapture_unlock(self);
return ALC_FALSE;
}
@@ -952,16 +1002,14 @@ 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);
@@ -974,11 +1022,7 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *
{
/* Finished a chunk, reset the offset and advance the read pointer. */
self->mSplOffset = 0;
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;
advance++;
data[0].len--;
if(!data[0].len)
@@ -989,11 +1033,29 @@ static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *
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, "Failed to update capture buffer: 0x%08x", result);
aluHandleDisconnect(device);
ALCopenslCapture_unlock(self);
return ALC_INVALID_DEVICE;
}
@@ -1029,13 +1091,16 @@ static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory*
return ALC_FALSE;
}
static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(opensl_device);
break;
case CAPTURE_DEVICE_PROBE:
alstr_append_range(outnames, opensl_device, opensl_device+sizeof(opensl_device));
AppendAllDevicesList(opensl_device);
break;
}
}
+45 -46
View File
@@ -35,8 +35,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "ringbuffer.h"
#include "threads.h"
#include "compat.h"
@@ -252,8 +250,9 @@ typedef struct ALCplaybackOSS {
static int ALCplaybackOSS_mixerProc(void *ptr);
static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self);
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
static void ALCplaybackOSS_close(ALCplaybackOSS *self);
static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
@@ -284,8 +283,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALCplaybackOSS_lock(self);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected)
{
FD_ZERO(&wfds);
FD_SET(self->fd, &wfds);
@@ -300,7 +298,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
@@ -320,8 +318,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
ERR("write failed: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed writing playback samples: %s",
strerror(errno));
aluHandleDisconnect(device);
break;
}
@@ -340,19 +337,9 @@ 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)
{
if(self->fd != -1)
close(self->fd);
self->fd = -1;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
{
struct oss_device *dev = &oss_playback;
@@ -392,6 +379,12 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
return ALC_NO_ERROR;
}
static void ALCplaybackOSS_close(ALCplaybackOSS *self)
{
close(self->fd);
self->fd = -1;
}
static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -524,8 +517,9 @@ typedef struct ALCcaptureOSS {
static int ALCcaptureOSS_recordProc(void *ptr);
static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
static void ALCcaptureOSS_close(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
@@ -568,7 +562,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
@@ -585,7 +579,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
{
ERR("read failed: %s\n", strerror(errno));
ALCcaptureOSS_lock(self);
aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno));
aluHandleDisconnect(device);
ALCcaptureOSS_unlock(self);
break;
}
@@ -602,22 +596,9 @@ 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)
{
if(self->fd != -1)
close(self->fd);
self->fd = -1;
ll_ringbuffer_free(self->ring);
self->ring = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -729,7 +710,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
return ALC_INVALID_VALUE;
}
self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false);
self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize);
if(!self->ring)
{
ERR("Ring buffer create failed\n");
@@ -743,6 +724,15 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
return ALC_NO_ERROR;
}
static void ALCcaptureOSS_close(ALCcaptureOSS *self)
{
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);
@@ -786,7 +776,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, al_string *outnames);
static void ALCossBackendFactory_probe(ALCossBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCossBackendFactory);
@@ -820,31 +810,40 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self),
return ALC_FALSE;
}
void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
{
struct oss_device *cur = NULL;
struct oss_device *cur;
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;
break;
}
while(cur != NULL)
{
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
alstr_append_range(outnames, cur->handle, cur->handle+strlen(cur->handle)+1);
cur = cur->next;
AppendCaptureDeviceList(cur->handle);
cur = cur->next;
}
break;
}
}
+34 -14
View File
@@ -26,8 +26,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "ringbuffer.h"
#include "compat.h"
#include "backends/base.h"
@@ -141,6 +139,7 @@ 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);
@@ -164,9 +163,8 @@ static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
static void ALCportPlayback_Destruct(ALCportPlayback *self)
{
PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
@@ -253,6 +251,14 @@ retry_open:
}
static void ALCportPlayback_close(ALCportPlayback *self)
{
PaError err = Pa_CloseStream(self->stream);
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;
@@ -330,6 +336,7 @@ 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);
@@ -349,17 +356,16 @@ 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)
{
PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
ll_ringbuffer_free(self->ring);
if(self->ring)
ll_ringbuffer_free(self->ring);
self->ring = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
@@ -395,7 +401,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, false);
self->ring = ll_ringbuffer_create(samples, frame_size);
if(self->ring == NULL) return ALC_INVALID_VALUE;
self->params.device = -1;
@@ -444,6 +450,17 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
return ALC_NO_ERROR;
}
static void ALCportCapture_close(ALCportCapture *self)
{
PaError err = Pa_CloseStream(self->stream);
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)
{
@@ -484,8 +501,9 @@ 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, al_string *outnames);
static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
@@ -517,13 +535,15 @@ static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUS
return ALC_FALSE;
}
static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(pa_device);
break;
case CAPTURE_DEVICE_PROBE:
alstr_append_range(outnames, pa_device, pa_device+sizeof(pa_device));
AppendCaptureDeviceList(pa_device);
break;
}
}
+81 -76
View File
@@ -25,7 +25,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "threads.h"
#include "compat.h"
@@ -334,20 +333,18 @@ 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";
al_string binname = AL_STRING_INIT_STATIC();
char path_name[PATH_MAX];
pa_context_state_t state;
pa_context *context;
int err;
GetProcBinary(NULL, &binname);
if(!alstr_empty(binname))
name = alstr_get_cstr(binname);
if(pa_get_binary_name(path_name, sizeof(path_name)))
name = pa_path_get_filename(path_name);
context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
if(!context)
{
ERR("pa_context_new() failed\n");
alstr_reset(&binname);
return NULL;
}
@@ -374,10 +371,9 @@ 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);
context = NULL;
return NULL;
}
alstr_reset(&binname);
return context;
}
@@ -472,7 +468,7 @@ typedef struct ALCpulsePlayback {
pa_stream *stream;
pa_context *context;
ATOMIC(ALenum) killNow;
volatile ALboolean killNow;
althrd_t thread;
} ALCpulsePlayback;
@@ -495,6 +491,7 @@ 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);
@@ -513,20 +510,11 @@ 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);
ATOMIC_INIT(&self->killNow, AL_TRUE);
}
static void ALCpulsePlayback_Destruct(ALCpulsePlayback *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));
}
@@ -651,7 +639,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, "Playback state failure");
aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
}
pa_threaded_mainloop_signal(self->loop, 0);
}
@@ -662,7 +650,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, "Playback stream failure");
aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
}
pa_threaded_mainloop_signal(self->loop, 0);
}
@@ -830,17 +818,13 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
pa_threaded_mainloop_lock(self->loop);
frame_size = pa_frame_size(&self->spec);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow && device->Connected)
{
void *buf;
int ret;
len = pa_stream_writable_size(self->stream);
if(len < 0)
{
ERR("Failed to get writable size: %ld", (long)len);
aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len);
aluHandleDisconnect(device);
break;
}
@@ -866,16 +850,31 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
pa_threaded_mainloop_wait(self->loop);
continue;
}
len -= len%self->attr.minreq;
len -= len%frame_size;
buf = pa_xmalloc(len);
while(len > 0)
{
size_t newlen = len;
int ret;
void *buf;
pa_free_cb_t free_func = NULL;
aluMixData(device, buf, len/frame_size);
if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
{
buf = pa_xmalloc(newlen);
free_func = pa_xfree;
}
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));
aluMixData(device, buf, 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;
}
}
pa_threaded_mainloop_unlock(self->loop);
@@ -953,6 +952,16 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
return ALC_NO_ERROR;
}
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);
}
static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -1129,7 +1138,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
{
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
@@ -1140,9 +1149,10 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
pa_operation *o;
int res;
if(!self->stream || ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(!self->stream || self->killNow)
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
@@ -1164,16 +1174,13 @@ 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);
err = pa_stream_get_latency(self->stream, &latency, &neg);
pa_threaded_mainloop_unlock(self->loop);
if(UNLIKELY(err != 0))
if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 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
@@ -1184,9 +1191,9 @@ static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self)
latency = 0;
neg = 0;
}
else if(UNLIKELY(neg))
latency = 0;
ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
if(neg) latency = 0;
ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000;
pa_threaded_mainloop_unlock(self->loop);
return ret;
}
@@ -1238,6 +1245,7 @@ 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);
@@ -1256,19 +1264,11 @@ 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)
{
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));
}
@@ -1380,7 +1380,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, "Capture state failure");
aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
}
pa_threaded_mainloop_signal(self->loop, 0);
}
@@ -1391,7 +1391,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, "Capture stream failure");
aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
}
pa_threaded_mainloop_signal(self->loop, 0);
}
@@ -1615,6 +1615,16 @@ fail:
return ALC_INVALID_VALUE;
}
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);
}
static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
{
pa_operation *o;
@@ -1654,15 +1664,14 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu
state = pa_stream_get_state(self->stream);
if(!PA_STREAM_IS_GOOD(state))
{
aluHandleDisconnect(device, "Bad capture state: %u", state);
aluHandleDisconnect(device);
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, "Failed retrieving capture samples: %s",
pa_strerror(pa_context_errno(self->context)));
aluHandleDisconnect(device);
break;
}
self->cap_remain = self->cap_len;
@@ -1695,7 +1704,7 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
size_t readable = self->cap_remain;
if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
if(device->Connected)
{
ssize_t got;
pa_threaded_mainloop_lock(self->loop);
@@ -1703,7 +1712,7 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
if(got < 0)
{
ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got));
aluHandleDisconnect(device);
}
else if((size_t)got > self->cap_len)
readable += got - self->cap_len;
@@ -1718,24 +1727,21 @@ 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);
err = pa_stream_get_latency(self->stream, &latency, &neg);
pa_threaded_mainloop_unlock(self->loop);
if(UNLIKELY(err != 0))
if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0)
{
ERR("Failed to get stream latency: 0x%x\n", err);
latency = 0;
neg = 0;
}
else if(UNLIKELY(neg))
latency = 0;
ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
if(neg) latency = 0;
ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000;
pa_threaded_mainloop_unlock(self->loop);
return ret;
}
@@ -1760,8 +1766,9 @@ 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, al_string *outnames);
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
@@ -1834,25 +1841,23 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN
return ALC_FALSE;
}
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type)
{
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();
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME);
#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();
VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME);
#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;
#undef APPEND_OUTNAME
}
}
@@ -1900,7 +1905,7 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN
return ALC_FALSE;
}
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type), al_string* UNUSED(outnames))
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe UNUSED(type))
{
}
+44 -43
View File
@@ -46,7 +46,7 @@ typedef struct {
ALvoid* buffer;
ALsizei size;
ATOMIC(ALenum) killNow;
volatile int killNow;
althrd_t thread;
} qsa_data;
@@ -119,9 +119,6 @@ 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);
@@ -169,8 +166,9 @@ typedef struct PlaybackWrapper {
} PlaybackWrapper;
static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
static void PlaybackWrapper_Destruct(PlaybackWrapper *self);
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);
@@ -209,7 +207,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr)
);
V0(device->Backend,lock)();
while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
while(!data->killNow)
{
FD_ZERO(&wfds);
FD_SET(data->audio_fd, &wfds);
@@ -223,7 +221,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr)
if(sret == -1)
{
ERR("select error: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
aluHandleDisconnect(device);
break;
}
if(sret == 0)
@@ -235,7 +233,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 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
while(len>0 && !data->killNow)
{
int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
if(wrote <= 0)
@@ -254,7 +252,7 @@ FORCE_ALIGN static int qsa_proc_playback(void *ptr)
{
if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0)
{
aluHandleDisconnect(device, "Playback recovery failed");
aluHandleDisconnect(device);
break;
}
}
@@ -285,7 +283,6 @@ 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;
@@ -599,7 +596,7 @@ static ALCboolean qsa_start_playback(PlaybackWrapper *self)
{
qsa_data *data = self->ExtraData;
ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release);
data->killNow = 0;
if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success)
return ALC_FALSE;
@@ -611,8 +608,10 @@ static void qsa_stop_playback(PlaybackWrapper *self)
qsa_data *data = self->ExtraData;
int res;
if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel))
if(data->killNow)
return;
data->killNow = 1;
althrd_join(data->thread, &res);
}
@@ -625,19 +624,16 @@ static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
self->ExtraData = NULL;
}
static void PlaybackWrapper_Destruct(PlaybackWrapper *self)
{
if(self->ExtraData)
qsa_close_playback(self);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
{
return qsa_open_playback(self, name);
}
static void PlaybackWrapper_close(PlaybackWrapper *self)
{
qsa_close_playback(self);
}
static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
{
return qsa_reset_playback(self);
@@ -665,8 +661,9 @@ typedef struct CaptureWrapper {
} CaptureWrapper;
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
static void CaptureWrapper_Destruct(CaptureWrapper *self);
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);
@@ -849,7 +846,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, "Failed capture recovery: %s", snd_strerror(rstatus));
aluHandleDisconnect(device);
return 0;
}
@@ -892,7 +889,7 @@ static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuin
switch (selectret)
{
case -1:
aluHandleDisconnect(device, "Failed to check capture samples");
aluHandleDisconnect(device);
return ALC_INVALID_DEVICE;
case 0:
break;
@@ -923,8 +920,7 @@ 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, "Failed capture recovery: %s",
snd_strerror(rstatus));
aluHandleDisconnect(device);
return ALC_INVALID_DEVICE;
}
snd_pcm_capture_go(data->pcmHandle);
@@ -949,19 +945,16 @@ static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
self->ExtraData = NULL;
}
static void CaptureWrapper_Destruct(CaptureWrapper *self)
{
if(self->ExtraData)
qsa_close_capture(self);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
{
return qsa_open_capture(self, name);
}
static void CaptureWrapper_close(CaptureWrapper *self)
{
qsa_close_capture(self);
}
static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
{
qsa_start_capture(self);
@@ -992,7 +985,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, al_string *outnames);
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);
@@ -1019,25 +1012,33 @@ static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED
return ALC_FALSE;
}
static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type)
{
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);
VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_OUTNAME);
#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
#undef APPEND_DEVICE
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);
VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_OUTNAME);
#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
#undef APPEND_DEVICE
break;
#undef APPEND_OUTNAME
}
}
-288
View File
@@ -1,288 +0,0 @@
/**
* 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 <stdlib.h>
#include <SDL2/SDL.h>
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
#ifdef _WIN32
#define DEVNAME_PREFIX "OpenAL Soft on "
#else
#define DEVNAME_PREFIX ""
#endif
typedef struct ALCsdl2Backend {
DERIVE_FROM_TYPE(ALCbackend);
SDL_AudioDeviceID deviceID;
ALsizei frameSize;
ALuint Frequency;
enum DevFmtChannels FmtChans;
enum DevFmtType FmtType;
ALuint UpdateSize;
} ALCsdl2Backend;
static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device);
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);
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 void ALCsdl2Backend_lock(ALCsdl2Backend *self);
static void ALCsdl2Backend_unlock(ALCsdl2Backend *self);
DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend)
DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend);
static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device";
static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), 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;
self->UpdateSize = device->UpdateSize;
}
static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self)
{
if(self->deviceID)
SDL_CloseAudioDevice(self->deviceID);
self->deviceID = 0;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len)
{
ALCsdl2Backend *self = (ALCsdl2Backend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
assert((len % self->frameSize) == 0);
aluMixData(device, stream, len / self->frameSize);
}
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;
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;
want.userdata = self;
/* 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;
device->Frequency = have.freq;
if(have.channels == 1)
device->FmtChans = DevFmtMono;
else if(have.channels == 2)
device->FmtChans = DevFmtStereo;
else
{
ERR("Got unhandled SDL channel count: %d\n", (int)have.channels);
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("Got unsupported SDL format: 0x%04x\n", have.format);
return ALC_INVALID_VALUE;
}
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;
self->UpdateSize = device->UpdateSize;
alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName);
return ALC_NO_ERROR;
}
static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Frequency = self->Frequency;
device->FmtChans = self->FmtChans;
device->FmtType = self->FmtType;
device->UpdateSize = self->UpdateSize;
device->NumUpdates = 2;
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self)
{
SDL_PauseAudioDevice(self->deviceID, 0);
return ALC_TRUE;
}
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);
} ALCsdl2BackendFactory;
#define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } }
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, al_string *outnames);
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))
{
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)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
{
int num_devices, i;
al_string name;
if(type != ALL_DEVICE_PROBE)
return;
AL_STRING_INIT(name);
num_devices = SDL_GetNumAudioDevices(SDL_FALSE);
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));
if(!alstr_empty(name))
alstr_append_range(outnames, VECTOR_BEGIN(name), VECTOR_END(name)+1);
}
alstr_reset(&name);
}
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;
}
+69 -323
View File
@@ -27,17 +27,15 @@
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "ringbuffer.h"
#include "backends/base.h"
#include <sndio.h>
static const ALCchar sndio_device[] = "SndIO Default";
typedef struct SndioPlayback {
typedef struct ALCsndioBackend {
DERIVE_FROM_TYPE(ALCbackend);
struct sio_hdl *sndHandle;
@@ -45,39 +43,39 @@ typedef struct SndioPlayback {
ALvoid *mix_data;
ALsizei data_size;
ATOMIC(int) killNow;
volatile int killNow;
althrd_t thread;
} SndioPlayback;
} ALCsndioBackend;
static int SndioPlayback_mixerProc(void *ptr);
static int ALCsndioBackend_mixerProc(void *ptr);
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)
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(SndioPlayback);
DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend);
static void SndioPlayback_Construct(SndioPlayback *self, ALCdevice *device)
static const ALCchar sndio_device[] = "SndIO Default";
static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(SndioPlayback, ALCbackend, self);
self->sndHandle = NULL;
self->mix_data = NULL;
ATOMIC_INIT(&self->killNow, AL_TRUE);
SET_VTABLE2(ALCsndioBackend, ALCbackend, self);
}
static void SndioPlayback_Destruct(SndioPlayback *self)
static void ALCsndioBackend_Destruct(ALCsndioBackend *self)
{
if(self->sndHandle)
sio_close(self->sndHandle);
@@ -90,9 +88,9 @@ static void SndioPlayback_Destruct(SndioPlayback *self)
}
static int SndioPlayback_mixerProc(void *ptr)
static int ALCsndioBackend_mixerProc(void *ptr)
{
SndioPlayback *self = (SndioPlayback*)ptr;
ALCsndioBackend *self = (ALCsndioBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALsizei frameSize;
size_t wrote;
@@ -102,23 +100,22 @@ static int SndioPlayback_mixerProc(void *ptr)
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow && device->Connected)
{
ALsizei len = self->data_size;
ALubyte *WritePtr = self->mix_data;
SndioPlayback_lock(self);
ALCsndioBackend_lock(self);
aluMixData(device, WritePtr, len/frameSize);
SndioPlayback_unlock(self);
while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
ALCsndioBackend_unlock(self);
while(len > 0 && !self->killNow)
{
wrote = sio_write(self->sndHandle, WritePtr, len);
if(wrote == 0)
{
ERR("sio_write failed\n");
ALCdevice_Lock(device);
aluHandleDisconnect(device, "Failed to write playback samples");
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
break;
}
@@ -132,7 +129,7 @@ static int SndioPlayback_mixerProc(void *ptr)
}
static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name)
static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -153,7 +150,13 @@ static ALCenum SndioPlayback_open(SndioPlayback *self, const ALCchar *name)
return ALC_NO_ERROR;
}
static ALCboolean SndioPlayback_reset(SndioPlayback *self)
static void ALCsndioBackend_close(ALCsndioBackend *self)
{
sio_close(self->sndHandle);
self->sndHandle = NULL;
}
static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
struct sio_par par;
@@ -238,7 +241,7 @@ static ALCboolean SndioPlayback_reset(SndioPlayback *self)
return ALC_TRUE;
}
static ALCboolean SndioPlayback_start(SndioPlayback *self)
static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -254,8 +257,8 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self)
return ALC_FALSE;
}
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
if(althrd_create(&self->thread, SndioPlayback_mixerProc, self) != althrd_success)
self->killNow = 0;
if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success)
{
sio_stop(self->sndHandle);
return ALC_FALSE;
@@ -264,12 +267,14 @@ static ALCboolean SndioPlayback_start(SndioPlayback *self)
return ALC_TRUE;
}
static void SndioPlayback_stop(SndioPlayback *self)
static void ALCsndioBackend_stop(ALCsndioBackend *self)
{
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
if(!sio_stop(self->sndHandle))
@@ -280,318 +285,59 @@ 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 {
typedef struct ALCsndioBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} SndioBackendFactory;
#define SNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(SndioBackendFactory, ALCbackendFactory) } }
} ALCsndioBackendFactory;
#define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } }
ALCbackendFactory *SndioBackendFactory_getFactory(void);
ALCbackendFactory *ALCsndioBackendFactory_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, al_string *outnames);
static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(SndioBackendFactory);
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 *SndioBackendFactory_getFactory(void)
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void)
{
static SndioBackendFactory factory = SNDIOBACKENDFACTORY_INITIALIZER;
static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean SndioBackendFactory_init(SndioBackendFactory* UNUSED(self))
static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self))
{
/* No dynamic loading */
return ALC_TRUE;
}
static ALCboolean SndioBackendFactory_querySupport(SndioBackendFactory* UNUSED(self), ALCbackend_Type type)
static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
static void SndioBackendFactory_probe(SndioBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
AppendAllDevicesList(sndio_device);
break;
case CAPTURE_DEVICE_PROBE:
alstr_append_range(outnames, sndio_device, sndio_device+sizeof(sndio_device));
break;
}
}
static ALCbackend* SndioBackendFactory_createBackend(SndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
SndioPlayback *backend;
NEW_OBJ(backend, SndioPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
SndioCapture *backend;
NEW_OBJ(backend, SndioCapture)(device);
ALCsndioBackend *backend;
NEW_OBJ(backend, ALCsndioBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
+13 -10
View File
@@ -34,7 +34,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "threads.h"
#include "compat.h"
@@ -60,6 +59,7 @@ 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);
@@ -84,7 +84,6 @@ 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);
}
@@ -120,8 +119,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr)
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALCsolarisBackend_lock(self);
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!ATOMIC_LOAD_SEQ(&self->killNow) && device->Connected)
{
FD_ZERO(&wfds);
FD_SET(self->fd, &wfds);
@@ -136,7 +134,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr)
if(errno == EINTR)
continue;
ERR("select failed: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno));
aluHandleDisconnect(device);
break;
}
else if(sret == 0)
@@ -156,8 +154,7 @@ static int ALCsolarisBackend_mixerProc(void *ptr)
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
ERR("write failed: %s\n", strerror(errno));
aluHandleDisconnect(device, "Failed to write playback samples: %s",
strerror(errno));
aluHandleDisconnect(device);
break;
}
@@ -193,6 +190,12 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na
return ALC_NO_ERROR;
}
static void ALCsolarisBackend_close(ALCsolarisBackend *self)
{
close(self->fd);
self->fd = -1;
}
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -302,7 +305,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, al_string *outnames);
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory);
@@ -327,7 +330,7 @@ static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory
return ALC_FALSE;
}
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -337,7 +340,7 @@ static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self
struct stat buf;
if(stat(solaris_driver, &buf) == 0)
#endif
alstr_append_range(outnames, solaris_device, solaris_device+sizeof(solaris_device));
AppendAllDevicesList(solaris_device);
}
break;
+20 -20
View File
@@ -27,7 +27,6 @@
#include "alMain.h"
#include "alu.h"
#include "alconfig.h"
#include "threads.h"
#include "compat.h"
@@ -77,15 +76,16 @@ typedef struct ALCwaveBackend {
ALvoid *mBuffer;
ALuint mSize;
ATOMIC(ALenum) killNow;
volatile int killNow;
althrd_t thread;
} ALCwaveBackend;
static int ALCwaveBackend_mixerProc(void *ptr);
static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
static void ALCwaveBackend_Destruct(ALCwaveBackend *self);
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
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);
@@ -110,17 +110,9 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
self->mBuffer = NULL;
self->mSize = 0;
ATOMIC_INIT(&self->killNow, AL_TRUE);
self->killNow = 1;
}
static void ALCwaveBackend_Destruct(ALCwaveBackend *self)
{
if(self->mFile)
fclose(self->mFile);
self->mFile = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCwaveBackend_mixerProc(void *ptr)
{
@@ -143,8 +135,7 @@ static int ALCwaveBackend_mixerProc(void *ptr)
ERR("Failed to get starting time\n");
return 1;
}
while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
@@ -205,7 +196,7 @@ static int ALCwaveBackend_mixerProc(void *ptr)
{
ERR("Error writing to file\n");
ALCdevice_Lock(device);
aluHandleDisconnect(device, "Failed to write playback samples");
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
break;
}
@@ -242,6 +233,13 @@ 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;
@@ -356,7 +354,7 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
return ALC_FALSE;
}
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = 0;
if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
{
free(self->mBuffer);
@@ -374,8 +372,10 @@ static void ALCwaveBackend_stop(ALCwaveBackend *self)
long size;
int res;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
free(self->mBuffer);
@@ -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, al_string *outnames);
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
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, al_string *outnames)
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
case ALL_DEVICE_PROBE:
alstr_append_range(outnames, waveDevice, waveDevice+sizeof(waveDevice));
AppendAllDevicesList(waveDevice);
break;
case CAPTURE_DEVICE_PROBE:
break;
+65 -48
View File
@@ -29,7 +29,6 @@
#include "alMain.h"
#include "alu.h"
#include "ringbuffer.h"
#include "threads.h"
#include "backends/base.h"
@@ -148,7 +147,7 @@ typedef struct ALCwinmmPlayback {
WAVEFORMATEX Format;
ATOMIC(ALenum) killNow;
volatile ALboolean killNow;
althrd_t thread;
} ALCwinmmPlayback;
@@ -159,6 +158,7 @@ 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);
@@ -180,7 +180,7 @@ static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device
InitRef(&self->WaveBuffersCommitted, 0);
self->OutHdl = NULL;
ATOMIC_INIT(&self->killNow, AL_TRUE);
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(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
if(self->killNow)
{
if(ReadRef(&self->WaveBuffersCommitted) == 0)
break;
@@ -311,6 +311,9 @@ 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;
@@ -371,7 +374,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
ALint BufferSize;
ALuint i;
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
@@ -402,8 +405,11 @@ static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self)
void *buffer = NULL;
int i;
if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
if(self->killNow)
return;
// Set flag to stop processing headers
self->killNow = AL_TRUE;
althrd_join(self->thread, &i);
// Release the wave buffers
@@ -430,7 +436,7 @@ typedef struct ALCwinmmCapture {
WAVEFORMATEX Format;
ATOMIC(ALenum) killNow;
volatile ALboolean killNow;
althrd_t thread;
} ALCwinmmCapture;
@@ -441,6 +447,7 @@ 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);
@@ -462,38 +469,11 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device)
InitRef(&self->WaveBuffersCommitted, 0);
self->InHdl = NULL;
ATOMIC_INIT(&self->killNow, AL_TRUE);
self->killNow = AL_TRUE;
}
static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
{
void *buffer = NULL;
int i;
/* Tell the processing thread to quit and wait for it to do so. */
if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
{
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;
@@ -532,7 +512,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(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
if(self->killNow)
break;
WaveHdr = ((WAVEHDR*)msg.lParam);
@@ -626,7 +606,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, self->Format.nBlockAlign, false);
self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign);
if(!self->Ring) goto failure;
InitRef(&self->WaveBuffersCommitted, 0);
@@ -652,7 +632,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
IncrementRef(&self->WaveBuffersCommitted);
}
ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
goto failure;
@@ -677,6 +657,37 @@ 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. */
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);
@@ -696,10 +707,21 @@ static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *bu
static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
{
return (ALCuint)ll_ringbuffer_read_space(self->Ring);
return ll_ringbuffer_read_space(self->Ring);
}
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;
@@ -708,7 +730,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, al_string *outnames);
static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory);
@@ -738,24 +760,19 @@ static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UN
return ALC_FALSE;
}
static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type)
{
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, APPEND_OUTNAME);
VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
ProbeCaptureDevices();
VECTOR_FOR_EACH(const al_string, CaptureDevices, APPEND_OUTNAME);
VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
break;
#undef APPEND_OUTNAME
}
}
+212 -92
View File
@@ -3,7 +3,7 @@
#include "bformatdec.h"
#include "ambdec.h"
#include "filters/splitter.h"
#include "mixer_defs.h"
#include "alu.h"
#include "bool.h"
@@ -11,14 +11,114 @@
#include "almalloc.h"
/* 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] = {
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;
}
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 coeff, d, x;
ALfloat z1, z2;
ALsizei 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 - z1) * coeff;
x = z1 + d;
z1 = 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*z1;
x = z1 + coeff*d;
z1 = d;
hpout[i] = x - lpout[i];
}
splitter->hp_z1 = z1;
}
void splitterap_init(SplitterAllpass *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->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;
}
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
};
const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
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) */
@@ -36,7 +136,7 @@ const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
2.645751311f, /* ACN 14 (N), sqrt(7) */
2.645751311f, /* ACN 15 (P), sqrt(7) */
};
const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
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) */
@@ -56,9 +156,11 @@ const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
};
#define HF_BAND 0
#define LF_BAND 1
#define NUM_BANDS 2
enum FreqBand {
FB_HighFreq,
FB_LowFreq,
FB_Max
};
/* These points are in AL coordinates! */
static const ALfloat Ambi3DPoints[8][3] = {
@@ -71,28 +173,35 @@ static const ALfloat Ambi3DPoints[8][3] = {
{ -0.577350269f, -0.577350269f, 0.577350269f },
{ 0.577350269f, -0.577350269f, 0.577350269f },
};
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
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 } },
{ { 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 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 {
ALuint Enabled; /* Bitfield of enabled channels. */
ALboolean Enabled[MAX_OUTPUT_CHANNELS];
union {
alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS];
alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS];
alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
} Matrix;
@@ -107,7 +216,7 @@ typedef struct BFormatDec {
struct {
BandSplitter XOver;
ALfloat Gains[NUM_BANDS];
ALfloat Gains[FB_Max];
} UpSampler[4];
ALsizei NumChannels;
@@ -116,20 +225,21 @@ typedef struct BFormatDec {
BFormatDec *bformatdec_alloc()
{
alcall_once(&bformatdec_inited, init_bformatdec);
return al_calloc(16, sizeof(BFormatDec));
}
void bformatdec_free(BFormatDec **dec)
void bformatdec_free(BFormatDec *dec)
{
if(dec && *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;
al_free(*dec);
*dec = NULL;
memset(dec, 0, sizeof(*dec));
al_free(dec);
}
}
@@ -138,7 +248,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 = N3D2N3DScale;
const ALfloat *coeff_scale = UnitScale;
bool periphonic;
ALfloat ratio;
ALsizei i;
@@ -153,9 +263,10 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
dec->SamplesHF = dec->Samples;
dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
dec->Enabled = 0;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
dec->Enabled[i] = AL_FALSE;
for(i = 0;i < conf->NumSpeakers;i++)
dec->Enabled |= 1 << chanmap[i];
dec->Enabled[chanmap[i]] = AL_TRUE;
if(conf->CoeffScale == ADS_SN3D)
coeff_scale = SN3D2N3DScale;
@@ -170,31 +281,31 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount
{
periphonic = true;
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;
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].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;
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
{
periphonic = false;
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;
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 < 3;i++)
{
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[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[HF_BAND] = 0.0f;
dec->UpSampler[3].Gains[LF_BAND] = 0.0f;
dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f;
dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f;
}
memset(&dec->Matrix, 0, sizeof(dec->Matrix));
@@ -261,8 +372,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<<l)))
dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
coeff_scale[l] * gain;
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
coeff_scale[l] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
{
@@ -272,8 +383,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<<l)))
dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
coeff_scale[l] * gain;
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
coeff_scale[l] * gain;
}
}
else
@@ -285,8 +396,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<<j)))
dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
coeff_scale[j] * gain;
dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
coeff_scale[j] * gain;
}
for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
{
@@ -295,8 +406,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<<j)))
dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
coeff_scale[j] * gain;
dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
coeff_scale[j] * gain;
}
}
}
@@ -317,15 +428,17 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
for(chan = 0;chan < OutChannels;chan++)
{
if(!(dec->Enabled&(1<<chan)))
if(!dec->Enabled[chan])
continue;
memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND],
dec->SamplesHF, dec->NumChannels, 0, SamplesToDo
MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq],
SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0,
SamplesToDo
);
MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND],
dec->SamplesLF, dec->NumChannels, 0, SamplesToDo
MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq],
SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0,
SamplesToDo
);
for(i = 0;i < SamplesToDo;i++)
@@ -336,12 +449,12 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
{
for(chan = 0;chan < OutChannels;chan++)
{
if(!(dec->Enabled&(1<<chan)))
if(!dec->Enabled[chan])
continue;
memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
dec->NumChannels, 0, SamplesToDo);
MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
dec->NumChannels, 0, SamplesToDo);
for(i = 0;i < SamplesToDo;i++)
OutBuffer[chan][i] += dec->ChannelMix[i];
@@ -370,13 +483,14 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B
* bands.
*/
bandsplit_process(&dec->UpSampler[i].XOver,
dec->Samples[HF_BAND], dec->Samples[LF_BAND],
dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq],
InSamples[i], SamplesToDo
);
/* Now write each band to the output. */
MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains,
dec->Samples, NUM_BANDS, 0, SamplesToDo
MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains,
SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0,
SamplesToDo
);
}
}
@@ -397,31 +511,28 @@ 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[NUM_BANDS][BUFFERSIZE];
alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE];
BandSplitter XOver[4];
ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS];
ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
} AmbiUpsampler;
AmbiUpsampler *ambiup_alloc()
{
alcall_once(&bformatdec_inited, init_bformatdec);
return al_calloc(16, sizeof(AmbiUpsampler));
}
void ambiup_free(struct AmbiUpsampler **ambiup)
void ambiup_free(struct AmbiUpsampler *ambiup)
{
if(ambiup)
{
al_free(*ambiup);
*ambiup = NULL;
}
al_free(ambiup);
}
void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale)
void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device)
{
ALfloat ratio;
ALsizei i;
size_t i;
ratio = 400.0f / (ALfloat)device->Frequency;
for(i = 0;i < 4;i++)
@@ -434,11 +545,11 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat
ALsizei j;
size_t k;
for(k = 0;k < COUNTOF(Ambi3DPoints);k++)
for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
{
ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
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
@@ -450,24 +561,32 @@ void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat
{
for(j = 0;j < device->Dry.NumChannels;j++)
{
ALdouble gain = 0.0;
ALfloat hfgain=0.0f, lfgain=0.0f;
for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
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;
{
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][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
ambiup->Gains[i][index][LF_BAND] = scale;
ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale);
ambiup->Gains[i][index][FB_LowFreq] = scale;
}
}
}
@@ -480,13 +599,14 @@ void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[
for(i = 0;i < 4;i++)
{
bandsplit_process(&ambiup->XOver[i],
ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND],
ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq],
InSamples[i], SamplesToDo
);
for(j = 0;j < OutChannels;j++)
MixRowSamples(OutBuffer[j], ambiup->Gains[i][j],
ambiup->Samples, NUM_BANDS, 0, SamplesToDo
MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j],
SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0,
SamplesToDo
);
}
}
+38 -20
View File
@@ -7,26 +7,18 @@
/* These are the necessary scales for first-order HF responses to play over
* higher-order 2D (non-periphonic) decoders.
*/
#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
#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_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
/* 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];
#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;
@@ -35,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. */
@@ -46,12 +38,38 @@ void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[B
/* Stand-alone first-order upsampler. Kept here because it shares some stuff
* with bformatdec. Assumes a periphonic (4-channel) input mix!
* with bformatdec.
*/
struct AmbiUpsampler *ambiup_alloc();
void ambiup_free(struct AmbiUpsampler **ambiup);
void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale);
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);
/* 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, 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 freq_mult);
void splitterap_clear(SplitterAllpass *splitter);
void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count);
#endif /* BFORMATDEC_H */
+5081
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -3,10 +3,6 @@
#include "alstring.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
@@ -42,7 +38,7 @@ struct FileMapping {
struct FileMapping MapFileToMem(const char *fname);
void UnmapFileMem(const struct FileMapping *mapping);
void GetProcBinary(al_string *path, al_string *fname);
al_string GetProcPath(void);
#ifdef HAVE_DYNLOAD
void *LoadLib(const char *name);
@@ -50,8 +46,12 @@ void CloseLib(void *handle);
void *GetSymbol(void *handle, const char *name);
#endif
#ifdef __cplusplus
} /* extern "C" */
#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 */
+16 -18
View File
@@ -3,8 +3,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)
@@ -27,16 +26,15 @@ 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 = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5,
MAX_PITCH * FRACTIONONE);
step = fastf2i(minf((ALdouble)srcRate / dstRate, MAX_PITCH)*FRACTIONONE + 0.5f);
converter->mIncrement = maxi(step, 1);
if(converter->mIncrement == FRACTIONONE)
converter->mResample = Resample_copy_C;
converter->mResample = Resample_copy32_C;
else
{
/* TODO: Allow other resamplers. */
BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12);
converter->mResample = SelectResampler(BSinc12Resampler);
BsincPrepare(converter->mIncrement, &converter->mState.bsinc);
converter->mResample = SelectResampler(BSincResampler);
}
END_MIXER_MODE();
@@ -207,8 +205,8 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe
return 0;
}
if(prepcount < MAX_RESAMPLE_PADDING*2 &&
MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes)
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;
@@ -216,7 +214,7 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe
DataSize64 = prepcount;
DataSize64 += srcframes;
DataSize64 -= MAX_RESAMPLE_PADDING*2;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
@@ -258,10 +256,10 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
converter->mSrcPrepCount = 0;
continue;
}
toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2);
toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES));
if(prepcount < MAX_RESAMPLE_PADDING*2 &&
MAX_RESAMPLE_PADDING*2 - prepcount >= toread)
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.
@@ -279,7 +277,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
DataSize64 = prepcount;
DataSize64 += toread;
DataSize64 -= MAX_RESAMPLE_PADDING*2;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
@@ -312,7 +310,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
sizeof(converter->Chan[chan].mPrevSamples));
else
{
size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd);
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,
@@ -321,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_RESAMPLE_PADDING, DataPosFrac, increment,
SrcData+MAX_PRE_SAMPLES, DataPosFrac, increment,
DstData, DstSize
);
@@ -333,8 +331,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
* fractional offset.
*/
DataPosFrac += increment*DstSize;
converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS),
MAX_RESAMPLE_PADDING*2);
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. */
+1 -1
View File
@@ -26,7 +26,7 @@ typedef struct SampleConverter {
alignas(16) ALfloat mDstSamples[BUFFERSIZE];
struct {
alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2];
alignas(16) ALfloat mPrevSamples[MAX_PRE_SAMPLES+MAX_POST_SAMPLES];
} Chan[];
} SampleConverter;
-15
View File
@@ -1,15 +0,0 @@
#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 */
-321
View File
@@ -1,321 +0,0 @@
/**
* 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 <math.h>
#include <stdlib.h>
#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;
/* Filter components derived from the envelope. */
struct {
ALfloat cos_w0;
ALfloat alpha;
} Env[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];
} Chans[MAX_EFFECT_CHANNELS];
/* Effects buffers */
alignas(16) ALfloat BufferOut[BUFFERSIZE];
} 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);
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. */
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;
memset(state->Env, 0, sizeof(state->Env));
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
{
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;
}
static ALvoid ALautowahState_update(ALautowahState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat ReleaseTime;
ALsizei i;
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));
/* 0-20dB Resonance Peak gain */
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;
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 ALautowahState_process(ALautowahState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
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;
ALsizei c, i;
env_delay = state->env_delay;
for(i = 0;i < SamplesToDo;i++)
{
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 = minf((bandwidth*env_delay + freq_min), 0.46f) * F_TAU;
state->Env[i].cos_w0 = cosf(w0);
state->Env[i].alpha = 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.
*/
ALfloat z1 = state->Chans[c].Filter.z1;
ALfloat z2 = state->Chans[c].Filter.z2;
for(i = 0;i < SamplesToDo;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];
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(state->BufferOut, NumChannels, SamplesOut, state->Chans[c].CurrentGains,
state->Chans[c].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 *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(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);
+116 -261
View File
@@ -24,40 +24,32 @@
#include <stdlib.h>
#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");
static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
enum WaveForm {
WF_Sinusoid,
WF_Triangle
enum ChorusWaveForm {
CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
};
typedef struct ALchorusState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat *SampleBuffer;
ALfloat *SampleBuffer[2];
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];
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum WaveForm waveform;
enum ChorusWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
@@ -65,7 +57,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 ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
@@ -78,51 +70,54 @@ static void ALchorusState_Construct(ALchorusState *state)
SET_VTABLE2(ALchorusState, ALeffectState, state);
state->BufferLength = 0;
state->SampleBuffer = NULL;
state->SampleBuffer[0] = NULL;
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_offset = 0;
state->lfo_range = 1;
state->waveform = WF_Triangle;
state->waveform = CWF_Triangle;
}
static ALvoid ALchorusState_Destruct(ALchorusState *state)
{
al_free(state->SampleBuffer);
state->SampleBuffer = NULL;
al_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)
{
const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY);
ALsizei maxlen;
ALsizei it;
maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u);
if(maxlen <= 0) return AL_FALSE;
maxlen = fastf2i(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1;
maxlen = NextPowerOf2(maxlen);
if(maxlen != state->BufferLength)
{
void *temp = al_calloc(16, maxlen * sizeof(ALfloat));
void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
if(!temp) return AL_FALSE;
al_free(state->SampleBuffer);
state->SampleBuffer = temp;
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = temp;
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
state->BufferLength = maxlen;
}
memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat));
memset(state->Gains, 0, sizeof(state->Gains));
for(it = 0;it < state->BufferLength;it++)
{
state->SampleBuffer[0][it] = 0.0f;
state->SampleBuffer[1][it] = 0.0f;
}
return AL_TRUE;
}
static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS;
const ALCdevice *device = Context->Device;
ALfloat frequency = (ALfloat)device->Frequency;
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat rate;
ALint phase;
@@ -130,61 +125,50 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Conte
switch(props->Chorus.Waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
state->waveform = WF_Triangle;
state->waveform = CWF_Triangle;
break;
case AL_CHORUS_WAVEFORM_SINUSOID:
state->waveform = WF_Sinusoid;
state->waveform = CWF_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(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f),
mindelay);
state->depth = minf(props->Chorus.Depth * state->delay,
(ALfloat)(state->delay - mindelay));
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);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = props->Chorus.Phase;
rate = props->Chorus.Rate;
if(!(rate > 0.0f))
{
state->lfo_offset = 0;
state->lfo_range = 1;
state->lfo_scale = 0.0f;
state->lfo_range = 1;
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 = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180)));
state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range*
lfo_range + 0.5f) % lfo_range;
state->lfo_range = lfo_range;
/* Calculate LFO coefficient */
state->lfo_range = fastf2i(frequency/rate + 0.5f);
switch(state->waveform)
{
case WF_Triangle:
case CWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
case WF_Sinusoid:
case CWF_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;
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));
}
}
@@ -215,68 +199,67 @@ static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsi
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
ALfloat *restrict leftbuf = state->SampleBuffer[0];
ALfloat *restrict rightbuf = state->SampleBuffer[1];
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];
alignas(16) ALfloat temps[2][256];
const ALsizei todo = mini(128, SamplesToDo-base);
ALfloat temps[128][2];
ALint moddelays[2][128];
if(state->waveform == WF_Sinusoid)
switch(state->waveform)
{
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);
case CWF_Triangle:
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:
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;
}
else /*if(state->waveform == WF_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);
}
state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range;
for(i = 0;i < todo;i++)
{
ALint delay;
ALfloat mu;
leftbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
leftbuf[offset&bufmask] += temps[i][0];
// Feed the buffer's input first (necessary for delays < 1).
delaybuf[offset&bufmask] = SamplesIn[0][base+i];
rightbuf[offset&bufmask] = SamplesIn[0][base+i];
temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
rightbuf[offset&bufmask] += temps[i][1];
// 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 of the taps.
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, SamplesToDo-base, base, todo);
for(c = 0;c < NumChannels;c++)
{
ALfloat gain = state->Gain[0][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
base += todo;
}
@@ -285,11 +268,11 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, c
}
typedef struct ChorusStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} ChorusStateFactory;
typedef struct ALchorusStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALchorusStateFactory;
static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory))
static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory))
{
ALchorusState *state;
@@ -299,14 +282,14 @@ static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(facto
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory);
EffectStateFactory *ChorusStateFactory_getFactory(void)
ALeffectStateFactory *ALchorusStateFactory_getFactory(void)
{
static ChorusStateFactory ChorusFactory = { { GET_VTABLE2(ChorusStateFactory, EffectStateFactory) } };
static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &ChorusFactory);
return STATIC_CAST(ALeffectStateFactory, &ChorusFactory);
}
@@ -317,22 +300,24 @@ 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,, "Invalid chorus waveform");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Waveform = val;
break;
case AL_CHORUS_PHASE:
if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Phase = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{ ALchorus_setParami(effect, context, param, vals[0]); }
{
ALchorus_setParami(effect, context, param, vals[0]);
}
void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
@@ -340,34 +325,36 @@ 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,, "Chorus rate out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Rate = val;
break;
case AL_CHORUS_DEPTH:
if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Depth = val;
break;
case AL_CHORUS_FEEDBACK:
if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Feedback = val;
break;
case AL_CHORUS_DELAY:
if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Chorus.Delay = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALchorus_setParamf(effect, context, param, vals[0]); }
{
ALchorus_setParamf(effect, context, param, vals[0]);
}
void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
@@ -383,11 +370,13 @@ void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum para
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{ ALchorus_getParami(effect, context, param, vals); }
{
ALchorus_getParami(effect, context, param, vals);
}
void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -410,146 +399,12 @@ void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALchorus_getParamf(effect, context, param, vals); }
{
ALchorus_getParamf(effect, context, param, vals);
}
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 FlangerStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} FlangerStateFactory;
ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory))
{
ALchorusState *state;
NEW_OBJ0(state, ALchorusState)();
if(!state) return NULL;
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory);
EffectStateFactory *FlangerStateFactory_getFactory(void)
{
static FlangerStateFactory FlangerFactory = { { GET_VTABLE2(FlangerStateFactory, EffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &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))
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,, "Flanger phase out of range");
props->Chorus.Phase = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param);
}
}
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))
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,, "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,, "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,, "Flanger delay out of range");
props->Chorus.Delay = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
}
}
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:
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); }
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:
alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
}
}
void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALflanger_getParamf(effect, context, param, vals); }
DEFINE_ALEFFECT_VTABLE(ALflanger);
+97 -86
View File
@@ -27,13 +27,6 @@
#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);
@@ -42,14 +35,14 @@ typedef struct ALcompressorState {
/* Effect parameters */
ALboolean Enabled;
ALfloat AttackMult;
ALfloat ReleaseMult;
ALfloat EnvFollower;
ALfloat AttackRate;
ALfloat ReleaseRate;
ALfloat GainCtrl;
} ALcompressorState;
static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
@@ -62,9 +55,9 @@ static void ALcompressorState_Construct(ALcompressorState *state)
SET_VTABLE2(ALcompressorState, ALeffectState, state);
state->Enabled = AL_TRUE;
state->AttackMult = 1.0f;
state->ReleaseMult = 1.0f;
state->EnvFollower = 1.0f;
state->AttackRate = 0.0f;
state->ReleaseRate = 0.0f;
state->GainCtrl = 1.0f;
}
static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
@@ -74,24 +67,17 @@ static ALvoid ALcompressorState_Destruct(ALcompressorState *state)
static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device)
{
/* 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;
const ALfloat attackTime = device->Frequency * 0.2f; /* 200ms Attack */
const ALfloat releaseTime = device->Frequency * 0.4f; /* 400ms Release */
/* 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);
state->AttackRate = 1.0f / attackTime;
state->ReleaseRate = 1.0f / releaseTime;
return AL_TRUE;
}
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALuint i;
state->Enabled = props->Compressor.OnOff;
@@ -99,7 +85,8 @@ 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++)
ComputePanGains(&device->FOAOut, IdentityMatrixf.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, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
@@ -109,52 +96,71 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
for(base = 0;base < SamplesToDo;)
{
ALfloat gains[256];
ALsizei td = mini(256, SamplesToDo-base);
ALfloat env = state->EnvFollower;
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];
}
/* Generate the per-sample gains from the signal envelope. */
if(state->Enabled)
{
for(i = 0;i < td;++i)
{
/* 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);
ALfloat gain = state->GainCtrl;
ALfloat output, amplitude;
/* Apply the reciprocal of the envelope to normalize the volume
* (compress the dynamic range).
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.
*/
gains[i] = 1.0f / env;
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;
}
state->GainCtrl = gain;
}
else
{
/* 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)
ALfloat gain = state->GainCtrl;
ALfloat output, amplitude;
for(i = 0;i < td;i++)
{
ALfloat amplitude = 1.0f;
if(amplitude > env)
env = minf(env*state->AttackMult, amplitude);
else if(amplitude < env)
env = maxf(env*state->ReleaseMult, amplitude);
/* 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);
gains[i] = 1.0f / env;
output = 1.0f / clampf(gain, 0.5f, 2.0f);
for(j = 0;j < 4;j++)
temps[i][j] *= output;
}
}
state->EnvFollower = env;
/* Now compress the signal amplitude to output. */
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
state->GainCtrl = gain;
}
/* Now mix to the output. */
for(j = 0;j < 4;j++)
{
for(k = 0;k < NumChannels;k++)
{
@@ -163,7 +169,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
continue;
for(i = 0;i < td;i++)
SamplesOut[k][base+i] += SamplesIn[j][base+i] * gains[i] * gain;
SamplesOut[k][base+i] += gain * temps[i][j];
}
}
@@ -172,11 +178,11 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei Sample
}
typedef struct CompressorStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} CompressorStateFactory;
typedef struct ALcompressorStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALcompressorStateFactory;
static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory))
static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
{
ALcompressorState *state;
@@ -186,13 +192,13 @@ static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUS
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
EffectStateFactory *CompressorStateFactory_getFactory(void)
ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
{
static CompressorStateFactory CompressorFactory = { { GET_VTABLE2(CompressorStateFactory, EffectStateFactory) } };
static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &CompressorFactory);
return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
}
@@ -203,21 +209,24 @@ 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,, "Compressor state out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Compressor.OnOff = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{ ALcompressor_setParami(effect, context, param, vals[0]); }
void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum 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); }
{
ALcompressor_setParami(effect, context, param, vals[0]);
}
void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{
ALcompressor_setParamf(effect, context, param, vals[0]);
}
void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
@@ -227,17 +236,19 @@ void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum
case AL_COMPRESSOR_ONOFF:
*val = props->Compressor.OnOff;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{ ALcompressor_getParami(effect, context, param, vals); }
void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum 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); }
{
ALcompressor_getParami(effect, context, param, vals);
}
void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{
ALcompressor_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALcompressor);
+62 -43
View File
@@ -23,22 +23,21 @@
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
#include "filters/defs.h"
typedef struct ALdedicatedState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
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 ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
@@ -47,8 +46,13 @@ 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)
@@ -56,44 +60,40 @@ static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device))
static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
{
ALsizei i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
state->CurrentGains[i] = 0.0f;
return AL_TRUE;
}
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat Gain;
ALsizei i;
ALuint i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
state->TargetGains[i] = 0.0f;
state->gains[i] = 0.0f;
Gain = slot->Params.Gain * props->Dedicated.Gain;
if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
Gain = Slot->Params.Gain * props->Dedicated.Gain;
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;
state->TargetGains[idx] = Gain;
state->gains[idx] = Gain;
}
}
else if(slot->Params.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
* 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;
state->TargetGains[idx] = Gain;
state->gains[idx] = Gain;
}
else
{
@@ -102,23 +102,34 @@ static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext
STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer;
STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels;
ComputePanGains(&device->Dry, coeffs, Gain, state->TargetGains);
ComputePanningGains(device->Dry, coeffs, Gain, state->gains);
}
}
}
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains,
state->TargetGains, SamplesToDo, 0, SamplesToDo);
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;
}
}
typedef struct DedicatedStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} DedicatedStateFactory;
typedef struct ALdedicatedStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALdedicatedStateFactory;
ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory))
ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory))
{
ALdedicatedState *state;
@@ -128,21 +139,23 @@ ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factor
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory);
EffectStateFactory *DedicatedStateFactory_getFactory(void)
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void)
{
static DedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(DedicatedStateFactory, EffectStateFactory) } };
static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &DedicatedFactory);
return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory);
}
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_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALdedicated_setParami(effect, context, param, vals[0]);
}
void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
@@ -150,21 +163,25 @@ 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,, "Dedicated gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Dedicated.Gain = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALdedicated_setParamf(effect, context, param, vals[0]); }
{
ALdedicated_setParamf(effect, context, param, vals[0]);
}
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_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALdedicated_getParami(effect, context, param, vals);
}
void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -175,10 +192,12 @@ void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALdedicated_getParamf(effect, context, param, vals); }
{
ALdedicated_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALdedicated);
+75 -64
View File
@@ -24,10 +24,10 @@
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
#include "filters/defs.h"
typedef struct ALdistortionState {
@@ -37,17 +37,15 @@ typedef struct ALdistortionState {
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
BiquadFilter lowpass;
BiquadFilter bandpass;
ALfilterState lowpass;
ALfilterState bandpass;
ALfloat attenuation;
ALfloat edge_coeff;
ALfloat Buffer[2][BUFFERSIZE];
} ALdistortionState;
static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
@@ -58,6 +56,9 @@ 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)
@@ -65,22 +66,21 @@ static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device))
static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
{
BiquadFilter_clear(&state->lowpass);
BiquadFilter_clear(&state->bandpass);
return AL_TRUE;
}
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat frequency = (ALfloat)device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat bandwidth;
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);
@@ -92,93 +92,98 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontex
/* Multiply sampling frequency by the amount of oversampling done during
* processing.
*/
BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f,
ALfilterState_setParams(&state->lowpass, ALfilterType_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);
BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f,
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain*props->Distortion.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)
{
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. 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;
/* 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;
}
/* 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.
*/
BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo);
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(i = 0;i < todo;i++)
for(it = 0;it < td*4;it++)
{
ALfloat smp = buffer[1][i];
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));
buffer[0][i] = smp;
buffer[0][it] = smp;
}
/* Third step, do bandpass filtering of distorted signal. */
BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo);
ALfilterState_process(&state->bandpass, buffer[1], buffer[0], td*4);
todo >>= 2;
for(k = 0;k < NumChannels;k++)
for(kt = 0;kt < NumChannels;kt++)
{
/* Fourth step, final, do attenuation and perform decimation,
* storing only one sample out of four.
* store only one sample out of 4.
*/
ALfloat gain = state->Gain[k];
ALfloat gain = state->Gain[kt] * state->attenuation;
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < todo;i++)
SamplesOut[k][base+i] += gain * buffer[1][i*4];
for(it = 0;it < td;it++)
SamplesOut[kt][base+it] += gain * buffer[1][it*4];
}
base += todo;
base += td;
}
}
typedef struct DistortionStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} DistortionStateFactory;
typedef struct ALdistortionStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALdistortionStateFactory;
static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory))
static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
{
ALdistortionState *state;
@@ -188,21 +193,23 @@ static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUS
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
EffectStateFactory *DistortionStateFactory_getFactory(void)
ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
{
static DistortionStateFactory DistortionFactory = { { GET_VTABLE2(DistortionStateFactory, EffectStateFactory) } };
static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &DistortionFactory);
return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
}
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_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALdistortion_setParami(effect, context, param, vals[0]);
}
void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
@@ -210,46 +217,49 @@ 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,, "Distortion edge out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.Edge = val;
break;
case AL_DISTORTION_GAIN:
if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.Gain = val;
break;
case AL_DISTORTION_LOWPASS_CUTOFF:
if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.LowpassCutoff = val;
break;
case AL_DISTORTION_EQCENTER:
if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.EQCenter = val;
break;
case AL_DISTORTION_EQBANDWIDTH:
if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Distortion.EQBandwidth = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x",
param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALdistortion_setParamf(effect, context, param, vals[0]); }
{
ALdistortion_setParamf(effect, context, param, vals[0]);
}
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_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALdistortion_getParami(effect, context, param, vals);
}
void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -276,11 +286,12 @@ void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x",
param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALdistortion_getParamf(effect, context, param, vals); }
{
ALdistortion_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALdistortion);
+95 -79
View File
@@ -28,7 +28,6 @@
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
#include "filters/defs.h"
typedef struct ALechoState {
@@ -43,21 +42,17 @@ typedef struct ALechoState {
ALsizei delay;
} Tap[2];
ALsizei Offset;
/* The panning gains for the two taps */
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
ALfloat Target[MAX_OUTPUT_CHANNELS];
} Gains[2];
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
ALfloat FeedGain;
BiquadFilter Filter;
ALfilterState Filter;
} ALechoState;
static ALvoid ALechoState_Destruct(ALechoState *state);
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALechoState)
@@ -76,7 +71,7 @@ static void ALechoState_Construct(ALechoState *state)
state->Tap[1].delay = 0;
state->Offset = 0;
BiquadFilter_clear(&state->Filter);
ALfilterState_clear(&state->Filter);
}
static ALvoid ALechoState_Destruct(ALechoState *state)
@@ -88,14 +83,13 @@ static ALvoid ALechoState_Destruct(ALechoState *state)
static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
{
ALsizei maxlen;
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 = 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;
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)
{
@@ -106,22 +100,20 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
state->SampleBuffer = temp;
state->BufferLength = maxlen;
}
memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat));
memset(state->Gains, 0, sizeof(state->Gains));
for(i = 0;i < state->BufferLength;i++)
state->SampleBuffer[i] = 0.0f;
return AL_TRUE;
}
static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALuint frequency = device->Frequency;
ALuint frequency = Device->Frequency;
ALfloat coeffs[MAX_AMBI_COEFFS];
ALfloat gainhf, lrpan, spread;
ALfloat gain, lrpan, spread;
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[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;
@@ -134,18 +126,20 @@ 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 */
BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf,
gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f)
);
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));
gain = Slot->Params.Gain;
/* First tap panning */
CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target);
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]);
/* Second tap panning */
CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs);
ComputePanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target);
ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]);
}
static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
@@ -153,59 +147,73 @@ static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const
const ALsizei mask = state->BufferLength-1;
const ALsizei tap1 = state->Tap[0].delay;
const ALsizei tap2 = state->Tap[1].delay;
ALfloat *restrict delaybuf = state->SampleBuffer;
ALsizei offset = state->Offset;
ALfloat z1, z2, in, out;
ALsizei base;
ALsizei c, i;
ALfloat x[2], y[2], in, out;
ALsizei base, k;
ALsizei i;
z1 = state->Filter.z1;
z2 = state->Filter.z2;
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;)
{
alignas(16) ALfloat temps[2][128];
ALfloat temps[128][2];
ALsizei td = mini(128, SamplesToDo-base);
for(i = 0;i < td;i++)
{
/* Feed the delay buffer's input first. */
delaybuf[offset&mask] = SamplesIn[0][i+base];
/* First tap */
temps[0][i] = delaybuf[(offset-tap1) & mask];
temps[i][0] = state->SampleBuffer[(offset-tap1) & mask];
/* Second tap */
temps[1][i] = delaybuf[(offset-tap2) & mask];
temps[i][1] = state->SampleBuffer[(offset-tap2) & mask];
/* Apply damping to the second tap, then add it to the buffer with
* feedback attenuation.
*/
in = temps[1][i];
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;
// Apply damping and feedback gain to the second tap, and mix in the
// new sample
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;
delaybuf[offset&mask] += out * state->FeedGain;
state->SampleBuffer[offset&mask] = out * state->FeedGain;
offset++;
}
for(c = 0;c < 2;c++)
MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current,
state->Gains[c].Target, SamplesToDo-base, base, td);
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[0][k];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][k];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][1] * gain;
}
}
base += td;
}
state->Filter.z1 = z1;
state->Filter.z2 = z2;
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;
}
typedef struct EchoStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} EchoStateFactory;
typedef struct ALechoStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALechoStateFactory;
ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory))
ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
{
ALechoState *state;
@@ -215,20 +223,22 @@ ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory))
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory);
EffectStateFactory *EchoStateFactory_getFactory(void)
ALeffectStateFactory *ALechoStateFactory_getFactory(void)
{
static EchoStateFactory EchoFactory = { { GET_VTABLE2(EchoStateFactory, EffectStateFactory) } };
static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &EchoFactory);
return STATIC_CAST(ALeffectStateFactory, &EchoFactory);
}
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_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALecho_setParami(effect, context, param, vals[0]);
}
void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
@@ -236,45 +246,49 @@ 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,, "Echo delay out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Delay = val;
break;
case AL_ECHO_LRDELAY:
if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.LRDelay = val;
break;
case AL_ECHO_DAMPING:
if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Damping = val;
break;
case AL_ECHO_FEEDBACK:
if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Feedback = val;
break;
case AL_ECHO_SPREAD:
if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Echo.Spread = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALecho_setParamf(effect, context, param, vals[0]); }
{
ALecho_setParamf(effect, context, param, vals[0]);
}
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_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALecho_getParami(effect, context, param, vals);
}
void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -301,10 +315,12 @@ void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param,
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALecho_getParamf(effect, context, param, vals); }
{
ALecho_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALecho);
+126 -101
View File
@@ -24,10 +24,10 @@
#include <stdlib.h>
#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 *
@@ -72,24 +72,24 @@
* 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);
struct {
/* Effect parameters */
BiquadFilter filter[4];
/* Effect gains for each channel */
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
/* Effect gains for each channel */
ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
} Chans[MAX_EFFECT_CHANNELS];
/* Effect parameters */
ALfilterState filter[4][MAX_EFFECT_CHANNELS];
ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
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 ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
@@ -98,8 +98,18 @@ 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)
@@ -107,100 +117,107 @@ static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device))
static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
{
ALsizei i, j;
for(i = 0; i < MAX_EFFECT_CHANNELS;i++)
{
for(j = 0;j < 4;j++)
BiquadFilter_clear(&state->Chans[i].filter[j]);
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
state->Chans[i].CurrentGains[j] = 0.0f;
}
return AL_TRUE;
}
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat frequency = (ALfloat)device->Frequency;
ALfloat gain, f0norm;
ALfloat gain, freq_mult;
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->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 = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */
f0norm = props->Equalizer.LowCutoff/frequency;
BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf,
gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f)
freq_mult = props->Equalizer.LowCutoff/frequency;
ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
gain = maxf(props->Equalizer.Mid1Gain, 0.0625f);
f0norm = props->Equalizer.Mid1Center/frequency;
BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(
f0norm, props->Equalizer.Mid1Width
)
);
gain = maxf(props->Equalizer.Mid2Gain, 0.0625f);
f0norm = props->Equalizer.Mid2Center/frequency;
BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking,
gain, f0norm, calc_rcpQ_from_bandwidth(
f0norm, props->Equalizer.Mid2Width
)
);
gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f);
f0norm = props->Equalizer.HighCutoff/frequency;
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++)
{
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]);
}
ALfilterState_copyParams(&state->filter[0][i], &state->filter[0][0]);
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);
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(
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,
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,
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
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)
{
ALfloat (*restrict temps)[BUFFERSIZE] = state->SampleBuffer;
ALsizei c;
ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer;
ALsizei it, kt, ft;
ALsizei base;
for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
for(base = 0;base < 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);
ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base);
MixSamples(temps[3], NumChannels, SamplesOut,
state->Chans[c].CurrentGains, state->Chans[c].TargetGains,
SamplesToDo, 0, SamplesToDo
);
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;
}
}
typedef struct EqualizerStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} EqualizerStateFactory;
typedef struct ALequalizerStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALequalizerStateFactory;
ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory))
ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory))
{
ALequalizerState *state;
@@ -210,20 +227,22 @@ ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factor
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory);
EffectStateFactory *EqualizerStateFactory_getFactory(void)
ALeffectStateFactory *ALequalizerStateFactory_getFactory(void)
{
static EqualizerStateFactory EqualizerFactory = { { GET_VTABLE2(EqualizerStateFactory, EffectStateFactory) } };
static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &EqualizerFactory);
return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory);
}
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_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{
ALequalizer_setParami(effect, context, param, vals[0]);
}
void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
{
ALeffectProps *props = &effect->Props;
@@ -231,75 +250,79 @@ 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,, "Equalizer low-band gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.LowGain = val;
break;
case AL_EQUALIZER_LOW_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.LowCutoff = val;
break;
case AL_EQUALIZER_MID1_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Gain = val;
break;
case AL_EQUALIZER_MID1_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Center = val;
break;
case AL_EQUALIZER_MID1_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid1Width = val;
break;
case AL_EQUALIZER_MID2_GAIN:
if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Gain = val;
break;
case AL_EQUALIZER_MID2_CENTER:
if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Center = val;
break;
case AL_EQUALIZER_MID2_WIDTH:
if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.Mid2Width = val;
break;
case AL_EQUALIZER_HIGH_GAIN:
if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.HighGain = val;
break;
case AL_EQUALIZER_HIGH_CUTOFF:
if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Equalizer.HighCutoff = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALequalizer_setParamf(effect, context, param, vals[0]); }
{
ALequalizer_setParamf(effect, context, param, vals[0]);
}
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_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{
ALequalizer_getParami(effect, context, param, vals);
}
void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -346,10 +369,12 @@ void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALequalizer_getParamf(effect, context, param, vals); }
{
ALequalizer_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALequalizer);
+408
View File
@@ -0,0 +1,408 @@
/**
* 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 <math.h>
#include <stdlib.h>
#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[2];
ALsizei BufferLength;
ALsizei offset;
ALsizei lfo_range;
ALfloat lfo_scale;
ALint lfo_disp;
/* Gains for left and right sides */
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* 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 ALCdevice *Device, 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[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));
}
static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
{
ALsizei maxlen;
ALsizei it;
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) * 2);
if(!temp) return AL_FALSE;
al_free(state->SampleBuffer[0]);
state->SampleBuffer[0] = temp;
state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
state->BufferLength = maxlen;
}
for(it = 0;it < state->BufferLength;it++)
{
state->SampleBuffer[0][it] = 0.0f;
state->SampleBuffer[1][it] = 0.0f;
}
return AL_TRUE;
}
static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
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;
}
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);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
phase = props->Flanger.Phase;
rate = props->Flanger.Rate;
if(!(rate > 0.0f))
{
state->lfo_scale = 0.0f;
state->lfo_range = 1;
state->lfo_disp = 0;
}
else
{
/* Calculate LFO coefficient */
state->lfo_range = fastf2i(frequency/rate + 0.5f);
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)
state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
else
state->lfo_disp = fastf2i(state->lfo_range * ((360+phase)/360.0f));
}
}
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)
{
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];
ALint moddelays[2][128];
switch(state->waveform)
{
case FWF_Triangle:
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:
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(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][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < todo;i++)
SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
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);
-329
View File
@@ -1,329 +0,0 @@
/**
* 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 <math.h>
#include <stdlib.h>
#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;
ALsizei PhaseStep;
ALsizei Phase;
ALdouble ld_sign;
/*Effects buffers*/
ALfloat InFIFO[HIL_SIZE];
ALcomplex OutFIFO[HIL_SIZE];
ALcomplex OutputAccum[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->PhaseStep = 0;
state->Phase = 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];
ALfloat step;
step = props->Fshifter.Frequency / (ALfloat)device->Frequency;
state->PhaseStep = fastf2i(minf(step, 0.5f) * FRACTIONONE);
switch(props->Fshifter.LeftDirection)
{
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->Phase = 0;
state->PhaseStep = 0;
break;
}
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
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)
{
static const ALcomplex complex_zero = { 0.0, 0.0 };
ALfloat *restrict BufferOut = state->BufferOut;
ALsizei j, k, base;
for(base = 0;base < SamplesToDo;)
{
ALsizei todo = mini(HIL_SIZE-state->count, SamplesToDo-base);
ASSUME(todo > 0);
/* Fill FIFO buffer with samples data */
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) continue;
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). */
complex_hilbert(state->Analytic, HIL_SIZE);
/* 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. */
for(k = 0;k < SamplesToDo;k++)
{
ALdouble phase = state->Phase * ((1.0/FRACTIONONE) * 2.0*M_PI);
BufferOut[k] = (ALfloat)(state->Outdata[k].Real*cos(phase) +
state->Outdata[k].Imag*sin(phase)*state->ld_sign);
state->Phase += state->PhaseStep;
state->Phase &= FRACTIONMASK;
}
/* 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 = 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.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.RightDirection = 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 = props->Fshifter.LeftDirection;
break;
case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
*val = props->Fshifter.RightDirection;
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 = 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);
+91 -87
View File
@@ -24,33 +24,28 @@
#include <stdlib.h>
#include "alMain.h"
#include "alFilter.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
#include "filters/defs.h"
#define MAX_UPDATE_SAMPLES 128
typedef struct ALmodulatorState {
DERIVE_FROM_TYPE(ALeffectState);
void (*GetSamples)(ALfloat*, ALsizei, const ALsizei, ALsizei);
void (*Process)(ALfloat*, const ALfloat*, ALsizei, const ALsizei, ALsizei);
ALsizei index;
ALsizei step;
struct {
BiquadFilter Filter;
ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
} Chans[MAX_EFFECT_CHANNELS];
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 ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
@@ -63,52 +58,51 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
static inline ALfloat Sin(ALsizei index)
{
return sinf((ALfloat)index * (F_TAU / WAVEFORM_FRACONE));
return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
}
static inline ALfloat Saw(ALsizei index)
{
return (ALfloat)index*(2.0f/WAVEFORM_FRACONE) - 1.0f;
return (ALfloat)index / WAVEFORM_FRACONE;
}
static inline ALfloat Square(ALsizei index)
{
return (ALfloat)(((index>>(WAVEFORM_FRACBITS-2))&2) - 1);
}
static inline ALfloat One(ALsizei UNUSED(index))
{
return 1.0f;
return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
}
#define DECL_TEMPLATE(func) \
static void Modulate##func(ALfloat *restrict dst, ALsizei index, \
const ALsizei step, ALsizei todo) \
static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\
ALsizei index, const ALsizei step, ALsizei todo) \
{ \
ALsizei i; \
for(i = 0;i < todo;i++) \
{ \
index += step; \
index &= WAVEFORM_FRACMASK; \
dst[i] = func(index); \
dst[i] = src[i] * func(index); \
} \
}
DECL_TEMPLATE(Sin)
DECL_TEMPLATE(Saw)
DECL_TEMPLATE(Square)
DECL_TEMPLATE(One)
#undef DECL_TEMPLATE
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)
@@ -116,89 +110,91 @@ static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device))
static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
{
ALsizei i, j;
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;
}
return AL_TRUE;
}
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
{
const ALCdevice *device = context->Device;
ALfloat f0norm;
ALfloat cw, a;
ALsizei i;
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;
if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->Process = ModulateSin;
else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
state->GetSamples = ModulateSaw;
state->Process = ModulateSaw;
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
state->GetSamples = ModulateSquare;
state->Process = ModulateSquare;
f0norm = props->Modulator.HighPassCutoff / (ALfloat)device->Frequency;
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));
for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter);
state->step = fastf2i(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 * props->Modulator.HighPassCutoff / Device->Frequency);
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.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++)
ComputePanGains(&device->FOAOut, IdentityMatrixf.m[i], slot->Params.Gain,
state->Chans[i].TargetGains);
{
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;
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]);
}
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
const ALsizei step = state->step;
ALsizei index = state->index;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
alignas(16) ALfloat modsamples[MAX_UPDATE_SAMPLES];
ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base);
ALsizei c, i;
ALfloat temps[2][128];
ALsizei td = mini(128, SamplesToDo-base);
ALsizei i, j, k;
state->GetSamples(modsamples, state->index, step, td);
state->index += (step*td) & WAVEFORM_FRACMASK;
state->index &= WAVEFORM_FRACMASK;
for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
{
alignas(16) ALfloat temps[MAX_UPDATE_SAMPLES];
ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td);
state->Process(temps[1], temps[0], index, step, td);
BiquadFilter_process(&state->Chans[c].Filter, temps, &SamplesIn[c][base], td);
for(i = 0;i < td;i++)
temps[i] *= modsamples[i];
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[j][k];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
MixSamples(temps, NumChannels, SamplesOut, state->Chans[c].CurrentGains,
state->Chans[c].TargetGains, SamplesToDo-base, base, td);
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;
}
typedef struct ModulatorStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} ModulatorStateFactory;
typedef struct ALmodulatorStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALmodulatorStateFactory;
static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory))
static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory))
{
ALmodulatorState *state;
@@ -208,13 +204,13 @@ static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED
return STATIC_CAST(ALeffectState, state);
}
DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory);
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory);
EffectStateFactory *ModulatorStateFactory_getFactory(void)
ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void)
{
static ModulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ModulatorStateFactory, EffectStateFactory) } };
static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &ModulatorFactory);
return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory);
}
@@ -225,22 +221,24 @@ 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,, "Modulator frequency out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.Frequency = val;
break;
case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.HighPassCutoff = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALmodulator_setParamf(effect, context, param, vals[0]); }
{
ALmodulator_setParamf(effect, context, param, vals[0]);
}
void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
{
ALeffectProps *props = &effect->Props;
@@ -253,16 +251,18 @@ 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,, "Invalid modulator waveform");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
props->Modulator.Waveform = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
{ ALmodulator_setParami(effect, context, param, vals[0]); }
{
ALmodulator_setParami(effect, context, param, vals[0]);
}
void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
{
@@ -280,11 +280,13 @@ void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
{ ALmodulator_getParami(effect, context, param, vals); }
{
ALmodulator_getParami(effect, context, param, vals);
}
void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
{
const ALeffectProps *props = &effect->Props;
@@ -298,10 +300,12 @@ void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALmodulator_getParamf(effect, context, param, vals); }
{
ALmodulator_getParamf(effect, context, param, vals);
}
DEFINE_ALEFFECT_VTABLE(ALmodulator);
+37 -37
View File
@@ -16,8 +16,8 @@ typedef struct 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 ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei mumChannels);
static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
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);
@@ -56,7 +56,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 ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
{
}
@@ -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))
{
}
@@ -85,12 +85,12 @@ static void ALnullState_Delete(void *ptr)
}
typedef struct NullStateFactory {
DERIVE_FROM_TYPE(EffectStateFactory);
} NullStateFactory;
typedef struct ALnullStateFactory {
DERIVE_FROM_TYPE(ALeffectStateFactory);
} ALnullStateFactory;
/* Creates ALeffectState objects of the appropriate type. */
ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory))
ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
{
ALnullState *state;
@@ -100,79 +100,79 @@ ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory))
return STATIC_CAST(ALeffectState, state);
}
/* Define the EffectStateFactory vtable for this type. */
DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory);
/* Define the ALeffectStateFactory vtable for this type. */
DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory);
EffectStateFactory *NullStateFactory_getFactory(void)
ALeffectStateFactory *ALnullStateFactory_getFactory(void)
{
static NullStateFactory NullFactory = { { GET_VTABLE2(NullStateFactory, EffectStateFactory) } };
return STATIC_CAST(EffectStateFactory, &NullFactory);
static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } };
return STATIC_CAST(ALeffectStateFactory, &NullFactory);
}
void ALnull_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
{
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamiv(ALeffect *UNUSED(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, "Invalid null effect integer-vector property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamf(ALeffect *UNUSED(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, "Invalid null effect float property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_setParamfv(ALeffect *UNUSED(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, "Invalid null effect float-vector property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParami(const ALeffect *UNUSED(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, "Invalid null effect integer property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamiv(const ALeffect *UNUSED(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, "Invalid null effect integer-vector property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamf(const ALeffect *UNUSED(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, "Invalid null effect float property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
void ALnull_getParamfv(const ALeffect *UNUSED(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, "Invalid null effect float-vector property 0x%04x", param);
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
-441
View File
@@ -1,441 +0,0 @@
/**
* 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 <math.h>
#include <stdlib.h>
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
#include "alu.h"
#include "filters/defs.h"
#include "alcomplex.h"
#define STFT_SIZE 1024
#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 ALphasor {
ALdouble Amplitude;
ALdouble Phase;
} ALphasor;
typedef struct ALFrequencyDomain {
ALdouble Amplitude;
ALdouble Frequency;
} ALfrequencyDomain;
typedef struct ALpshifterState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect parameters */
ALsizei count;
ALsizei PitchShiftI;
ALfloat PitchShift;
ALfloat FreqPerBin;
/*Effects buffers*/
ALfloat InFIFO[STFT_SIZE];
ALfloat OutFIFO[STFT_STEP];
ALdouble LastPhase[STFT_HALF_SIZE+1];
ALdouble SumPhase[STFT_HALF_SIZE+1];
ALdouble OutputAccum[STFT_SIZE];
ALcomplex FFTbuffer[STFT_SIZE];
ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1];
ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1];
alignas(16) ALfloat BufferOut[BUFFERSIZE];
/* Effect gains for each output channel */
ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
} 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);
/* Define a Hann window, used to filter the STFT input and output. */
alignas(16) static ALdouble HannWindow[STFT_SIZE];
static void InitHannWindow(void)
{
ALsizei i;
/* 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 = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1));
HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val;
}
}
static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT;
static inline ALint double2int(ALdouble d)
{
#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&I64(0xfffffffffffff)) | I64(0x10000000000000);
if(LIKELY(shift < 0))
return (ALint)(mant >> -shift) * sign;
return (ALint)(mant << shift) * sign;
#else
return (ALint)d;
#endif
}
/* Converts ALcomplex to ALphasor */
static inline ALphasor rect2polar(ALcomplex number)
{
ALphasor polar;
polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag);
polar.Phase = atan2(number.Imag, number.Real);
return polar;
}
/* Converts ALphasor to ALcomplex */
static inline ALcomplex polar2rect(ALphasor number)
{
ALcomplex cartesian;
cartesian.Real = number.Amplitude * cos(number.Phase);
cartesian.Imag = number.Amplitude * sin(number.Phase);
return cartesian;
}
static void ALpshifterState_Construct(ALpshifterState *state)
{
ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
SET_VTABLE2(ALpshifterState, ALeffectState, state);
alcall_once(&HannInitOnce, InitHannWindow);
}
static ALvoid ALpshifterState_Destruct(ALpshifterState *state)
{
ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
}
static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device)
{
/* (Re-)initializing parameters and clear the buffers. */
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));
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));
memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer));
memset(state->CurrentGains, 0, sizeof(state->CurrentGains));
memset(state->TargetGains, 0, sizeof(state->TargetGains));
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];
float pitch;
pitch = powf(2.0f,
(ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f
);
state->PitchShiftI = fastf2i(pitch*FRACTIONONE);
state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE);
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
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)
{
/* Pitch shifter engine based on the work of Stephan Bernsee.
* http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
*/
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;
for(i = 0;i < SamplesToDo;)
{
do {
/* Fill FIFO buffer with samples data */
state->InFIFO[count] = SamplesIn[0][i];
bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY];
count++;
} while(++i < SamplesToDo && count < STFT_SIZE);
/* Check whether FIFO buffer is filled */
if(count < STFT_SIZE) break;
count = FIFO_LATENCY;
/* Real signal windowing and store in FFTbuffer */
for(k = 0;k < STFT_SIZE;k++)
{
state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k];
state->FFTbuffer[k].Imag = 0.0;
}
/* ANALYSIS */
/* Apply FFT to FFTbuffer data */
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.
*/
for(k = 0;k < STFT_HALF_SIZE+1;k++)
{
ALphasor component;
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]) - k*expected;
/* Map delta phase into +/- Pi interval */
qpd = double2int(tmp / M_PI);
tmp -= M_PI * (qpd + (qpd%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.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;
}
/* PROCESSING */
/* pitch shifting */
for(k = 0;k < STFT_HALF_SIZE+1;k++)
{
state->Syntesis_buffer[k].Amplitude = 0.0;
state->Syntesis_buffer[k].Frequency = 0.0;
}
for(k = 0;k < STFT_HALF_SIZE+1;k++)
{
j = (k*state->PitchShiftI) >> FRACTIONBITS;
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 *
state->PitchShift;
}
/* SYNTHESIS */
/* Synthesis the processing data */
for(k = 0;k < STFT_HALF_SIZE+1;k++)
{
ALphasor component;
ALdouble tmp;
/* Compute bin deviation from scaled freq */
tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k;
/* Calculate actual delta phase and accumulate it to get bin phase */
state->SumPhase[k] += (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 */
for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++)
{
state->FFTbuffer[k].Real = 0.0;
state->FFTbuffer[k].Imag = 0.0;
}
/* Apply iFFT to buffer data */
complex_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.5 * STFT_HALF_SIZE * OVERSAMP);
/* Shift accumulator, input & output FIFO */
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.0;
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,
maxi(SamplesToDo, 512), 0, SamplesToDo);
}
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);
+1253 -936
View File
File diff suppressed because it is too large Load Diff
-112
View File
@@ -1,112 +0,0 @@
#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 BiquadType {
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
BiquadType_HighShelf,
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
BiquadType_LowShelf,
/** Peaking filter, specifying a gain and reference frequency. */
BiquadType_Peaking,
/** Low-pass cut-off filter, specifying a cut-off frequency. */
BiquadType_LowPass,
/** High-pass cut-off filter, specifying a cut-off frequency. */
BiquadType_HighPass,
/** Band-pass filter, specifying a center frequency. */
BiquadType_BandPass,
} BiquadType;
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). */
} BiquadFilter;
/* Currently only a C-based filter process method is implemented. */
#define BiquadFilter_process BiquadFilter_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 BiquadFilter_clear(BiquadFilter *filter)
{
filter->z1 = 0.0f;
filter->z2 = 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 BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ);
inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src)
{
dst->b0 = src->b0;
dst->b1 = src->b1;
dst->b2 = src->b2;
dst->a1 = src->a1;
dst->a2 = src->a2;
}
void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples)
{
if(LIKELY(numsamples >= 2))
{
filter->z1 = 0.0f;
filter->z2 = 0.0f;
}
else if(numsamples == 1)
{
filter->z1 = filter->z2;
filter->z2 = 0.0f;
}
}
#endif /* ALC_FILTER_H */
-129
View File
@@ -1,129 +0,0 @@
#include "config.h"
#include "AL/alc.h"
#include "AL/al.h"
#include "alMain.h"
#include "defs.h"
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 BiquadFilter_setParams(BiquadFilter *filter, BiquadType 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 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 );
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 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 );
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 BiquadType_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 BiquadType_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 BiquadType_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 BiquadType_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 BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples)
{
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[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;
}
-49
View File
@@ -1,49 +0,0 @@
#ifndef FILTER_NFC_H
#define FILTER_NFC_H
struct NfcFilter1 {
float base_gain, gain;
float b1, a1;
float z[1];
};
struct NfcFilter2 {
float base_gain, gain;
float b1, b2, a1, a2;
float z[2];
};
struct NfcFilter3 {
float base_gain, gain;
float b1, b2, b3, a1, a2, a3;
float z[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 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 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 NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
#endif /* FILTER_NFC_H */
-109
View File
@@ -1,109 +0,0 @@
#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;
ASSUME(count > 0);
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. */
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;
}
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, in, out;
ALfloat z1;
ALsizei i;
ASSUME(count > 0);
coeff = splitter->coeff;
z1 = splitter->z1;
for(i = 0;i < count;i++)
{
in = samples[i];
out = in*coeff + z1;
z1 = in - out*coeff;
samples[i] = out;
}
splitter->z1 = z1;
}
-40
View File
@@ -1,40 +0,0 @@
#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 */
-34
View File
@@ -1,34 +0,0 @@
#ifndef FPU_MODES_H
#define FPU_MODES_H
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
typedef struct FPUCtl {
#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);
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 */
+193 -217
View File
@@ -39,9 +39,6 @@
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_PROC_PIDPATH
#include <libproc.h>
#endif
#ifdef __FreeBSD__
#include <sys/types.h>
@@ -69,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_WASAPI
#ifdef HAVE_MMDEVAPI
#include <wtypes.h>
#include <devpropdef.h>
#include <propkeydef.h>
@@ -111,8 +108,6 @@ 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"
@@ -123,50 +118,73 @@ 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);
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);
#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
#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, &regs[0], &regs[1], &regs[2], &regs[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
ALuint CPUCapFlags = 0;
int CPUCapFlags = 0;
void FillCPUCaps(int capfilter)
void FillCPUCaps(ALuint capfilter)
{
int caps = 0;
ALuint 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?). */
#ifdef CAN_GET_CPUID
#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64))
union {
reg_type regs[4];
char str[sizeof(reg_type[4])];
} cpuinf[3] = {{ { 0, 0, 0, 0 } }};
unsigned int regs[4];
char str[sizeof(unsigned int[4])];
} cpuinf[3];
get_cpuid(0, cpuinf[0].regs);
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))
union {
int regs[4];
char str[sizeof(int[4])];
} cpuinf[3];
(__cpuid)(cpuinf[0].regs, 0);
if(cpuinf[0].regs[0] == 0)
ERR("Failed to get CPUID\n");
else
@@ -174,7 +192,7 @@ void FillCPUCaps(int capfilter)
unsigned int maxfunc = cpuinf[0].regs[0];
unsigned int maxextfunc;
get_cpuid(0x80000000, cpuinf[0].regs);
(__cpuid)(cpuinf[0].regs, 0x80000000);
maxextfunc = cpuinf[0].regs[0];
TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
@@ -182,23 +200,29 @@ 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)
{
get_cpuid(0x80000002, cpuinf[0].regs);
get_cpuid(0x80000003, cpuinf[1].regs);
get_cpuid(0x80000004, cpuinf[2].regs);
(__cpuid)(cpuinf[0].regs, 0x80000002);
(__cpuid)(cpuinf[1].regs, 0x80000003);
(__cpuid)(cpuinf[2].regs, 0x80000004);
TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
}
if(maxfunc >= 1)
{
get_cpuid(1, cpuinf[0].regs);
(__cpuid)(cpuinf[0].regs, 1);
if((cpuinf[0].regs[3]&(1<<25)))
{
caps |= CPU_CAP_SSE;
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;
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;
}
}
}
}
}
#else
@@ -223,32 +247,22 @@ 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;
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;
len = strlen(buf);
while(len > 0 && isspace(buf[len-1]))
buf[--len] = 0;
if(!alstr_empty(features))
{
const char *str = alstr_get_cstr(features);
while(isspace(str[0])) ++str;
TRACE("Got features string:%s\n", buf+10);
TRACE("Got features string:%s\n", str);
str = buf;
while((str=strstr(str, "neon")) != NULL)
{
if(isspace(*(str-1)) && (str[4] == 0 || isspace(str[4])))
@@ -256,11 +270,13 @@ void FillCPUCaps(int capfilter)
caps |= CPU_CAP_NEON;
break;
}
++str;
str++;
}
break;
}
alstr_reset(&features);
fclose(file);
file = NULL;
}
#endif
@@ -278,44 +294,81 @@ void FillCPUCaps(int capfilter)
void SetMixerFPUMode(FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fegetenv(STATIC_CAST(fenv_t, ctl));
#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))
{
__asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
unsigned int sseState = ctl->sse_state;
int sseState = ctl->sse_state;
sseState |= 0x6000; /* set round-to-zero */
sseState |= 0x8000; /* set flush-to-zero */
if((CPUCapFlags&CPU_CAP_SSE2))
sseState |= 0x0040; /* set denormals-are-zero */
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState));
}
#endif
#elif defined(HAVE___CONTROL87_2)
__control87_2(0, 0, &ctl->state, &ctl->sse_state);
_control87(_DN_FLUSH, _MCW_DN);
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
#elif defined(HAVE__CONTROLFP)
ctl->state = _controlfp(0, 0);
_controlfp(_DN_FLUSH, _MCW_DN);
(void)_controlfp(_RC_CHOP, _MCW_RC);
#endif
}
void RestoreFPUMode(const FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fesetenv(STATIC_CAST(fenv_t, ctl));
#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_DN, &mode, NULL);
__control87_2(ctl->sse_state, _MCW_DN, NULL, &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
#elif defined(HAVE__CONTROLFP)
_controlfp(ctl->state, _MCW_DN);
_controlfp(ctl->state, _MCW_RC);
#endif
}
@@ -339,8 +392,9 @@ static WCHAR *strrchrW(WCHAR *str, WCHAR ch)
return ret;
}
void GetProcBinary(al_string *path, al_string *fname)
al_string GetProcPath(void)
{
al_string ret = AL_STRING_INIT_STATIC();
WCHAR *pathname, *sep;
DWORD pathlen;
DWORD len;
@@ -357,34 +411,23 @@ void GetProcBinary(al_string *path, al_string *fname)
{
free(pathname);
ERR("Failed to get process name: error %lu\n", GetLastError());
return;
return ret;
}
pathname[len] = 0;
if((sep=strrchrW(pathname, '\\')) != NULL)
if((sep = strrchrW(pathname, '\\')))
{
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
{
if(path) alstr_clear(path);
if(fname) alstr_copy_wcstr(fname, pathname);
WCHAR *sep2 = strrchrW(pathname, '/');
if(sep2) *sep2 = 0;
else *sep = 0;
}
else if((sep = strrchrW(pathname, '/')))
*sep = 0;
alstr_copy_wcstr(&ret, pathname);
free(pathname);
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));
TRACE("Got: %s\n", alstr_get_cstr(ret));
return ret;
}
@@ -591,7 +634,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[MAX_PATH];
WCHAR buffer[PATH_MAX];
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
{
alstr_copy_wcstr(&path, buffer);
@@ -678,103 +721,64 @@ void UnmapFileMem(const struct FileMapping *mapping)
#else
void GetProcBinary(al_string *path, al_string *fname)
al_string GetProcPath(void)
{
char *pathname = NULL;
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 };
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, 4, (void*)pathname, &pathlen, NULL, 0);
pathname[pathlen] = 0;
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;
}
#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);
}
pathname = malloc(pathlen + 1);
sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0);
pathname[pathlen] = 0;
#else
const char *fname;
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);
}
#endif
if(!pathname)
{
const char *selfname;
ssize_t len;
pathlen = 256;
while(len > 0 && (size_t)len == pathlen)
{
free(pathname);
pathlen <<= 1;
pathname = malloc(pathlen);
selfname = "/proc/self/exe";
len = readlink(selfname, pathname, pathlen);
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);
}
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;
len = readlink(fname, pathname, pathlen);
}
if(len <= 0)
{
free(pathname);
WARN("Failed to readlink %s: %s\n", fname, strerror(errno));
return ret;
}
char *sep = strrchr(pathname, '/');
pathname[len] = 0;
#endif
sep = strrchr(pathname, '/');
if(sep)
{
if(path) alstr_copy_range(path, pathname, sep);
if(fname) alstr_copy_cstr(fname, sep+1);
}
alstr_copy_range(&ret, pathname, sep);
else
{
if(path) alstr_clear(path);
if(fname) alstr_copy_cstr(fname, pathname);
}
alstr_copy_cstr(&ret, pathname);
free(pathname);
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));
TRACE("Got: %s\n", alstr_get_cstr(ret));
return ret;
}
@@ -877,32 +881,15 @@ 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
{
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;
}
}
DirectorySearch(".", ext, &results);
// Search local data dir
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
@@ -1105,8 +1092,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+1, len+2);
VECTOR_BACK(*str) = c;
VECTOR_RESIZE(*str, len, len+2);
VECTOR_PUSH_BACK(*str, c);
VECTOR_ELEM(*str, len+1) = 0;
}
@@ -1164,17 +1151,6 @@ 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;
+61 -372
View File
@@ -28,9 +28,8 @@
#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"
@@ -41,20 +40,12 @@
#define MAX_IR_SIZE (512)
#define MOD_IR_SIZE (8)
#define MIN_FD_COUNT (1)
#define MAX_FD_COUNT (16)
#define MIN_FD_DISTANCE (50)
#define MAX_FD_DISTANCE (2500)
#define MIN_EV_COUNT (5)
#define MAX_EV_COUNT (128)
#define MIN_AZ_COUNT (1)
#define MAX_AZ_COUNT (128)
#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1)
struct HrtfEntry {
struct HrtfEntry *next;
struct Hrtf *handle;
@@ -63,7 +54,6 @@ struct HrtfEntry {
static const ALchar magicMarker00[8] = "MinPHR00";
static const ALchar magicMarker01[8] = "MinPHR01";
static const ALchar magicMarker02[8] = "MinPHR02";
/* First value for pass-through coefficients (remaining are 0), used for omni-
* directional sounds. */
@@ -74,36 +64,37 @@ 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).
* 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, ALfloat *mu)
{
ALsizei idx;
ev = (F_PI_2+ev) * (evcount-1) / F_PI;
idx = float2int(ev);
idx = mini(fastf2i(ev), evcount-1);
*mu = ev - idx;
return mini(idx, evcount-1);
return idx;
}
/* Calculate the azimuth index given the polar azimuth in radians. This will
* return an index between 0 and (azcount - 1).
* return an index between 0 and (azcount - 1). Assumes the FPU is in round-to-
* zero mode.
*/
static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu)
{
ALsizei idx;
az = (F_TAU+az) * azcount / F_TAU;
idx = float2int(az);
*mu = az - idx;
return idx % azcount;
idx = fastf2i(az) % azcount;
*mu = az - floorf(az);
return idx;
}
/* Calculates static HRIR coefficients and delays for the given polar elevation
* and azimuth in radians. The coefficients are normalized.
*/
void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread,
ALfloat (*restrict coeffs)[2], ALsizei *delays)
void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays)
{
ALsizei evidx, azidx, idx[4];
ALsizei evoffset;
@@ -158,11 +149,11 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth,
/* 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]
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]
Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f
);
/* Calculate the sample offsets for the HRIR indices. */
@@ -171,8 +162,6 @@ 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);
coeffs[0][1] = PassthruCoeff * (1.0f-dirfact);
@@ -183,17 +172,16 @@ void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth,
}
for(c = 0;c < 4;c++)
{
const ALfloat (*restrict srccoeffs)[2] = ASSUME_ALIGNED(Hrtf->coeffs+idx[c], 16);
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] += srccoeffs[i][0] * blend[c];
coeffs[i][1] += srccoeffs[i][1] * blend[c];
coeffs[i][0] += Hrtf->coeffs[idx[c]+i][0] * blend[c];
coeffs[i][1] += Hrtf->coeffs[idx[c]+i][1] * blend[c];
}
}
}
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)
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
@@ -201,16 +189,12 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N
*/
#define NUM_BANDS 2
BandSplitter splitter;
ALdouble (*tmpres)[HRIR_LENGTH][2];
ALsizei *restrict idx;
ALsizei idx[HRTF_AMBI_MAX_CHANNELS];
ALsizei min_delay = HRTF_HISTORY_LENGTH;
ALsizei max_delay = 0;
ALfloat temps[3][HRIR_LENGTH];
ALsizei max_length;
ALsizei max_length = 0;
ALsizei i, c, b;
idx = al_calloc(DEF_ALIGN, AmbiCount*sizeof(*idx));
for(c = 0;c < AmbiCount;c++)
{
ALuint evidx, azidx;
@@ -218,24 +202,23 @@ void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei N
ALuint azcount;
/* Calculate elevation index. */
evidx = (ALsizei)((F_PI_2+AmbiPoints[c].Elev) * (Hrtf->evCount-1) / F_PI + 0.5f);
evidx = clampi(evidx, 0, Hrtf->evCount-1);
evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) *
(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 = (ALsizei)((F_TAU+AmbiPoints[c].Azim) * azcount / F_TAU + 0.5f) % azcount;
azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) *
azcount/F_TAU + 0.5f) % azcount;
/* 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]));
max_delay = maxi(max_delay, maxi(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++)
@@ -244,17 +227,20 @@ 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)
{
for(i = 0;i < NumChannels;++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)
{
tmpres[i][lidx++][0] += fir[j][0] * mult;
tmpres[i][ridx++][1] += fir[j][1] * mult;
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++;
}
}
@@ -270,14 +256,12 @@ 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)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)
tmpres[i][lidx++][0] += temps[b][j++] * mult;
state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][b][i];
}
}
@@ -290,58 +274,29 @@ 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)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)
tmpres[i][ridx++][1] += temps[b][j++] * mult;
state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][b][i];
}
}
}
}
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;
al_free(idx);
idx = NULL;
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;
max_length = RoundUp(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;
TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
return max_length;
#undef NUM_BANDS
}
static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize,
ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount,
const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2],
const char *filename)
static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount,
const ALubyte *azCount, const ALushort *evOffset,
const ALfloat (*coeffs)[2], const ALubyte (*delays)[2],
const char *filename)
{
struct Hrtf *Hrtf;
size_t total;
@@ -370,26 +325,23 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize,
InitRef(&Hrtf->ref, 0);
Hrtf->sampleRate = rate;
Hrtf->irSize = irSize;
Hrtf->distance = distance;
Hrtf->evCount = evCount;
/* Set up pointers to storage following the main HRTF struct. */
_azCount = (ALubyte*)(base + offset);
_azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount;
offset += sizeof(_azCount[0])*evCount;
offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */
_evOffset = (ALushort*)(base + offset);
_evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset;
offset += sizeof(_evOffset[0])*evCount;
offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */
_coeffs = (ALfloat(*)[2])(base + offset);
_coeffs = (ALfloat(*)[2])(base + offset); Hrtf->coeffs = _coeffs;
offset += sizeof(_coeffs[0])*irSize*irCount;
_delays = (ALubyte(*)[2])(base + offset);
_delays = (ALubyte(*)[2])(base + offset); Hrtf->delays = _delays;
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];
@@ -404,11 +356,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize,
_delays[i][1] = delays[i][1];
}
/* Finally, assign the storage pointers. */
Hrtf->azCount = _azCount;
Hrtf->evOffset = _evOffset;
Hrtf->coeffs = _coeffs;
Hrtf->delays = _delays;
assert(offset == total);
}
return Hrtf;
@@ -435,16 +383,9 @@ static ALushort GetLE_ALushort(const ALubyte **data, size_t *len)
return ret;
}
static ALint GetLE_ALint24(const ALubyte **data, size_t *len)
static ALint GetLE_ALuint(const ALubyte **data, size_t *len)
{
ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16);
*data += 3; *len -= 3;
return (ret^0x800000) - 0x800000;
}
static ALuint GetLE_ALuint(const ALubyte **data, size_t *len)
{
ALuint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24);
ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24);
*data += 4; *len -= 4;
return ret;
}
@@ -458,6 +399,7 @@ static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t s
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename)
{
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0;
@@ -583,9 +525,9 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
for(i = 0;i < irCount;i++)
{
delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > MAX_HRIR_DELAY)
if(delays[i][0] > maxDelay)
{
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
failed = AL_TRUE;
}
}
@@ -610,7 +552,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
}
}
Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount,
Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
evOffset, coeffs, delays, filename);
}
@@ -623,6 +565,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename)
{
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0;
@@ -731,9 +674,9 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
for(i = 0;i < irCount;i++)
{
delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > MAX_HRIR_DELAY)
if(delays[i][0] > maxDelay)
{
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
failed = AL_TRUE;
}
}
@@ -758,7 +701,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
}
}
Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount,
Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
evOffset, coeffs, delays, filename);
}
@@ -768,253 +711,6 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
return Hrtf;
}
#define SAMPLETYPE_S16 0
#define SAMPLETYPE_S24 1
#define CHANTYPE_LEFTONLY 0
#define CHANTYPE_LEFTRIGHT 1
static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char *filename)
{
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0;
ALubyte sampleType;
ALubyte channelType;
ALushort irCount = 0;
ALushort irSize = 0;
ALubyte fdCount = 0;
ALushort distance = 0;
ALubyte evCount = 0;
const ALubyte *azCount = NULL;
ALushort *evOffset = NULL;
ALfloat (*coeffs)[2] = NULL;
ALubyte (*delays)[2] = NULL;
ALsizei i, j;
if(datalen < 8)
{
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 8, datalen);
return NULL;
}
rate = GetLE_ALuint(&data, &datalen);
sampleType = GetLE_ALubyte(&data, &datalen);
channelType = GetLE_ALubyte(&data, &datalen);
irSize = GetLE_ALubyte(&data, &datalen);
fdCount = GetLE_ALubyte(&data, &datalen);
if(sampleType > SAMPLETYPE_S24)
{
ERR("Unsupported sample type: %d\n", sampleType);
failed = AL_TRUE;
}
if(channelType > CHANTYPE_LEFTRIGHT)
{
ERR("Unsupported channel type: %d\n", channelType);
failed = AL_TRUE;
}
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(fdCount != 1)
{
ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n",
evCount, MIN_FD_COUNT, MAX_FD_COUNT);
failed = AL_TRUE;
}
if(failed)
return NULL;
for(i = 0;i < fdCount;i++)
{
if(datalen < 3)
{
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 3, datalen);
return NULL;
}
distance = GetLE_ALushort(&data, &datalen);
if(distance < MIN_FD_DISTANCE || distance > MAX_FD_DISTANCE)
{
ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n",
distance, MIN_FD_DISTANCE, MAX_FD_DISTANCE);
failed = AL_TRUE;
}
evCount = GetLE_ALubyte(&data, &datalen);
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", filename, evCount, datalen);
return NULL;
}
azCount = Get_ALubytePtr(&data, &datalen, evCount);
for(j = 0;j < evCount;j++)
{
if(azCount[j] < MIN_AZ_COUNT || azCount[j] > MAX_AZ_COUNT)
{
ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
j, azCount[j], MIN_AZ_COUNT, MAX_AZ_COUNT);
failed = AL_TRUE;
}
}
}
if(failed)
return NULL;
evOffset = malloc(sizeof(evOffset[0])*evCount);
if(azCount == NULL || evOffset == NULL)
{
ERR("Out of memory.\n");
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);
delays = malloc(sizeof(delays[0])*irCount);
if(coeffs == NULL || delays == 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",
filename, reqsize, datalen);
failed = AL_TRUE;
}
}
if(!failed)
{
if(channelType == CHANTYPE_LEFTONLY)
{
if(sampleType == SAMPLETYPE_S16)
for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
}
else if(sampleType == SAMPLETYPE_S24)
for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
}
for(i = 0;i < irCount;i++)
{
delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > MAX_HRIR_DELAY)
{
ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
failed = AL_TRUE;
}
}
}
else if(channelType == CHANTYPE_LEFTRIGHT)
{
if(sampleType == SAMPLETYPE_S16)
for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
{
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
coeffs[i*irSize + j][1] = GetLE_ALshort(&data, &datalen) / 32768.0f;
}
}
else if(sampleType == SAMPLETYPE_S24)
for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
{
coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
coeffs[i*irSize + j][1] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
}
}
for(i = 0;i < irCount;i++)
{
delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > MAX_HRIR_DELAY)
{
ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
failed = AL_TRUE;
}
delays[i][1] = GetLE_ALubyte(&data, &datalen);
if(delays[i][1] > MAX_HRIR_DELAY)
{
ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY);
failed = AL_TRUE;
}
}
}
}
if(!failed)
{
if(channelType == CHANTYPE_LEFTONLY)
{
/* 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,
(ALfloat)distance / 1000.0f, evCount, irCount, azCount, evOffset,
coeffs, delays, filename
);
}
free(evOffset);
free(coeffs);
free(delays);
return Hrtf;
}
static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename)
{
@@ -1034,12 +730,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;
}
@@ -1096,7 +792,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_al_string filename, ALuint residx)
static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, size_t residx)
{
EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
struct HrtfEntry *loaded_entry;
@@ -1113,12 +809,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;
}
@@ -1136,7 +832,7 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filenam
);
loaded_entry->next = LoadedHrtfs;
loaded_entry->handle = hrtf;
snprintf(loaded_entry->filename, namelen, "!%u_%s",
snprintf(loaded_entry->filename, namelen, "!"SZFMT"_%s",
residx, alstr_get_cstr(filename));
LoadedHrtfs = loaded_entry;
}
@@ -1324,7 +1020,7 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
struct FileMapping fmap;
const ALubyte *rdata;
const char *name;
ALuint residx;
size_t residx;
size_t rsize;
char ch;
@@ -1340,7 +1036,7 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
fmap.ptr = NULL;
fmap.len = 0;
if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_')
if(sscanf(entry->filename, "!"SZFMT"%c", &residx, &ch) == 2 && ch == '_')
{
name = strchr(entry->filename, ch)+1;
@@ -1348,7 +1044,7 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
rdata = GetResource(residx, &rsize);
if(rdata == NULL || rsize == 0)
{
ERR("Could not get resource %u, %s\n", residx, name);
ERR("Could not get resource "SZFMT", %s\n", residx, name);
goto done;
}
}
@@ -1368,15 +1064,8 @@ struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
rsize = fmap.len;
}
if(rsize < sizeof(magicMarker02))
if(rsize < sizeof(magicMarker01))
ERR("%s data is too short ("SZFMT" bytes)\n", name, rsize);
else if(memcmp(rdata, magicMarker02, sizeof(magicMarker02)) == 0)
{
TRACE("Detected data set format v2\n");
hrtf = LoadHrtf02(rdata+sizeof(magicMarker02),
rsize-sizeof(magicMarker02), name
);
}
else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0)
{
TRACE("Detected data set format v1\n");
+8 -40
View File
@@ -9,13 +9,10 @@
#include "atomic.h"
#define HRTF_HISTORY_BITS (6)
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
/* The maximum number of virtual speakers used to generate HRTF coefficients
* for decoding B-Format.
*/
#define HRTF_AMBI_MAX_CHANNELS 16
struct HrtfEntry;
@@ -25,8 +22,6 @@ struct Hrtf {
ALuint sampleRate;
ALsizei irSize;
ALfloat distance;
ALubyte evCount;
const ALubyte *azCount;
@@ -36,33 +31,6 @@ struct Hrtf {
};
typedef struct HrtfState {
alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
alignas(16) ALfloat Values[HRIR_LENGTH][2];
} HrtfState;
typedef struct HrtfParams {
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
ALsizei Delay[2];
ALfloat Gain;
} HrtfParams;
typedef struct DirectHrtfState {
/* HRTF filter state for dry buffer content */
ALsizei Offset;
ALsizei IrSize;
struct {
alignas(16) ALfloat Values[HRIR_LENGTH][2];
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
} Chan[];
} DirectHrtfState;
struct AngularPoint {
ALfloat Elev;
ALfloat Azim;
};
void FreeHrtfs(void);
vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname);
@@ -75,10 +43,10 @@ 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, 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.
* virtual speaker positions and HF/LF matrices for decoding to them. The
* returned coefficients are ordered and scaled according to the matrices.
* Returns the maximum impulse-response length of the generated coefficients.
*/
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);
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 */
-87
View File
@@ -1,87 +0,0 @@
#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
#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);
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
#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
#endif /* INPROGEXT_H */
-69
View File
@@ -1,69 +0,0 @@
#ifndef LOGGING_H
#define LOGGING_H
#include <stdio.h>
#ifdef __GNUC__
#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
#else
#define DECL_FORMAT(x, y, z)
#endif
#ifdef __cplusplus
extern "C" {
#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 <android/log.h>
#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)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LOGGING_H */
+190 -465
View File
@@ -2,529 +2,254 @@
#include <math.h>
#include "mastering.h"
#include "alu.h"
#include "almalloc.h"
#include "static_assert.h"
#define RMS_WINDOW_SIZE (1<<7)
#define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1)
#define RMS_VALUE_MAX (1<<24)
/* These structures assume BUFFERSIZE is a power of 2. */
static_assert((BUFFERSIZE & (BUFFERSIZE-1)) == 0, "BUFFERSIZE is not a power of 2");
#define LOOKAHEAD_SIZE (1<<13)
#define LOOKAHEAD_MASK (LOOKAHEAD_SIZE-1)
typedef struct SlidingHold {
ALfloat Values[BUFFERSIZE];
ALsizei Expiries[BUFFERSIZE];
ALsizei LowerIndex;
ALsizei UpperIndex;
ALsizei Length;
} SlidingHold;
static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big");
/* 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;
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;
ALuint RmsSum;
ALuint *RmsWindow;
ALsizei RmsIndex;
ALfloat Envelope[BUFFERSIZE];
ALfloat EnvLast;
} Compressor;
/* 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:
/* Multichannel compression is linked via one of two modes:
*
* http://www.richardhartersworld.com/cri/2001/slidingmin.html
* Summed - Absolute sum of all channels.
* Maxed - Absolute maximum of any channel.
*/
static ALfloat UpdateSlidingHold(SlidingHold *Hold, const ALsizei i, const ALfloat in)
static void SumChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE])
{
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;
ALsizei c, i;
if(i >= expiries[upperIndex])
upperIndex = (upperIndex + 1) & mask;
for(i = 0;i < SamplesToDo;i++)
Comp->Envelope[i] = 0.0f;
if(in >= values[upperIndex])
for(c = 0;c < NumChans;c++)
{
values[upperIndex] = in;
expiries[upperIndex] = i + length;
lowerIndex = upperIndex;
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] = fastf2i(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
{
do {
do {
if(!(in >= values[lowerIndex]))
goto found_place;
} while(lowerIndex--);
lowerIndex = mask;
} while(1);
found_place:
const ALfloat lower = threshold - (0.5f * knee);
const ALfloat upper = threshold + (0.5f * knee);
const ALfloat m = 0.5f * Slope / knee;
lowerIndex = (lowerIndex + 1) & mask;
values[lowerIndex] = in;
expiries[lowerIndex] = i + length;
}
Hold->LowerIndex = lowerIndex;
Hold->UpperIndex = upperIndex;
return values[upperIndex];
}
static void ShiftSlidingHold(SlidingHold *Hold, const ALsizei n)
{
const ALsizei lowerIndex = Hold->LowerIndex;
ALsizei *restrict expiries = Hold->Expiries;
ALsizei i = Hold->UpperIndex;
if(lowerIndex < i)
{
for(;i < BUFFERSIZE;i++)
expiries[i] -= n;
i = 0;
}
for(;i < lowerIndex;i++)
expiries[i] -= n;
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 index = Comp->LookAhead;
const ALsizei numChans = Comp->NumChans;
ALfloat *restrict sideChain = Comp->SideChain;
ALsizei c, i;
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
for(i = 0;i < SamplesToDo;i++)
sideChain[index + i] = 0.0f;
for(c = 0;c < numChans;c++)
{
ALsizei offset = index;
for(i = 0;i < SamplesToDo;i++)
{
sideChain[offset] = maxf(sideChain[offset], fabsf(OutBuffer[c][i]));
++offset;
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));
}
}
}
/* 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 CrestDetector(Compressor *Comp, const ALsizei SamplesToDo)
{
const ALfloat a_crest = Comp->CrestCoeff;
const ALsizei index = 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;
ASSUME(SamplesToDo > 0);
for(i = 0;i < SamplesToDo;i++)
{
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));
y2_rms = lerp(x2, y2_rms, a_crest);
crestFactor[i] = y2_peak / y2_rms;
}
Comp->LastPeakSq = y2_peak;
Comp->LastRmsSq = y2_rms;
}
/* 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 PeakDetector(Compressor *Comp, const ALsizei SamplesToDo)
{
const ALsizei index = Comp->LookAhead;
ALfloat *restrict sideChain = Comp->SideChain;
ALsizei i;
ASSUME(SamplesToDo > 0);
for(i = 0;i < SamplesToDo;i++)
{
const ALuint offset = index + i;
const ALfloat x_abs = sideChain[offset];
sideChain[offset] = logf(maxf(0.000001f, x_abs));
}
}
/* 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 index = Comp->LookAhead;
ALfloat *restrict sideChain = Comp->SideChain;
SlidingHold *hold = Comp->Hold;
ALsizei i;
ASSUME(SamplesToDo > 0);
for(i = 0;i < SamplesToDo;i++)
{
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);
}
ShiftSlidingHold(hold, SamplesToDo);
}
/* 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 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 slope = Comp->Slope;
const ALfloat attack = Comp->Attack;
const ALfloat release = Comp->Release;
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 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;
ASSUME(SamplesToDo > 0);
for(i = 0;i < SamplesToDo;i++)
{
const ALfloat y2_crest = crestFactor[i];
const ALfloat x_G = sideChain[lookAhead + i];
const 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)
{
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)
c_dev = maxf(c_dev, sideChain[i] - y_L - threshold - c_est);
postGain = -(c_dev + c_est);
}
sideChain[i] = expf(postGain - y_L);
}
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;
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
for(c = 0;c < numChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
{
ALfloat sig = OutBuffer[c][i];
OutBuffer[c][i] = delay[c][(indexOut + i) & mask];
delay[c][(indexIn + i) & mask] = sig;
}
}
Comp->DelayIndex = (indexIn + SamplesToDo) & mask;
}
/* 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 ALsizei 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 *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;
ALsizei lookAhead;
ALsizei hold;
size_t size;
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;
ALsizei i;
size = sizeof(*Comp);
if(lookAhead > 0)
{
size += sizeof(*Comp->Delay) * NumChans;
if(hold > 0)
size += sizeof(*Comp->Hold);
}
if(RmsSensing)
size += sizeof(Comp->RmsWindow[0]) * RMS_WINDOW_SIZE;
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);
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;
/* 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;
Comp->RmsSum = 0;
if(RmsSensing)
Comp->RmsWindow = (ALuint*)(Comp+1);
else
Comp->RmsWindow = NULL;
Comp->RmsIndex = 0;
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);
}
}
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
for(i = 0;i < BUFFERSIZE;i++)
Comp->Envelope[i] = 0.0f;
Comp->EnvLast = -6.0f;
return Comp;
}
void ApplyCompression(Compressor *Comp, const ALsizei SamplesToDo, ALfloat (*restrict OutBuffer)[BUFFERSIZE])
ALuint GetCompressorSampleRate(const Compressor *Comp)
{
return Comp->SampleRate;
}
void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE])
{
const ALsizei numChans = Comp->NumChans;
const ALfloat preGain = Comp->PreGain;
ALfloat *restrict sideChain;
ALsizei c, i;
ASSUME(SamplesToDo > 0);
ASSUME(numChans > 0);
if(preGain != 1.0f)
if(Comp->PreGain != 1.0f)
{
for(c = 0;c < numChans;c++)
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
OutBuffer[c][i] *= preGain;
OutBuffer[c][i] *= Comp->PreGain;
}
}
LinkChannels(Comp, SamplesToDo, OutBuffer);
if(Comp->Auto.Attack || Comp->Auto.Release)
CrestDetector(Comp, SamplesToDo);
if(Comp->Hold)
PeakHoldDetector(Comp, SamplesToDo);
if(Comp->SummedLink)
SumChannels(Comp, NumChans, SamplesToDo, OutBuffer);
else
PeakDetector(Comp, SamplesToDo);
MaxChannels(Comp, NumChans, SamplesToDo, OutBuffer);
GainCompressor(Comp, SamplesToDo);
if(Comp->RmsWindow)
RmsDetection(Comp, SamplesToDo);
FollowEnvelope(Comp, SamplesToDo);
if(Comp->Delay)
SignalDelay(Comp, SamplesToDo, OutBuffer);
if(Comp->Ratio > 0.0f)
EnvelopeGain(Comp, SamplesToDo, 1.0f - (1.0f / Comp->Ratio));
else
EnvelopeGain(Comp, SamplesToDo, 1.0f);
sideChain = Comp->SideChain;
for(c = 0;c < numChans;c++)
if(Comp->PostGain != 1.0f)
{
for(i = 0;i < SamplesToDo;i++)
OutBuffer[c][i] *= sideChain[i];
Comp->Envelope[i] *= Comp->PostGain;
}
for(c = 0;c < NumChans;c++)
{
for(i = 0;i < SamplesToDo;i++)
OutBuffer[c][i] *= Comp->Envelope[i];
}
memmove(sideChain, sideChain+SamplesToDo, Comp->LookAhead*sizeof(ALfloat));
}
ALsizei GetCompressorLookAhead(const Compressor *Comp)
{ return Comp->LookAhead; }
-49
View File
@@ -1,49 +0,0 @@
#ifndef MASTERING_H
#define MASTERING_H
#include "AL/al.h"
/* For BUFFERSIZE. */
#include "alMain.h"
struct Compressor;
/* 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 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.
*/
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,
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 SamplesToDo,
ALfloat (*restrict OutBuffer)[BUFFERSIZE]);
ALsizei GetCompressorLookAhead(const struct Compressor *Comp);
#endif /* MASTERING_H */
+176 -267
View File
@@ -33,33 +33,29 @@
#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"
#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, ALsizei *restrict pos_arr, ALsizei size);
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!");
/* 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!");
enum Resampler ResamplerDefault = LinearResampler;
MixerFunc MixSamples = Mix_C;
RowMixerFunc MixRowSamples = MixRow_C;
static MixerFunc MixSamples = Mix_C;
static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C;
HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C;
static MixerFunc SelectMixer(void)
MixerFunc SelectMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
@@ -72,7 +68,7 @@ static MixerFunc SelectMixer(void)
return Mix_C;
}
static RowMixerFunc SelectRowMixer(void)
RowMixerFunc SelectRowMixer(void)
{
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
@@ -116,37 +112,48 @@ ResamplerFunc SelectResampler(enum Resampler resampler)
switch(resampler)
{
case PointResampler:
return Resample_point_C;
return Resample_point32_C;
case LinearResampler:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_lerp_Neon;
return Resample_lerp32_Neon;
#endif
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_lerp_SSE41;
return Resample_lerp32_SSE41;
#endif
#ifdef HAVE_SSE2
if((CPUCapFlags&CPU_CAP_SSE2))
return Resample_lerp_SSE2;
return Resample_lerp32_SSE2;
#endif
return Resample_lerp_C;
return Resample_lerp32_C;
case FIR4Resampler:
return Resample_cubic_C;
case BSinc12Resampler:
case BSinc24Resampler:
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Resample_bsinc_Neon;
return Resample_fir4_32_Neon;
#endif
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_fir4_32_SSE41;
#endif
#ifdef HAVE_SSE3
if((CPUCapFlags&CPU_CAP_SSE3))
return Resample_fir4_32_SSE3;
#endif
return Resample_fir4_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_bsinc_SSE;
return Resample_bsinc32_SSE;
#endif
return Resample_bsinc_C;
return Resample_bsinc32_C;
}
return Resample_point_C;
return Resample_point32_C;
}
@@ -160,20 +167,13 @@ void aluInitMixer(void)
ResamplerDefault = PointResampler;
else if(strcasecmp(str, "linear") == 0)
ResamplerDefault = LinearResampler;
else if(strcasecmp(str, "cubic") == 0)
else if(strcasecmp(str, "sinc4") == 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)
ResamplerDefault = BSincResampler;
else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 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);
WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str);
ResamplerDefault = FIR4Resampler;
}
else
@@ -190,25 +190,11 @@ void aluInitMixer(void)
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 = 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);
}
static inline ALfloat Sample_ALubyte(ALubyte val)
{ return (val-128) * (1.0f/128.0f); }
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/128.0f); }
static inline ALfloat Sample_ALshort(ALshort val)
{ return val * (1.0f/32768.0f); }
@@ -216,53 +202,45 @@ 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); }
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) \
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]); \
dst[i] = Sample_##T(src[i*srcstep]); \
}
DECL_TEMPLATE(ALubyte)
DECL_TEMPLATE(ALbyte)
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)
static void LoadSamples(ALfloat *dst, const ALvoid *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);
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;
}
#undef HANDLE_FMT
}
static inline void SilenceSamples(ALfloat *dst, ALsizei samples)
{
ALsizei i;
for(i = 0;i < samples;i++)
dst[i] = 0.0f;
}
static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter,
static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
ALfloat *restrict dst, const ALfloat *restrict src,
ALsizei numsamples, enum ActiveFilters type)
{
@@ -270,17 +248,17 @@ static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter,
switch(type)
{
case AF_None:
BiquadFilter_passthru(lpfilter, numsamples);
BiquadFilter_passthru(hpfilter, numsamples);
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_processPassthru(hpfilter, src, numsamples);
break;
case AF_LowPass:
BiquadFilter_process(lpfilter, dst, src, numsamples);
BiquadFilter_passthru(hpfilter, numsamples);
ALfilterState_process(lpfilter, dst, src, numsamples);
ALfilterState_processPassthru(hpfilter, dst, numsamples);
return dst;
case AF_HighPass:
BiquadFilter_passthru(lpfilter, numsamples);
BiquadFilter_process(hpfilter, dst, src, numsamples);
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_process(hpfilter, dst, src, numsamples);
return dst;
case AF_BandPass:
@@ -289,8 +267,8 @@ static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter,
ALfloat temp[256];
ALsizei todo = mini(256, numsamples-i);
BiquadFilter_process(lpfilter, temp, src+i, todo);
BiquadFilter_process(hpfilter, dst+i, temp, todo);
ALfilterState_process(lpfilter, temp, src+i, todo);
ALfilterState_process(hpfilter, dst+i, temp, todo);
i += todo;
}
return dst;
@@ -299,19 +277,11 @@ static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *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, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo)
ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, 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;
@@ -322,13 +292,11 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
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);
@@ -340,7 +308,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0);
Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
Resample_copy_C : voice->Resampler);
Resample_copy32_C : voice->Resampler);
Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0;
firstpass = true;
@@ -354,126 +322,81 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
DataSize64 += MAX_RESAMPLE_PADDING*2;
DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
/* Figure out how many samples we can actually mix from this. */
DataSize64 = SrcBufferSize;
DataSize64 -= MAX_RESAMPLE_PADDING*2;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment,
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. */
if(DstBufferSize < SamplesToDo-OutPos)
if(OutPos+DstBufferSize < SamplesToDo)
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;
ALfloat *SrcData = Device->SourceData;
ALsizei SrcDataSize;
/* 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;
/* Load the previous samples into the source data first. */
memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
SrcDataSize = MAX_PRE_SAMPLES;
if(isstatic)
if(Source->SourceType == AL_STATIC)
{
/* 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;
const ALbuffer *ALBuffer = BufferListItem->buffer;
const ALubyte *Data = ALBuffer->data;
ALsizei DataSize;
/* Offset buffer data to current channel */
Data += chan*SampleSize;
/* If current pos is beyond the loop range, do not loop */
if(!BufferLoopItem || DataPosInt >= LoopEnd)
if(!BufferLoopItem || DataPosInt >= ALBuffer->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;
/* Load what's left to play from the source buffer, and
* clear the rest of the temp buffer */
DataSize = minu(SrcBufferSize - SrcDataSize,
ALBuffer->SampleLen - DataPosInt);
if(DataPosInt >= buffer->SampleLen)
continue;
LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
/* 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;
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
else
{
ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt);
ALsizei CompLen = 0;
ALsizei i;
ALsizei LoopStart = ALBuffer->LoopStart;
ALsizei LoopEnd = ALBuffer->LoopEnd;
for(i = 0;i < BufferListItem->num_buffers;i++)
/* Load what's left of this loop iteration, then load
* repeats of the loop section */
DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt);
LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
DataSize = LoopEnd-LoopStart;
while(SrcBufferSize > SrcDataSize)
{
const ALbuffer *buffer = BufferListItem->buffers[i];
const ALubyte *Data = buffer->data;
ALsizei DataSize;
DataSize = mini(SrcBufferSize - SrcDataSize, 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;
LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
}
@@ -483,60 +406,57 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
ALbufferlistitem *tmpiter = BufferListItem;
ALsizei pos = DataPosInt;
while(tmpiter && SrcBufferSize > FilledAmt)
while(tmpiter && SrcBufferSize > SrcDataSize)
{
ALsizei SizeToDo = SrcBufferSize - FilledAmt;
ALsizei CompLen = 0;
ALsizei i;
for(i = 0;i < tmpiter->num_buffers;i++)
const ALbuffer *ALBuffer;
if((ALBuffer=tmpiter->buffer) != NULL)
{
const ALbuffer *ALBuffer = tmpiter->buffers[i];
ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0;
const ALubyte *Data = ALBuffer->data;
ALsizei DataSize = ALBuffer->SampleLen;
if(DataSize > pos)
/* Skip the data already played */
if(DataSize <= pos)
pos -= DataSize;
else
{
const ALubyte *Data = ALBuffer->data;
Data += (pos*NumChannels + chan)*SampleSize;
DataSize -= pos;
pos -= pos;
DataSize = mini(SizeToDo, DataSize - pos);
CompLen = maxi(CompLen, DataSize);
LoadSamples(&SrcData[FilledAmt], Data, NumChannels,
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
if(UNLIKELY(!CompLen))
pos -= tmpiter->max_samples;
else
{
FilledAmt += CompLen;
if(SrcBufferSize <= FilledAmt)
break;
pos = 0;
}
tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire);
if(!tmpiter) tmpiter = BufferLoopItem;
if(!tmpiter && BufferLoopItem)
tmpiter = BufferLoopItem;
else if(!tmpiter)
{
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
}
}
/* Store the last source samples used for next time. */
memcpy(voice->PrevSamples[chan],
&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
MAX_RESAMPLE_PADDING*sizeof(ALfloat)
MAX_PRE_SAMPLES*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
&SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
Device->ResampledData, DstBufferSize
);
{
DirectParams *parms = &voice->Direct.Params[chan];
const ALfloat *samples;
samples = DoFilters(
&parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF],
&parms->LowPass, &parms->HighPass, Device->FilteredData,
ResampledData, DstBufferSize, voice->Direct.FilterType
);
if(!(voice->Flags&VOICE_HAS_HRTF))
@@ -551,7 +471,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
);
else
{
ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF];
ALfloat *nfcsamples = Device->NFCtrlData;
ALsizei chanoffset = 0;
MixSamples(samples,
@@ -563,8 +483,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
#define APPLY_NFC_MIX(order) \
if(voice->Direct.ChannelsPerOrder[order] > 0) \
{ \
NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples, \
DstBufferSize); \
NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \
samples, DstBufferSize); \
MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \
voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \
@@ -583,8 +503,8 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
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)
@@ -616,7 +536,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
*/
gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain,
minf(1.0f, (ALfloat)fademix/Counter));
hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs;
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;
@@ -645,7 +565,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
gain = lerp(parms->Hrtf.Old.Gain, gain,
(ALfloat)todo/(Counter-fademix));
hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs;
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;
@@ -675,7 +595,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
continue;
samples = DoFilters(
&parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF],
&parms->LowPass, &parms->HighPass, Device->FilteredData,
ResampledData, DstBufferSize, voice->Send[send].FilterType
);
@@ -697,50 +617,47 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
firstpass = false;
if(isstatic)
/* Handle looping sources */
while(1)
{
if(BufferLoopItem)
const ALbuffer *ALBuffer;
ALsizei DataSize = 0;
ALsizei LoopStart = 0;
ALsizei LoopEnd = 0;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
/* 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;
}
DataSize = ALBuffer->SampleLen;
LoopStart = ALBuffer->LoopStart;
LoopEnd = ALBuffer->LoopEnd;
if(LoopEnd > DataPosInt)
break;
}
else
if(BufferLoopItem && Source->SourceType == AL_STATIC)
{
/* Handle non-looping static source */
if(DataPosInt >= BufferListItem->max_samples)
assert(LoopEnd > LoopStart);
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
break;
}
if(DataSize > DataPosInt)
break;
BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire);
if(!BufferListItem)
{
BufferListItem = BufferLoopItem;
if(!BufferListItem)
{
isplaying = false;
BufferListItem = NULL;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
}
}
else while(1)
{
/* Handle streaming source */
if(BufferListItem->max_samples > DataPosInt)
break;
DataPosInt -= BufferListItem->max_samples;
buffers_done += BufferListItem->num_buffers;
BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_relaxed);
if(!BufferListItem && !(BufferListItem=BufferLoopItem))
{
isplaying = false;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
DataPosInt -= DataSize;
}
} while(isplaying && OutPos < SamplesToDo);
@@ -750,13 +667,5 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
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;
}
-283
View File
@@ -1,283 +0,0 @@
#include "config.h"
#include <arm_neon.h>
#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) ALsizei pos_[4], frac_[4];
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_);
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);
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);
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);
}
/* 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)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
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;
ASSUME(m > 0);
ASSUME(dstlen > 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<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
offset = m*pi*4;
fil = ASSUME_ALIGNED(filter + offset, 16); offset += m;
scd = ASSUME_ALIGNED(filter + offset, 16); offset += m;
phd = ASSUME_ALIGNED(filter + offset, 16); offset += m;
spd = ASSUME_ALIGNED(filter + offset, 16);
// 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);
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[j], sf4, scd[j]),
pf4, vmlaq_f32(phd[j], sf4, spd[j])
);
/* r += f*src */
r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j*4]));
}
}
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 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 "hrtf_inc.c"
void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
ALsizei BufferSize)
{
const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
ALsizei c;
ASSUME(OutChans > 0);
ASSUME(BufferSize > 0);
data = ASSUME_ALIGNED(data, 16);
OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
for(c = 0;c < OutChans;c++)
{
ALsizei pos = 0;
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;
/* Mix with applying gain steps in aligned multiples of 4. */
if(LIKELY(minsize > 3))
{
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, vmlaq_f32(gain4, step4, step_count4));
step_count4 = vaddq_f32(step_count4, four4);
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
} 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.
*/
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 + 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. */
minsize = mini(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
if(LIKELY(BufferSize-pos > 3))
{
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;
}
}
void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
{
ALsizei c;
ASSUME(InChans > 0);
ASSUME(BufferSize > 0);
for(c = 0;c < InChans;c++)
{
ALsizei pos = 0;
const ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
if(LIKELY(BufferSize > 3))
{
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;
}
}
View File
+99 -60
View File
@@ -6,42 +6,17 @@
#include "alu.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "defs.h"
static inline ALfloat do_point(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei UNUSED(frac))
static inline ALfloat point32(const ALfloat *restrict vals, ALsizei UNUSED(frac))
{ return vals[0]; }
static inline ALfloat do_lerp(const InterpState* UNUSED(state), const ALfloat *restrict vals, ALsizei frac)
static inline ALfloat lerp32(const ALfloat *restrict vals, ALsizei frac)
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
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;
static inline ALfloat fir4_32(const ALfloat *restrict vals, ALsizei frac)
{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
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<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
fil = ASSUME_ALIGNED(state->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 *Resample_copy32_C(const InterpState* UNUSED(state),
const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment),
ALfloat *restrict dst, ALsizei numsamples)
{
@@ -54,20 +29,15 @@ const ALfloat *Resample_copy_C(const InterpState* UNUSED(state),
return dst;
}
#define DECL_TEMPLATE(Tag, Sampler, O) \
const ALfloat *Resample_##Tag##_C(const InterpState *state, \
#define DECL_TEMPLATE(Sampler) \
const ALfloat *Resample_##Sampler##_C(const InterpState* UNUSED(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(&istate, src, frac); \
dst[i] = Sampler(src, frac); \
\
frac += increment; \
src += frac>>FRACTIONBITS; \
@@ -76,13 +46,90 @@ const ALfloat *Resample_##Tag##_C(const InterpState *state, \
return dst; \
}
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)
DECL_TEMPLATE(point32)
DECL_TEMPLATE(lerp32)
DECL_TEMPLATE(fir4_32)
#undef DECL_TEMPLATE
const ALfloat *Resample_bsinc32_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 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<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
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;
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];
dst[i] = r;
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples)
{
ALsizei i;
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];
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];
}
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,
@@ -101,39 +148,34 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
#define MixHrtf MixHrtf_C
#define MixHrtfBlend MixHrtfBlend_C
#define MixDirectHrtf MixDirectHrtf_C
#include "hrtf_inc.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)
{
const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
ALfloat gain, delta, step;
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;
ALfloat gain = CurrentGains[c];
const ALfloat diff = TargetGains[c] - gain;
if(fabsf(diff) > FLT_EPSILON)
gain = CurrentGains[c];
step = (TargetGains[c] - gain) * delta;
if(fabsf(step) > FLT_EPSILON)
{
ALsizei minsize = mini(BufferSize, Counter);
const ALfloat step = diff * delta;
ALfloat step_count = 0.0f;
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos] * (gain + step*step_count);
step_count += 1.0f;
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain += step;
}
if(pos == Counter)
gain = TargetGains[c];
else
gain += step*step_count;
CurrentGains[c] = gain;
}
@@ -154,12 +196,9 @@ 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++)
{
const ALfloat gain = Gains[c];
ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
+31 -21
View File
@@ -12,11 +12,11 @@ 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);
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 */
@@ -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, ALsizei *restrict pos_arr, ALsizei size)
inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size)
{
ALsizei i;
@@ -76,16 +76,23 @@ inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restr
}
}
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_lerp32_SSE2(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_lerp32_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);
const ALfloat *Resample_fir4_32_SSE3(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_fir4_32_SSE41(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_bsinc32_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,
@@ -109,11 +116,14 @@ void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains,
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);
const ALfloat *Resample_lerp32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_fir4_32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei numsamples);
const ALfloat *Resample_bsinc32_Neon(const InterpState *state, const ALfloat *restrict src,
ALsizei frac, ALint increment, ALfloat *restrict dst,
ALsizei dstlen);
#endif /* MIXER_DEFS_H */
+18 -32
View File
@@ -4,9 +4,9 @@
#include "alSource.h"
#include "hrtf.h"
#include "mixer_defs.h"
#include "align.h"
#include "alu.h"
#include "defs.h"
static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
@@ -22,24 +22,18 @@ 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] };
const ALfloat gainstep = hrtfparams->GainStep;
const ALfloat gain = hrtfparams->Gain;
ALfloat g, stepcount = 0.0f;
ALfloat gainstep = hrtfparams->GainStep;
ALfloat gain = hrtfparams->Gain;
ALfloat left, right;
ALsizei i;
ASSUME(IrSize >= 4);
ASSUME(BufferSize > 0);
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
{
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
g = gain + gainstep*stepcount;
left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*g;
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;
@@ -48,10 +42,10 @@ void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
*(LeftOut++) += hrtfstate->Values[Offset&HRIR_MASK][0];
*(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
stepcount += 1.0f;
gain += gainstep;
Offset++;
}
hrtfparams->Gain = gain + gainstep*stepcount;
hrtfparams->Gain = gain;
}
void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
@@ -62,19 +56,15 @@ 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] };
const ALfloat oldGain = oldparams->Gain;
const ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize;
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] };
const ALfloat newGain = newparams->Gain;
const ALfloat newGainStep = newparams->GainStep;
ALfloat g, stepcount = 0.0f;
ALfloat newGain = newparams->Gain;
ALfloat newGainStep = newparams->GainStep;
ALfloat left, right;
ALsizei i;
ASSUME(IrSize >= 4);
ASSUME(BufferSize > 0);
LeftOut += OutPos;
RightOut += OutPos;
for(i = 0;i < BufferSize;i++)
@@ -84,23 +74,22 @@ void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
g = oldGain + oldGainStep*stepcount;
left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*g;
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);
g = newGain + newGainStep*stepcount;
left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*g;
right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*g;
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];
stepcount += 1.0f;
oldGain += oldGainStep;
newGain += newGainStep;
Offset++;
}
newparams->Gain = newGain + newGainStep*stepcount;
newparams->Gain = newGain;
}
void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
@@ -111,9 +100,6 @@ 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;
+331
View File
@@ -0,0 +1,331 @@
#include "config.h"
#include <arm_neon.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_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_fir4_32_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 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_);
--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(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);
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_s32(frac4, increment4);
pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS));
frac4 = vandq_s32(frac4, fracMask4);
vst1q_s32(pos_, pos4);
vst1q_s32(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_bsinc32_Neon(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen)
{
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->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<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
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);
{
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]));
}
}
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 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;
}
}
+59 -79
View File
@@ -9,25 +9,21 @@
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "defs.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 *Resample_bsinc32_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;
const ALfloat *fil, *scd, *phd, *spd;
ALsizei pi, i, j;
ALfloat pf;
__m128 r4;
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.
@@ -36,32 +32,30 @@ const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restr
pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
#undef FRAC_PHASE_BITDIFF
offset = m*pi*4;
fil = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
scd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
phd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
spd = (const __m128*)ASSUME_ALIGNED(filter + offset, 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();
{
const ALsizei count = m >> 2;
const __m128 pf4 = _mm_set1_ps(pf);
ASSUME(count > 0);
#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 < count;j++)
for(j = 0;j < m;j+=4)
{
/* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */
const __m128 f4 = MLA4(
MLA4(fil[j], sf4, scd[j]),
pf4, MLA4(phd[j], sf4, spd[j])
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, _mm_loadu_ps(&src[j*4]));
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));
@@ -132,65 +126,61 @@ static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
#define MixHrtf MixHrtf_SSE
#define MixHrtfBlend MixHrtfBlend_SSE
#define MixDirectHrtf MixDirectHrtf_SSE
#include "hrtf_inc.c"
#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)
{
const ALfloat delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
ALfloat gain, delta, step;
__m128 gain4;
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;
ALfloat gain = CurrentGains[c];
const ALfloat diff = TargetGains[c] - gain;
if(fabsf(diff) > FLT_EPSILON)
gain = CurrentGains[c];
step = (TargetGains[c] - gain) * delta;
if(fabsf(step) > 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))
if(minsize-pos > 3)
{
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;
__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]);
#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
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
gain4 = _mm_add_ps(gain4, step4);
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
step_count4 = _mm_add_ps(step_count4, four4);
pos += 4;
} 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.
} 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.
*/
step_count = _mm_cvtss_f32(step_count4);
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 + step*step_count);
step_count += 1.0f;
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain += step;
}
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. */
@@ -201,17 +191,13 @@ void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
if(LIKELY(BufferSize-pos > 3))
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
{
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);
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;
@@ -220,29 +206,23 @@ 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);
ASSUME(BufferSize > 0);
for(c = 0;c < InChans;c++)
{
ALsizei pos = 0;
const ALfloat gain = Gains[c];
ALfloat gain = Gains[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
if(LIKELY(BufferSize > 3))
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
{
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);
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;
+16 -19
View File
@@ -22,38 +22,33 @@
#include <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "alu.h"
#include "defs.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state),
const ALfloat *Resample_lerp32_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);
alignas(16) ALsizei pos_[4], frac_[4];
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALsizei todo, pos, i;
ALint pos;
ALsizei 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));
todo = numsamples & ~3;
for(i = 0;i < todo;i += 4)
for(i = 0;numsamples-i > 3;i += 4)
{
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]);
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);
@@ -65,15 +60,17 @@ 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);
_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 = _mm_cvtsi128_si32(pos4);
pos = pos_.i[0];
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));
+39 -26
View File
@@ -1,6 +1,9 @@
/**
* OpenAL cross platform audio library
* OpenAL cross platform audio library, SSE3 mixer functions
*
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* Copyright (C) 2015 by Chris Robinson <chris.kcat@gmail.com>.
*
* 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
@@ -22,59 +25,69 @@
#include <xmmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include "alu.h"
#include "defs.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state),
const ALfloat *Resample_fir4_32_SSE3(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);
alignas(16) ALsizei pos_[4], frac_[4];
union { alignas(16) ALint i[4]; float f[4]; } pos_;
union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALsizei todo, pos, i;
ALint pos;
ALsizei 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));
todo = numsamples & ~3;
for(i = 0;i < todo;i += 4)
--src;
for(i = 0;numsamples-i > 3;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)));
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]);
const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
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(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;
/* 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));
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 = _mm_hadd_ps(k0, k2);
_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));
_mm_store_ps(frac_.f, _mm_castsi128_ps(frac4));
}
/* NOTE: These four elements represent the position *after* the last four
* samples, so the lowest element is the next position to resample.
*/
pos = _mm_cvtsi128_si32(pos4);
frac = _mm_cvtsi128_si32(frac4);
pos = pos_.i[0];
frac = frac_.i[0];
for(;i < numsamples;++i)
for(;i < numsamples;i++)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
+154
View File
@@ -0,0 +1,154 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* 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 <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_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;
}
const ALfloat *Resample_fir4_32_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 __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));
--src;
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
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(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);
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 = _mm_hadd_ps(k0, k2);
_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);
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_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
+201 -209
View File
@@ -1,10 +1,9 @@
#include "config.h"
#include "nfc.h"
#include "alMain.h"
#include "nfcfilter.h"
#include <string.h>
#include "alu.h"
/* Near-field control filters are the basis for handling the near-field effect.
@@ -53,256 +52,249 @@ static const float B[4][3] = {
/*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/
};
static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1)
void NfcFilterCreate1(NfcFilter *nfc, const float w0, const float w1)
{
float b_00, g_0;
float r;
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->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->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)
{
float b_00, g_0;
float r;
r = 0.5f * w0;
b_00 = B[1][0] * r;
g_0 = 1.0f + b_00;
nfc->gain = nfc->base_gain * g_0;
nfc->b1 = 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->base_gain = 1.0f;
nfc->gain = 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->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;
b_10 = B[2][0] * r;
b_11 = B[2][1] * r * r;
g_1 = 1.0f + b_10 + b_11;
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)
{
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->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;
}
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->base_gain = 1.0f;
nfc->gain = 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->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->gain *= g_0;
nfc->b3 = 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->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->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)
{
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->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->gain *= g_0;
nfc->b3 = 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);
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;
}
void NfcFilterAdjust(NfcFilter *nfc, const float w0)
void NfcFilterAdjust1(NfcFilter *nfc, const float w0)
{
NfcFilterAdjust1(&nfc->first, w0);
NfcFilterAdjust2(&nfc->second, w0);
NfcFilterAdjust3(&nfc->third, 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;
}
void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
void NfcFilterUpdate1(NfcFilter *nfc, ALfloat *restrict dst, const float *restrict src, const int count)
{
const float gain = nfc->first.gain;
const float b1 = nfc->first.b1;
const float a1 = nfc->first.a1;
float z1 = nfc->first.z[0];
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;
ASSUME(count > 0);
for(i = 0;i < count;i++)
{
float y = src[i]*gain - a1*z1;
float out = y + b1*z1;
float out = src[i] * b0;
float y;
y = out - (a1*z1);
out = y + (a0*z1);
z1 += y;
dst[i] = out;
}
nfc->first.z[0] = z1;
nfc->history[0] = z1;
}
void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
{
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);
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 = 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;
}
void NfcFilterAdjust2(NfcFilter *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;
}
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 y = src[i]*gain - a1*z1 - a2*z2;
float out = y + b1*z1 + b2*z2;
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.z[0] = z1;
nfc->second.z[1] = z2;
nfc->history[0] = z1;
nfc->history[1] = z2;
}
void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
{
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);
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 = 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;
}
void NfcFilterAdjust3(NfcFilter *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 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 y = src[i]*gain - a1*z1 - a2*z2;
float out = y + b1*z1 + b2*z2;
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 - a3*z3;
out = y + b3*z3;
y = out - (a12*z3);
out = y + (a02*z3);
z3 += y;
dst[i] = out;
}
nfc->third.z[0] = z1;
nfc->third.z[1] = z2;
nfc->third.z[2] = z3;
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)
{
@@ -399,7 +391,7 @@ static void NfcFilterAdjust(NfcFilter *nfc, const float distance)
}
}
static float NfcFilterProcess(const float in, NfcFilter *nfc)
static float NfcFilterUpdate(const float in, NfcFilter *nfc)
{
int i;
float out = in * nfc->coeffs[0];
+37
View File
@@ -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 */
+266 -234
View File
@@ -29,19 +29,14 @@
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "alconfig.h"
#include "bool.h"
#include "ambdec.h"
#include "bformatdec.h"
#include "filters/splitter.h"
#include "uhjfilter.h"
#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 float ScaleAzimuthFront(float azimuth, float scale);
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] = {
@@ -67,16 +62,64 @@ 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 CalcAmbiCoeffs(const ALfloat y, const ALfloat z, const ALfloat x, const ALfloat spread,
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];
ALfloat y = -dir[0];
ALfloat z = dir[1];
/* Zeroth-order */
coeffs[0] = 1.0f; /* ACN 0 = 1 */
/* First-order */
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 */
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 */
/* 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 */
@@ -150,8 +193,41 @@ 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*restrict coeffs, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
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;
@@ -166,7 +242,7 @@ void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, AL
gains[i] = 0.0f;
}
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat*restrict 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])
{
ALsizei i;
@@ -176,6 +252,31 @@ 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)
{
@@ -228,28 +329,34 @@ typedef struct ChannelMap {
ChannelConfig Config;
} ChannelMap;
static void SetChannelMap(const enum Channel devchans[MAX_OUTPUT_CHANNELS],
ChannelConfig *ambicoeffs, const ChannelMap *chanmap,
ALsizei count, ALsizei *outcount)
static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs,
const ChannelMap *chanmap, size_t count, ALsizei *outcount)
{
ALsizei maxchans = 0;
ALsizei i, j;
size_t j, k;
ALsizei i;
for(i = 0;i < count;i++)
for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++)
{
ALint idx = GetChannelIndex(devchans, chanmap[i].ChanName);
if(idx < 0)
if(devchans[i] == LFE)
{
ERR("Failed to find %s channel in device\n",
GetLabelFromChannel(chanmap[i].ChanName));
for(j = 0;j < MAX_AMBI_COEFFS;j++)
ambicoeffs[i][j] = 0.0f;
continue;
}
maxchans = maxi(maxchans, idx+1);
for(j = 0;j < MAX_AMBI_COEFFS;j++)
ambicoeffs[idx][j] = chanmap[i].Config[j];
for(j = 0;j < count;j++)
{
if(devchans[i] != chanmap[j].ChanName)
continue;
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 channel map\n", GetLabelFromChannel(devchans[i]), i);
}
*outcount = mini(maxchans, MAX_OUTPUT_CHANNELS);
*outcount = i;
}
static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei speakermap[MAX_OUTPUT_CHANNELS])
@@ -258,8 +365,7 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp
for(i = 0;i < conf->NumSpeakers;i++)
{
enum Channel ch;
int chidx = -1;
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
@@ -282,63 +388,62 @@ static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALsizei sp
* and vice-versa.
*/
if(alstr_cmp_cstr(conf->Speakers[i].Name, "LF") == 0)
ch = FrontLeft;
c = GetChannelIdxByName(device->RealOut, FrontLeft);
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RF") == 0)
ch = FrontRight;
c = GetChannelIdxByName(device->RealOut, FrontRight);
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CE") == 0)
ch = FrontCenter;
c = GetChannelIdxByName(device->RealOut, FrontCenter);
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LS") == 0)
{
if(device->FmtChans == DevFmtX51Rear)
ch = BackLeft;
c = GetChannelIdxByName(device->RealOut, BackLeft);
else
ch = SideLeft;
c = GetChannelIdxByName(device->RealOut, SideLeft);
}
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RS") == 0)
{
if(device->FmtChans == DevFmtX51Rear)
ch = BackRight;
c = GetChannelIdxByName(device->RealOut, BackRight);
else
ch = SideRight;
c = GetChannelIdxByName(device->RealOut, SideRight);
}
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "LB") == 0)
{
if(device->FmtChans == DevFmtX51)
ch = SideLeft;
c = GetChannelIdxByName(device->RealOut, SideLeft);
else
ch = BackLeft;
c = GetChannelIdxByName(device->RealOut, BackLeft);
}
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "RB") == 0)
{
if(device->FmtChans == DevFmtX51)
ch = SideRight;
c = GetChannelIdxByName(device->RealOut, SideRight);
else
ch = BackRight;
c = GetChannelIdxByName(device->RealOut, BackRight);
}
else if(alstr_cmp_cstr(conf->Speakers[i].Name, "CB") == 0)
ch = BackCenter;
c = GetChannelIdxByName(device->RealOut, BackCenter);
else
{
const char *name = alstr_get_cstr(conf->Speakers[i].Name);
unsigned int n;
char c;
char ch;
if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16)
ch = Aux0+n;
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;
}
}
chidx = GetChannelIdxByName(&device->RealOut, ch);
if(chidx == -1)
if(c == -1)
{
ERR("Failed to lookup AmbDec speaker label %s\n",
alstr_get_cstr(conf->Speakers[i].Name));
return false;
}
speakermap[i] = chidx;
speakermap[i] = c;
}
return true;
@@ -348,28 +453,31 @@ 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.52305643e-2f } },
{ FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 5.52305643e-2f } },
{ 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 } },
{ 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[4] = {
{ SideLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } },
{ FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } },
{ FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } },
{ SideRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } },
}, X51RearCfg[4] = {
{ BackLeft, { 3.33000782e-1f, 1.89084803e-1f, 0.0f, -2.00042375e-1f, -2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } },
{ FrontLeft, { 1.88542860e-1f, 1.27709292e-1f, 0.0f, 1.66295695e-1f, 7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } },
{ FrontRight, { 1.88542860e-1f, -1.27709292e-1f, 0.0f, 1.66295695e-1f, -7.30571517e-2f, 0.0f, 0.0f, 0.0f, 2.10901184e-2f } },
{ BackRight, { 3.33000782e-1f, -1.89084803e-1f, 0.0f, -2.00042375e-1f, 2.12307769e-2f, 0.0f, 0.0f, 0.0f, -1.14579885e-2f } },
}, X51SideCfg[5] = {
{ 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] = {
{ 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] = {
{ SideLeft, { 2.04460341e-1f, 2.17177926e-1f, 0.0f, -4.39996780e-2f, -2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } },
{ FrontLeft, { 1.58923161e-1f, 9.21772680e-2f, 0.0f, 1.59658796e-1f, 6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } },
{ FrontRight, { 1.58923161e-1f, -9.21772680e-2f, 0.0f, 1.59658796e-1f, -6.66278083e-2f, 0.0f, 0.0f, 0.0f, 3.84686854e-2f } },
{ SideRight, { 2.04460341e-1f, -2.17177926e-1f, 0.0f, -4.39996780e-2f, 2.60790269e-2f, 0.0f, 0.0f, 0.0f, -6.87239792e-2f } },
{ 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 } },
@@ -380,24 +488,28 @@ 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,
const ALsizei *restrict chans_per_order)
static void InitNearFieldCtrl(ALCdevice *device, ALfloat ctrl_dist, ALsizei order, bool periphonic)
{
const char *devname = alstr_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 can only
* be used when rendering to an ambisonic buffer.
/* 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 = minf(ctrl_dist, 10.0f);
TRACE("Using near-field reference distance: %.2f meters\n", device->AvgSpeakerDist);
device->AvgSpeakerDist = ctrl_dist;
for(i = 0;i < order+1;i++)
device->NumChannelsPerOrder[i] = chans_per_order[i];
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->NumChannelsPerOrder[i] = 0;
device->Dry.NumChannelsPerOrder[i] = 0;
}
}
@@ -405,7 +517,7 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL
{
const char *devname = alstr_get_cstr(device->DeviceName);
ALfloat maxdist = 0.0f;
size_t total = 0;
ALsizei total = 0;
ALsizei i;
for(i = 0;i < conf->NumSpeakers;i++)
@@ -519,7 +631,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) ?*/ N3D2N3DScale;
/*(device->AmbiScale == AmbiNorm_N3D) ?*/ UnitScale;
ALfloat nfc_delay = 0.0f;
count = (device->AmbiOrder == 3) ? 16 :
@@ -542,8 +654,6 @@ 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.
*/
@@ -556,27 +666,14 @@ static void InitPanning(ALCdevice *device)
device->FOAOut.CoeffCount = 0;
device->FOAOut.NumChannels = 4;
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);
ambiup_reset(device->AmbiUp, 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, chans_per_order);
device->AmbiOrder, true);
}
}
else
@@ -587,10 +684,10 @@ static void InitPanning(ALCdevice *device)
chanmap, count, &device->Dry.NumChannels);
device->Dry.CoeffCount = coeffcount;
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;
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 < device->Dry.NumChannels;i++)
@@ -608,7 +705,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 = N3D2N3DScale;
const ALfloat *coeff_scale = UnitScale;
ALfloat w_scale = 1.0f;
ALfloat xyz_scale = 1.0f;
ALsizei i, j;
@@ -621,26 +718,26 @@ static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const A
{
if(conf->ChanMask > 0x1ff)
{
w_scale = W_SCALE_3H3P;
xyz_scale = XYZ_SCALE_3H3P;
w_scale = W_SCALE3D_THIRD;
xyz_scale = XYZ_SCALE3D_THIRD;
}
else if(conf->ChanMask > 0xf)
{
w_scale = W_SCALE_2H2P;
xyz_scale = XYZ_SCALE_2H2P;
w_scale = W_SCALE3D_SECOND;
xyz_scale = XYZ_SCALE3D_SECOND;
}
}
else
{
if(conf->ChanMask > 0x1ff)
{
w_scale = W_SCALE_3H0P;
xyz_scale = XYZ_SCALE_3H0P;
w_scale = W_SCALE2D_THIRD;
xyz_scale = XYZ_SCALE2D_THIRD;
}
else if(conf->ChanMask > 0xf)
{
w_scale = W_SCALE_2H0P;
xyz_scale = XYZ_SCALE_2H0P;
w_scale = W_SCALE2D_SECOND;
xyz_scale = XYZ_SCALE2D_SECOND;
}
}
@@ -692,8 +789,6 @@ 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;
@@ -770,7 +865,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) ? chans_per_order3d : chans_per_order2d
!!(conf->ChanMask&AMBI_PERIPHONIC_MASK)
);
InitDistanceComp(device, conf, speakermap);
@@ -779,93 +874,66 @@ static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALsiz
static void InitHrtfPanning(ALCdevice *device)
{
/* NOTE: azimuth goes clockwise. */
static const struct AngularPoint AmbiPoints[] = {
static const ALfloat AmbiPoints[][2] = {
{ DEG2RAD( 90.0f), DEG2RAD( 0.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( 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( 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.2643897f), DEG2RAD( 45.0f) },
{ DEG2RAD(-35.2643897f), DEG2RAD( 135.0f) },
{ DEG2RAD(-35.2643897f), DEG2RAD(-135.0f) },
{ DEG2RAD(-35.2643897f), 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) },
};
static const ALfloat AmbiMatrixFOA[][MAX_AMBI_COEFFS] = {
{ 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] = {
{ 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 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] = {
3.00000000e+00f, 1.73205081e+00f
}, AmbiOrderHFGainHOA[MAX_AMBI_ORDER+1] = {
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;
const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = device->AmbiUp ? AmbiMatrixHOA :
AmbiMatrixFOA;
ALsizei count = device->AmbiUp ? 9 : 4;
ALsizei i;
static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixFOA), "FOA Ambisonic HRTF mismatch");
static_assert(COUNTOF(AmbiPoints) == COUNTOF(AmbiMatrixHOA), "HOA Ambisonic HRTF mismatch");
if(device->AmbiUp)
{
AmbiMatrix = AmbiMatrixHOA;
AmbiOrderHFGain = AmbiOrderHFGainHOA;
count = COUNTOF(IndexMap);
}
static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small");
device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count));
for(i = 0;i < count;i++)
{
device->Dry.Ambi.Map[i].Scale = 1.0f;
device->Dry.Ambi.Map[i].Index = IndexMap[i];
device->Dry.Ambi.Map[i].Index = i;
}
device->Dry.CoeffCount = 0;
device->Dry.NumChannels = count;
@@ -881,8 +949,7 @@ static void InitHrtfPanning(ALCdevice *device)
device->FOAOut.CoeffCount = 0;
device->FOAOut.NumChannels = 4;
ambiup_reset(device->AmbiUp, device, AmbiOrderHFGainFOA[0] / AmbiOrderHFGain[0],
AmbiOrderHFGainFOA[1] / AmbiOrderHFGain[1]);
ambiup_reset(device->AmbiUp, device);
}
else
{
@@ -893,13 +960,10 @@ 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),
AmbiOrderHFGain
device->Hrtf->IrSize = BuildBFormatHrtf(device->HrtfHandle,
device->Hrtf, device->Dry.NumChannels,
AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints)
);
InitNearFieldCtrl(device, device->HrtfHandle->distance, device->AmbiUp ? 2 : 1,
ChansPerOrder);
}
static void InitUhjPanning(ALCdevice *device)
@@ -942,7 +1006,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->NumChannelsPerOrder[i] = 0;
device->Dry.NumChannelsPerOrder[i] = 0;
device->AvgSpeakerDist = 0.0f;
memset(device->ChannelDelay, 0, sizeof(device->ChannelDelay));
@@ -952,9 +1016,6 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
device->ChannelDelay[i].Length = 0;
}
al_free(device->Stablizer);
device->Stablizer = NULL;
if(device->FmtChans != DevFmtStereo)
{
ALsizei speakermap[MAX_OUTPUT_CHANNELS];
@@ -1005,20 +1066,25 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0))
{
ambiup_free(&device->AmbiUp);
ambiup_free(device->AmbiUp);
device->AmbiUp = NULL;
if(!device->AmbiDecoder)
device->AmbiDecoder = bformatdec_alloc();
}
else
{
bformatdec_free(&device->AmbiDecoder);
if(device->FmtChans != DevFmtAmbi3D || device->AmbiOrder < 2)
ambiup_free(&device->AmbiUp);
else
bformatdec_free(device->AmbiDecoder);
device->AmbiDecoder = NULL;
if(device->FmtChans == DevFmtAmbi3D && device->AmbiOrder > 1)
{
if(!device->AmbiUp)
device->AmbiUp = ambiup_alloc();
}
else
{
ambiup_free(device->AmbiUp);
device->AmbiUp = NULL;
}
}
if(!pconf)
@@ -1028,48 +1094,12 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
else
InitCustomPanning(device, pconf, speakermap);
/* Enable the stablizer only for formats that have front-left, front-
* right, and front-center outputs.
*/
switch(device->FmtChans)
{
case DevFmtX51:
case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
if(GetConfigValueBool(devname, NULL, "front-stablizer", 0))
{
/* Initialize band-splitting filters for the front-left and
* front-right channels, with a crossover at 5khz (could be
* higher).
*/
ALfloat scale = (ALfloat)(5000.0 / device->Frequency);
FrontStablizer *stablizer = al_calloc(16, sizeof(*stablizer));
bandsplit_init(&stablizer->LFilter, scale);
stablizer->RFilter = stablizer->LFilter;
/* Initialize all-pass filters for all other channels. */
splitterap_init(&stablizer->APFilter[0], scale);
for(i = 1;i < (size_t)device->RealOut.NumChannels;i++)
stablizer->APFilter[i] = stablizer->APFilter[0];
device->Stablizer = stablizer;
}
break;
case DevFmtMono:
case DevFmtStereo:
case DevFmtQuad:
case DevFmtAmbi3D:
break;
}
TRACE("Front stablizer %s\n", device->Stablizer ? "enabled" : "disabled");
ambdec_deinit(&conf);
return;
}
bformatdec_free(&device->AmbiDecoder);
bformatdec_free(device->AmbiDecoder);
device->AmbiDecoder = NULL;
headphones = device->IsHeadphones;
if(device->Type != Loopback)
@@ -1161,7 +1191,8 @@ 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);
ambiup_free(device->AmbiUp);
device->AmbiUp = NULL;
}
else
{
@@ -1186,7 +1217,8 @@ no_hrtf:
device->Render_Mode = StereoPair;
ambiup_free(&device->AmbiUp);
ambiup_free(device->AmbiUp);
device->AmbiUp = NULL;
bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) ||
(hrtf_appreq == Hrtf_Enable)) ? 5 : 0;
-105
View File
@@ -1,105 +0,0 @@
#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))
#endif /* POLYMORPHISM_H */
-77
View File
@@ -1,77 +0,0 @@
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ll_ringbuffer ll_ringbuffer_t;
typedef struct ll_ringbuffer_data {
char *buf;
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);
/**
* 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);
/**
* 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);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* RINGBUFFER_H */
+47 -33
View File
@@ -9,29 +9,36 @@
#define MAX_UPDATE_SAMPLES 128
static const ALfloat Filter1CoeffSqr[4] = {
0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f
static const ALfloat Filter1Coeff[4] = {
0.6923878f, 0.9360654322959f, 0.9882295226860f, 0.9987488452737f
};
static const ALfloat Filter2CoeffSqr[4] = {
0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f
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, ALsizei todo)
{
ALfloat z1 = state->z[0];
ALfloat z2 = state->z[1];
ALsizei i;
for(i = 0;i < todo;i++)
if(todo > 1)
{
ALfloat input = src[i];
ALfloat output = input*aa + z1;
z1 = z2; z2 = output*aa - input;
dst[i] = output;
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];
}
state->z[0] = z1;
state->z[1] = z2;
}
@@ -61,37 +68,41 @@ 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);
ASSUME(todo > 0);
/* 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], 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);
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->LastY;
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];
enc->LastY = temp[0][i-1];
/* D += j(-0.3420201*W + 0.5098604*X) */
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], 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);
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];
@@ -99,14 +110,17 @@ 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], 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);
allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo);
S[0] = enc->LastWX;
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];
enc->LastWX = temp[0][i-1];
/* Left = (S + D)/2.0 */
for(i = 0;i < todo;i++)
+3 -3
View File
@@ -6,7 +6,8 @@
#include "alMain.h"
typedef struct AllPassState {
ALfloat z[2];
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:
@@ -35,10 +36,9 @@ 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
+1 -2
View File
@@ -37,8 +37,7 @@ typedef const _##N* const_##N;
\
if(((_x) ? (_x)->Capacity : 0) < _cap) \
{ \
ptrdiff_t data_offset = (_x) ? (char*)((_x)->Data) - (char*)(_x) : \
sizeof(*(_x)); \
ptrdiff_t data_offset = (char*)((_x)->Data) - (char*)(_x); \
size_t old_size = ((_x) ? (_x)->Size : 0); \
void *temp; \
\
+299 -489
View File
File diff suppressed because it is too large Load Diff
+52 -8
View File
@@ -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,3 +435,47 @@ 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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-67
View File
@@ -1,70 +1,3 @@
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.
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.
Implemented the Pitch Shifter, Frequency Shifter, and Autowah effects.
Fixed compiling on FreeBSD systems that use freebsd-lib 9.1.
Fixed compiling on NetBSD.
Fixed the reverb effect's density scale and panning parameters.
Fixed use of the WASAPI backend with certain games, which caused odd COM
initialization errors.
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.
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.
Added an SDL2 playback backend. Disabled by default to avoid a dependency
on SDL2.
Improved the performance and quality of the Chorus and Flanger effects.
Improved the efficiency of the band-limited Sinc resampler.
Improved the Sinc resampler's transition band to avoid over-attenuating
higher frequencies.
Improved the performance of some filter operations.
Improved the efficiency of object ID lookups.
Improved the efficienty of internal voice/source synchronization.
Improved AL call error logging with contextualized messages.
Removed the reverb effect's modulation stage. Due to the lack of reference
for its intended behavior and strength.
openal-soft-1.18.2:
Fixed resetting the FPU rounding mode after certain function calls on
+46 -41
View File
@@ -29,21 +29,16 @@ struct ALeffectStateVtable {
void (*const Destruct)(ALeffectState *state);
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props);
void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
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*) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \
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)); } \
@@ -59,22 +54,21 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
}
struct EffectStateFactoryVtable;
struct ALeffectStateFactoryVtable;
typedef struct EffectStateFactory {
const struct EffectStateFactoryVtable *vtab;
} EffectStateFactory;
typedef struct ALeffectStateFactory {
const struct ALeffectStateFactoryVtable *vtbl;
} ALeffectStateFactory;
struct EffectStateFactoryVtable {
ALeffectState *(*const create)(EffectStateFactory *factory);
struct ALeffectStateFactoryVtable {
ALeffectState *(*const create)(ALeffectStateFactory *factory);
};
#define EffectStateFactory_create(x) ((x)->vtab->create((x)))
#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T) \
DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create) \
#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T) \
DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create) \
\
static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \
T##_EffectStateFactory_create, \
static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
T##_ALeffectStateFactory_create, \
}
@@ -116,18 +110,17 @@ typedef struct ALeffectslot {
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 DecayLFRatio;
ALfloat DecayHFRatio;
ALboolean DecayHFLimit;
ALfloat AirAbsorptionGainHF;
@@ -140,43 +133,55 @@ 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 * sqrt(3)
* * Channel 2 is OpenAL Y * sqrt(3)
* * Channel 3 is OpenAL -Z * sqrt(3)
* * 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 make a B-Format source pan for first-order device
* output (FOAOut).
* ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
* first-order device output (FOAOut).
*/
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);
void UpdateEffectSlotProps(ALeffectslot *slot);
void UpdateAllEffectSlotProps(ALCcontext *context);
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);
EffectStateFactory *EchoStateFactory_getFactory(void);
EffectStateFactory *EqualizerStateFactory_getFactory(void);
EffectStateFactory *FlangerStateFactory_getFactory(void);
EffectStateFactory *FshifterStateFactory_getFactory(void);
EffectStateFactory *ModulatorStateFactory_getFactory(void);
EffectStateFactory *PshifterStateFactory_getFactory(void);
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 *DedicatedStateFactory_getFactory(void);
ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
void ALeffectState_DecRef(ALeffectState *state);
void InitEffectFactoryMap(void);
void DeinitEffectFactoryMap(void);
#ifdef __cplusplus
}
+52 -39
View File
@@ -1,13 +1,7 @@
#ifndef _AL_BUFFER_H_
#define _AL_BUFFER_H_
#include "AL/alc.h"
#include "AL/al.h"
#include "AL/alext.h"
#include "inprogext.h"
#include "atomic.h"
#include "rwlock.h"
#include "alMain.h"
#ifdef __cplusplus
extern "C" {
@@ -15,25 +9,29 @@ extern "C" {
/* User formats */
enum UserFmtType {
UserFmtUByte,
UserFmtShort,
UserFmtFloat,
UserFmtDouble,
UserFmtMulaw,
UserFmtAlaw,
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 = AL_MULAW_SOFT,
UserFmtAlaw = 0x10000000,
UserFmtIMA4,
UserFmtMSADPCM,
};
enum UserFmtChannels {
UserFmtMono,
UserFmtStereo,
UserFmtRear,
UserFmtQuad,
UserFmtX51, /* (WFX order) */
UserFmtX61, /* (WFX order) */
UserFmtX71, /* (WFX order) */
UserFmtBFormat2D, /* 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 */
};
ALsizei BytesFromUserFmt(enum UserFmtType type);
@@ -46,12 +44,9 @@ inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType
/* Storable formats */
enum FmtType {
FmtUByte = UserFmtUByte,
FmtShort = UserFmtShort,
FmtFloat = UserFmtFloat,
FmtDouble = UserFmtDouble,
FmtMulaw = UserFmtMulaw,
FmtAlaw = UserFmtAlaw,
FmtByte = UserFmtByte,
FmtShort = UserFmtShort,
FmtFloat = UserFmtFloat,
};
enum FmtChannels {
FmtMono = UserFmtMono,
@@ -77,17 +72,18 @@ inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
typedef struct ALbuffer {
ALvoid *data;
ALsizei Frequency;
ALbitfieldSOFT Access;
ALsizei SampleLen;
ALsizei Frequency;
ALenum Format;
ALsizei SampleLen;
enum FmtChannels FmtChannels;
enum FmtType FmtType;
ALsizei BytesAlloc;
ALuint BytesAlloc;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
enum UserFmtChannels OriginalChannels;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
ALsizei LoopStart;
ALsizei LoopEnd;
@@ -95,17 +91,34 @@ typedef struct ALbuffer {
ATOMIC(ALsizei) UnpackAlign;
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;
RWLock lock;
/* Self ID */
ALuint id;
} 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)
{ 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); }
ALvoid ReleaseALBuffers(ALCdevice *device);
#ifdef __cplusplus
+37 -54
View File
@@ -10,34 +10,23 @@ extern "C" {
struct ALeffect;
enum {
EAXREVERB_EFFECT = 0,
REVERB_EFFECT,
AUTOWAH_EFFECT,
CHORUS_EFFECT,
COMPRESSOR_EFFECT,
DISTORTION_EFFECT,
ECHO_EFFECT,
EQUALIZER_EFFECT,
FLANGER_EFFECT,
FSHIFTER_EFFECT,
MODULATOR_EFFECT,
PSHIFTER_EFFECT,
DEDICATED_EFFECT,
AL__EAXREVERB = 0,
AL__REVERB,
AL__CHORUS,
AL__COMPRESSOR,
AL__DISTORTION,
AL__ECHO,
AL__EQUALIZER,
AL__FLANGER,
AL__MODULATOR,
AL__DEDICATED,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
extern ALfloat ReverbBoost;
struct EffectList {
const char name[16];
int type;
ALenum val;
};
#define EFFECTLIST_SIZE 14
extern const struct EffectList EffectList[EFFECTLIST_SIZE];
extern ALboolean EmulateEAXReverb;
struct ALeffectVtable {
void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
@@ -61,17 +50,14 @@ 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;
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;
extern const struct ALeffectVtable ALdedicated_vtable;
@@ -105,13 +91,6 @@ typedef union ALeffectProps {
ALfloat LFReference;
} Reverb;
struct {
ALfloat AttackTime;
ALfloat ReleaseTime;
ALfloat Resonance;
ALfloat PeakGain;
} Autowah;
struct {
ALint Waveform;
ALint Phase;
@@ -119,7 +98,7 @@ typedef union ALeffectProps {
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Chorus; /* Also Flanger */
} Chorus;
struct {
ALboolean OnOff;
@@ -157,10 +136,13 @@ typedef union ALeffectProps {
} Equalizer;
struct {
ALfloat Frequency;
ALint LeftDirection;
ALint RightDirection;
} Fshifter;
ALint Waveform;
ALint Phase;
ALfloat Rate;
ALfloat Depth;
ALfloat Feedback;
ALfloat Delay;
} Flanger;
struct {
ALfloat Frequency;
@@ -168,11 +150,6 @@ typedef union ALeffectProps {
ALint Waveform;
} Modulator;
struct {
ALint CoarseTune;
ALint FineTune;
} Pshifter;
struct {
ALfloat Gain;
} Dedicated;
@@ -184,27 +161,33 @@ typedef struct ALeffect {
ALeffectProps Props;
const struct ALeffectVtable *vtab;
const struct ALeffectVtable *vtbl;
/* 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 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; }
void InitEffect(ALeffect *effect);
void ReleaseALEffects(ALCdevice *device);
ALenum InitEffect(ALeffect *effect);
ALvoid ReleaseALEffects(ALCdevice *device);
void LoadReverbPreset(const char *name, ALeffect *effect);
ALvoid LoadReverbPreset(const char *name, ALeffect *effect);
#ifdef __cplusplus
}
+12 -8
View File
@@ -2,7 +2,6 @@
#define _AL_ERROR_H_
#include "alMain.h"
#include "logging.h"
#ifdef __cplusplus
extern "C" {
@@ -10,16 +9,21 @@ extern "C" {
extern ALboolean TrapALError;
void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
#define SETERR_GOTO(ctx, err, lbl, ...) do { \
alSetError((ctx), (err), __VA_ARGS__); \
goto lbl; \
#define SET_ERROR_AND_RETURN(ctx, err) do { \
alSetError((ctx), (err)); \
return; \
} while(0)
#define SETERR_RETURN(ctx, err, retval, ...) do { \
alSetError((ctx), (err), __VA_ARGS__); \
return retval; \
#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do { \
alSetError((ctx), (err)); \
return (val); \
} while(0)
#define SET_ERROR_AND_GOTO(ctx, err, lbl) do { \
alSetError((ctx), (err)); \
goto lbl; \
} while(0)
#ifdef __cplusplus
+126 -29
View File
@@ -1,8 +1,9 @@
#ifndef _AL_FILTER_H_
#define _AL_FILTER_H_
#include "AL/alc.h"
#include "AL/al.h"
#include "alMain.h"
#include "math_defs.h"
#ifdef __cplusplus
extern "C" {
@@ -12,27 +13,99 @@ extern "C" {
#define HIGHPASSFREQREF (250.0f)
struct ALfilter;
/* 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 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);
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,
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;
/** 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;
#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 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.
* 0 < gain
* 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.
*/
inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
{
ALfloat w0 = F_TAU * freq_mult;
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;
}
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)
{
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 {
// Filter type (AL_FILTER_NULL, ...)
@@ -44,21 +117,45 @@ typedef struct ALfilter {
ALfloat GainLF;
ALfloat LFReference;
const struct ALfilterVtable *vtab;
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);
/* 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);
#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)
{ 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);
#ifdef __cplusplus
}
+14 -15
View File
@@ -8,23 +8,19 @@
extern "C" {
#endif
struct ALcontextProps {
ALfloat DopplerFactor;
ALfloat DopplerVelocity;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
ALfloat MetersPerUnit;
ATOMIC(struct ALcontextProps*) next;
};
struct ALlistenerProps {
ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat DopplerVelocity;
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
ATOMIC(struct ALlistenerProps*) next;
};
@@ -35,13 +31,17 @@ typedef struct ALlistener {
ALfloat Forward[3];
ALfloat Up[3];
ALfloat Gain;
ATOMIC_FLAG PropsClean;
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 {
aluMatrixf Matrix;
aluVector Velocity;
@@ -50,8 +50,7 @@ typedef struct ALlistener {
ALfloat MetersPerUnit;
ALfloat DopplerFactor;
ALfloat SpeedOfSound; /* in units per sec! */
ALfloat ReverbSpeedOfSound; /* in meters per sec! */
ALfloat SpeedOfSound;
ALboolean SourceDistanceModel;
enum DistanceModel DistanceModel;
+558 -393
View File
File diff suppressed because it is too large Load Diff
+17 -9
View File
@@ -19,10 +19,8 @@ struct ALsource;
typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
ATOMIC(struct ALbufferlistitem*) next;
ALsizei max_samples;
ALsizei num_buffers;
struct ALbuffer *buffers[];
} ALbufferlistitem;
@@ -93,22 +91,32 @@ typedef struct ALsource {
ALint SourceType;
/** Source state (initial, playing, paused, or stopped) */
ALenum state;
ATOMIC(ALenum) state;
/** Source Buffer Queue head. */
RWLock queue_lock;
ALbufferlistitem *queue;
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;
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);
+20
View File
@@ -0,0 +1,20 @@
#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
+99 -117
View File
@@ -12,27 +12,28 @@
#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"
#include "filters/nfc.h"
#define MAX_PITCH (255)
/* 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
/* Maximum number of buffer samples before the current pos needed for resampling. */
#define MAX_PRE_SAMPLES 12
/* Maximum number of buffer samples after the current pos needed for resampling. */
#define MAX_POST_SAMPLES 12
#ifdef __cplusplus
extern "C" {
#endif
struct BSincTable;
struct ALsource;
struct ALbufferlistitem;
struct ALvoice;
@@ -52,16 +53,13 @@ enum Resampler {
PointResampler,
LinearResampler,
FIR4Resampler,
BSinc12Resampler,
BSinc24Resampler,
BSincResampler,
ResamplerMax = BSinc24Resampler
ResamplerMax = BSincResampler
};
extern enum Resampler ResamplerDefault;
/* The number of distinct scale and phase intervals within the bsinc filter
* table.
*/
/* The number of distinct scale and phase intervals within the filter table. */
#define BSINC_SCALE_BITS 4
#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
#define BSINC_PHASE_BITS 4
@@ -73,29 +71,27 @@ extern enum Resampler ResamplerDefault;
*/
typedef struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
ALsizei m; /* Coefficient count. */
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.
*/
const ALfloat *filter;
ALuint m; /* Coefficient count. */
ALint l; /* Left coefficient offset. */
struct {
const ALfloat *filter; /* Filter coefficients. */
const ALfloat *scDelta; /* Scale deltas. */
const ALfloat *phDelta; /* Phase deltas. */
const ALfloat *spDelta; /* Scale-phase deltas. */
} coeffs[BSINC_PHASE_COUNT];
} BsincState;
typedef union InterpState {
BsincState bsinc;
} InterpState;
ALboolean BsincPrepare(const ALuint increment, BsincState *state);
typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen
);
void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table);
extern const struct BSincTable bsinc12;
extern const struct BSincTable bsinc24;
typedef union aluVector {
alignas(16) ALfloat v[4];
@@ -153,10 +149,10 @@ typedef struct MixHrtfParams {
typedef struct DirectParams {
BiquadFilter LowPass;
BiquadFilter HighPass;
ALfilterState LowPass;
ALfilterState HighPass;
NfcFilter NFCtrlFilter;
NfcFilter NFCtrlFilter[MAX_AMBI_ORDER];
struct {
HrtfParams Old;
@@ -171,8 +167,8 @@ typedef struct DirectParams {
} DirectParams;
typedef struct SendParams {
BiquadFilter LowPass;
BiquadFilter HighPass;
ALfilterState LowPass;
ALfilterState HighPass;
struct {
ALfloat Current[MAX_OUTPUT_CHANNELS];
@@ -235,15 +231,16 @@ struct ALvoiceProps {
} Send[];
};
#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)
/* 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)
typedef struct ALvoice {
struct ALvoiceProps *Props;
ATOMIC(struct ALvoiceProps*) Update;
ATOMIC(struct ALvoiceProps*) FreeList;
ATOMIC(struct ALsource*) Source;
ATOMIC(bool) Playing;
@@ -280,7 +277,7 @@ typedef struct ALvoice {
ALuint Offset; /* Number of output samples mixed since starting. */
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
InterpState ResampleState;
@@ -384,26 +381,19 @@ 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)); }
extern alignas(16) const ALfloat bsincTab[18840];
extern alignas(16) const ALfloat sinc4Tab[FRACTIONONE][4];
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALsizei frac)
{
ALfloat mu2 = mu*mu, mu3 = mu2*mu;
ALfloat a0 = -0.5f*mu3 + mu2 + -0.5f*mu;
ALfloat a1 = 1.5f*mu3 + -2.5f*mu2 + 1.0f;
ALfloat a2 = -1.5f*mu3 + 2.0f*mu2 + 0.5f*mu;
ALfloat a3 = 0.5f*mu3 + -0.5f*mu2;
return val1*a0 + val2*a1 + val3*a2 + val4*a3;
return sinc4Tab[frac][0]*val0 + sinc4Tab[frac][1]*val1 +
sinc4Tab[frac][2]*val2 + sinc4Tab[frac][3]*val3;
}
@@ -413,10 +403,10 @@ enum HrtfRequestMode {
Hrtf_Disable = 2,
};
void aluInit(void);
void aluInitMixer(void);
MixerFunc SelectMixer(void);
RowMixerFunc SelectRowMixer(void);
ResamplerFunc SelectResampler(enum Resampler resampler);
/* aluInitRenderer
@@ -428,37 +418,14 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
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 an OpenAL 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 a direction vector. The vector
* must be normalized (unit length), and the spread is the angular width of the
* sound (0...tau).
*/
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);
}
void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* CalcAngleCoeffs
@@ -469,63 +436,78 @@ inline void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat co
*/
inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
{
ALfloat x = -sinf(azimuth) * cosf(elevation);
ALfloat y = sinf(elevation);
ALfloat z = cosf(azimuth) * cosf(elevation);
CalcAmbiCoeffs(x, y, z, spread, coeffs);
ALfloat dir[3] = {
sinf(azimuth) * cosf(elevation),
sinf(elevation),
-cosf(azimuth) * cosf(elevation)
};
CalcDirectionCoeffs(dir, spread, coeffs);
}
/**
* ScaleAzimuthFront
* CalcAnglePairwiseCoeffs
*
* Scales the given azimuth toward the side (+/- pi/2 radians) for positions in
* front.
* 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.
*/
inline float ScaleAzimuthFront(float azimuth, float scale)
{
ALfloat sign = copysignf(1.0f, azimuth);
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*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]);
void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
/**
* ComputePanGains
* 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]);
/**
* ComputePanningGains
*
* Computes panning gains using the given channel decoder coefficients and the
* 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.
* pre-calculated direction or angle coefficients.
*/
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,
coeffs, ingain, gains);
else
ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains);
}
#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]);
/**
* 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.
*/
#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]);
ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo);
void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
/* Caller must lock the device, and the mixer must not be running. */
void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3);
void UpdateContextProps(ALCcontext *context);
extern MixerFunc MixSamples;
extern RowMixerFunc MixRowSamples;
/* Caller must lock the device. */
void aluHandleDisconnect(ALCdevice *device);
extern ALfloat ConeScale;
extern ALfloat ZScale;
extern ALboolean OverrideReverbSpeedOfSound;
#ifdef __cplusplus
}
+1 -7
View File
@@ -4,12 +4,6 @@
#include "AL/al.h"
#include "alBuffer.h"
extern const ALshort muLawDecompressionTable[256];
extern const ALshort aLawDecompressionTable[256];
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);
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align);
#endif /* SAMPLE_CVT_H */
+207 -282
View File
@@ -27,81 +27,36 @@
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#include "fpu_modes.h"
#include "almalloc.h"
extern inline void LockEffectSlotList(ALCcontext *context);
extern inline void UnlockEffectSlotList(ALCcontext *context);
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 void AddActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
static void RemoveActiveEffectSlots(const ALuint *slotids, ALsizei count, ALCcontext *context);
static const struct {
ALenum Type;
EffectStateFactory* (*GetFactory)(void);
} FactoryList[] = {
{ 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 },
{ 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 },
{ AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory }
};
static inline EffectStateFactory *getFactoryByType(ALenum type)
static UIntMap EffectStateFactoryMap;
static inline ALeffectStateFactory *getFactoryByType(ALenum type)
{
size_t i;
for(i = 0;i < COUNTOF(FactoryList);i++)
{
if(FactoryList[i].Type == type)
return FactoryList[i].GetFactory();
}
ALeffectStateFactory* (*getFactory)(void) = LookupUIntMapKey(&EffectStateFactoryMap, type);
if(getFactory != NULL)
return getFactory();
return NULL;
}
static void ALeffectState_IncRef(ALeffectState *state);
static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
{
id--;
if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList)))
return NULL;
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)<<slidx)))
return NULL;
return sublist->Effects + slidx;
}
static void ALeffectState_DecRef(ALeffectState *state);
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateEffectSlotProps(slot, context); \
UpdateEffectSlotProps(slot); \
else \
ATOMIC_FLAG_CLEAR(&slot->PropsClean, almemory_order_release); \
} while(0)
@@ -109,63 +64,77 @@ 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;
ALenum err;
context = GetContextRef();
if(!context) return;
if(!(n >= 0))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Generating %d effect slots", n);
if(n == 0) goto done;
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
tmpslots = al_malloc(DEF_ALIGN, sizeof(ALeffectslot*)*n);
LockEffectSlotList(context);
device = context->Device;
LockEffectSlotsWrite(context);
for(cur = 0;cur < n;cur++)
{
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++)
{
if(!*iter)
break;
}
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);
}
slot = al_calloc(16, sizeof(ALeffectslot));
ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
err = AL_OUT_OF_MEMORY;
if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
{
al_free(slot);
UnlockEffectSlotList(context);
UnlockEffectSlotsWrite(context);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SETERR_GOTO(context, err, done, "Effect slot object allocation failed");
SET_ERROR_AND_GOTO(context, err, done);
}
err = NewThunkEntry(&slot->id);
if(err == AL_NO_ERROR)
err = InsertUIntMapEntryNoLock(&context->EffectSlotMap, slot->id, slot);
if(err != 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);
alDeleteAuxiliaryEffectSlots(cur, effectslots);
SET_ERROR_AND_GOTO(context, err, done);
}
aluInitEffectPanning(slot);
slot->id = (iter - VECTOR_BEGIN(context->EffectSlotList)) + 1;
*iter = slot;
tmpslots[cur] = slot;
effectslots[cur] = slot->id;
}
AddActiveEffectSlots(effectslots, n, context);
UnlockEffectSlotList(context);
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);
}
UnlockEffectSlotsWrite(context);
done:
al_free(tmpslots);
ALCcontext_DecRef(context);
}
@@ -178,28 +147,54 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsWrite(context);
if(!(n >= 0))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n);
if(n == 0) goto done;
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u",
effectslots[i]);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(ReadRef(&slot->ref) != 0)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u",
effectslots[i]);
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
// All effectslots are valid
RemoveActiveEffectSlots(effectslots, n, context);
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);
}
for(i = 0;i < n;i++)
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
if((slot=RemoveEffectSlot(context, effectslots[i])) == NULL)
continue;
VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL;
FreeThunkEntry(slot->id);
DeinitEffectSlot(slot);
@@ -208,7 +203,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsWrite(context);
ALCcontext_DecRef(context);
}
@@ -220,9 +215,9 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
context = GetContextRef();
if(!context) return AL_FALSE;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
ret = (LookupEffectSlot(context, effectslot) ? AL_TRUE : AL_FALSE);
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
@@ -240,45 +235,43 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
LockEffectSlotList(context);
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_EFFECT:
device = context->Device;
LockEffectList(device);
LockEffectsRead(device);
effect = (value ? LookupEffect(device, value) : NULL);
if(!(value == 0 || effect != NULL))
{
UnlockEffectList(device);
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Invalid effect ID %u", value);
UnlockEffectsRead(device);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
err = InitializeEffect(context, slot, effect);
UnlockEffectList(device);
err = InitializeEffect(device, slot, effect);
UnlockEffectsRead(device);
if(err != AL_NO_ERROR)
SETERR_GOTO(context, err, done, "Effect initialization failed");
SET_ERROR_AND_GOTO(context, err, done);
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
if(!(value == AL_TRUE || value == AL_FALSE))
SETERR_GOTO(context, AL_INVALID_VALUE, done,
"Effect slot auxiliary send auto out of range");
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->AuxSendAuto = value;
break;
default:
SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot integer property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotList(context);
almtx_unlock(&context->PropLock);
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -297,18 +290,17 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
@@ -320,27 +312,26 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
LockEffectSlotList(context);
WriteLock(&context->PropLock);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
if(!(value >= 0.0f && value <= 1.0f))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Effect slot gain out of range");
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->Gain = value;
break;
default:
SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid effect slot float property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
DO_UPDATEPROPS();
done:
UnlockEffectSlotList(context);
almtx_unlock(&context->PropLock);
UnlockEffectSlotsRead(context);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -358,18 +349,17 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
@@ -381,9 +371,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
@@ -391,11 +381,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer property 0x%04x", param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
@@ -414,18 +404,17 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot integer-vector property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
@@ -437,9 +426,9 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if((slot=LookupEffectSlot(context, effectslot)) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_EFFECTSLOT_GAIN:
@@ -447,11 +436,11 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float property 0x%04x", param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
@@ -469,32 +458,54 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p
context = GetContextRef();
if(!context) return;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
if(LookupEffectSlot(context, effectslot) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslot);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid effect slot float-vector property 0x%04x",
param);
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
done:
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
ALCcontext_DecRef(context);
}
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
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(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALCdevice *Device = Context->Device;
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
struct ALeffectslotProps *props;
ALeffectState *State;
if(newtype != EffectSlot->Effect.Type)
{
EffectStateFactory *factory;
ALeffectStateFactory *factory;
factory = getFactoryByType(newtype);
if(!factory)
@@ -502,7 +513,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 = EffectStateFactory_create(factory);
State = V0(factory,create)();
if(!State) return AL_OUT_OF_MEMORY;
START_MIXER_MODE();
@@ -537,7 +548,7 @@ ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect
EffectSlot->Effect.Props = effect->Props;
/* Remove state references from old effect slot property updates. */
props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
props = ATOMIC_LOAD_SEQ(&EffectSlot->FreeList);
while(props)
{
if(props->State)
@@ -557,7 +568,7 @@ static void ALeffectState_IncRef(ALeffectState *state)
TRACEREF("%p increasing refcount to %u\n", state, ref);
}
void ALeffectState_DecRef(ALeffectState *state)
static void ALeffectState_DecRef(ALeffectState *state)
{
uint ref;
ref = DecrementRef(&state->Ref);
@@ -579,103 +590,15 @@ 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(UNLIKELY(newarray->slot[i] == newarray->slot[--j]))
{
newcount--;
for(j = i;j < newcount;j++)
newarray->slot[j] = newarray->slot[j+1];
i--;
break;
}
}
}
/* 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))
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;
ALCdevice *device = context->Device;
ALsizei i, j;
/* 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++)
{
/* 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[--j])
goto skip_ins;
}
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();
al_free(curarray);
}
ALenum InitEffectSlot(ALeffectslot *slot)
{
EffectStateFactory *factory;
ALeffectStateFactory *factory;
slot->Effect.Type = AL_EFFECT_NULL;
factory = getFactoryByType(AL_EFFECT_NULL);
slot->Effect.State = EffectStateFactory_create(factory);
if(!slot->Effect.State) return AL_OUT_OF_MEMORY;
if(!(slot->Effect.State=V0(factory,create)()))
return AL_OUT_OF_MEMORY;
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
@@ -683,6 +606,7 @@ ALenum InitEffectSlot(ALeffectslot *slot)
InitRef(&slot->ref, 0);
ATOMIC_INIT(&slot->Update, NULL);
ATOMIC_INIT(&slot->FreeList, NULL);
slot->Params.Gain = 1.0f;
slot->Params.AuxSendAuto = AL_TRUE;
@@ -690,7 +614,6 @@ 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;
@@ -701,6 +624,7 @@ ALenum InitEffectSlot(ALeffectslot *slot)
void DeinitEffectSlot(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
size_t count = 0;
props = ATOMIC_LOAD_SEQ(&slot->Update);
if(props)
@@ -709,19 +633,29 @@ void DeinitEffectSlot(ALeffectslot *slot)
TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
al_free(props);
}
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
while(props)
{
struct ALeffectslotProps *next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
if(props->State) ALeffectState_DecRef(props->State);
al_free(props);
props = next;
++count;
}
TRACE("Freed "SZFMT" AuxiliaryEffectSlot property object%s\n", count, (count==1)?"":"s");
ALeffectState_DecRef(slot->Effect.State);
if(slot->Params.EffectState)
ALeffectState_DecRef(slot->Params.EffectState);
}
void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
void UpdateEffectSlotProps(ALeffectslot *slot)
{
struct ALeffectslotProps *props;
ALeffectState *oldstate;
/* Get an unused property container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&context->FreeEffectslotProps, almemory_order_relaxed);
props = ATOMIC_LOAD(&slot->FreeList, almemory_order_relaxed);
if(!props)
props = al_calloc(16, sizeof(*props));
else
@@ -729,7 +663,7 @@ void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context)
struct ALeffectslotProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeEffectslotProps, &props, next,
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&slot->FreeList, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
@@ -753,10 +687,7 @@ 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);
ATOMIC_REPLACE_HEAD(struct ALeffectslotProps*, &slot->FreeList, props);
}
if(oldstate)
@@ -768,35 +699,29 @@ void UpdateAllEffectSlotProps(ALCcontext *context)
struct ALeffectslotArray *auxslots;
ALsizei i;
LockEffectSlotList(context);
LockEffectSlotsRead(context);
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, context);
UpdateEffectSlotProps(slot);
}
UnlockEffectSlotList(context);
UnlockEffectSlotsRead(context);
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *context)
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
{
ALeffectslotPtr *iter = VECTOR_BEGIN(context->EffectSlotList);
ALeffectslotPtr *end = VECTOR_END(context->EffectSlotList);
size_t leftover = 0;
for(;iter != end;iter++)
ALsizei pos;
for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
{
ALeffectslot *slot = *iter;
if(!slot) continue;
*iter = NULL;
ALeffectslot *temp = Context->EffectSlotMap.values[pos];
Context->EffectSlotMap.values[pos] = NULL;
DeinitEffectSlot(slot);
DeinitEffectSlot(temp);
memset(slot, 0, sizeof(*slot));
al_free(slot);
++leftover;
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffectslot));
al_free(temp);
}
if(leftover > 0)
WARN("(%p) Deleted "SZFMT" AuxiliaryEffectSlot%s\n", context, leftover, (leftover==1)?"":"s");
}
+711 -607
View File
File diff suppressed because it is too large Load Diff
+112 -215
View File
@@ -28,53 +28,26 @@
#include "AL/alc.h"
#include "alMain.h"
#include "alEffect.h"
#include "alThunk.h"
#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 },
{ "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
{ "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 },
{ "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 },
{ "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
};
ALboolean DisabledEffects[MAX_EFFECTS];
static ALeffect *AllocEffect(ALCcontext *context);
static void FreeEffect(ALCdevice *device, ALeffect *effect);
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 void InitEffectParams(ALeffect *effect, ALenum type);
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)<<slidx)))
return NULL;
return sublist->Effects + slidx;
}
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
ALCdevice *device;
ALCcontext *context;
ALsizei cur;
@@ -82,18 +55,37 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
if(!context) return;
if(!(n >= 0))
alSetError(context, AL_INVALID_VALUE, "Generating %d effects", n);
else for(cur = 0;cur < n;cur++)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
{
ALeffect *effect = AllocEffect(context);
if(!effect)
ALeffect *effect = al_calloc(16, sizeof(ALeffect));
ALenum err = AL_OUT_OF_MEMORY;
if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR)
{
al_free(effect);
alDeleteEffects(cur, effects);
break;
SET_ERROR_AND_GOTO(context, err, done);
}
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);
SET_ERROR_AND_GOTO(context, err, done);
}
effects[cur] = effect->id;
}
done:
ALCcontext_DecRef(context);
}
@@ -108,22 +100,26 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
if(!context) return;
device = context->Device;
LockEffectList(device);
LockEffectsWrite(device);
if(!(n >= 0))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effects", n);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if(effects[i] && LookupEffect(device, effects[i]) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect ID %u", effects[i]);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
}
for(i = 0;i < n;i++)
{
if((effect=LookupEffect(device, effects[i])) != NULL)
FreeEffect(device, effect);
if((effect=RemoveEffect(device, effects[i])) == NULL)
continue;
FreeThunkEntry(effect->id);
memset(effect, 0, sizeof(*effect));
al_free(effect);
}
done:
UnlockEffectList(device);
UnlockEffectsWrite(device);
ALCcontext_DecRef(context);
}
@@ -135,10 +131,10 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockEffectList(Context->Device);
LockEffectsRead(Context->Device);
result = ((!effect || LookupEffect(Context->Device, effect)) ?
AL_TRUE : AL_FALSE);
UnlockEffectList(Context->Device);
UnlockEffectsRead(Context->Device);
ALCcontext_DecRef(Context);
@@ -155,16 +151,16 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_EFFECT_TYPE)
{
ALboolean isOk = (value == AL_EFFECT_NULL);
ALint i;
for(i = 0;!isOk && i < EFFECTLIST_SIZE;i++)
for(i = 0;!isOk && EffectList[i].val;i++)
{
if(value == EffectList[i].val &&
!DisabledEffects[EffectList[i].type])
@@ -174,15 +170,15 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
if(isOk)
InitEffectParams(ALEffect, value);
else
alSetError(Context, AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
alSetError(Context, AL_INVALID_VALUE);
}
else
{
/* Call the appropriate handler */
ALeffect_setParami(ALEffect, Context, param, value);
V(ALEffect,setParami)(Context, param, value);
}
}
UnlockEffectList(Device);
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -204,15 +200,15 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *v
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_setParamiv(ALEffect, Context, param, values);
V(ALEffect,setParamiv)(Context, param, values);
}
UnlockEffectList(Device);
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -227,15 +223,15 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_setParamf(ALEffect, Context, param, value);
V(ALEffect,setParamf)(Context, param, value);
}
UnlockEffectList(Device);
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -250,15 +246,15 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsWrite(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_setParamfv(ALEffect, Context, param, values);
V(ALEffect,setParamfv)(Context, param, values);
}
UnlockEffectList(Device);
UnlockEffectsWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -273,9 +269,9 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_EFFECT_TYPE)
@@ -283,10 +279,10 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value
else
{
/* Call the appropriate handler */
ALeffect_getParami(ALEffect, Context, param, value);
V(ALEffect,getParami)(Context, param, value);
}
}
UnlockEffectList(Device);
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
@@ -308,15 +304,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *valu
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_getParamiv(ALEffect, Context, param, values);
V(ALEffect,getParamiv)(Context, param, values);
}
UnlockEffectList(Device);
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
@@ -331,15 +327,15 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_getParamf(ALEffect, Context, param, value);
V(ALEffect,getParamf)(Context, param, value);
}
UnlockEffectList(Device);
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
@@ -354,120 +350,39 @@ AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->Device;
LockEffectList(Device);
LockEffectsRead(Device);
if((ALEffect=LookupEffect(Device, effect)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid effect ID %u", effect);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALeffect_getParamfv(ALEffect, Context, param, values);
V(ALEffect,getParamfv)(Context, param, values);
}
UnlockEffectList(Device);
UnlockEffectsRead(Device);
ALCcontext_DecRef(Context);
}
void InitEffect(ALeffect *effect)
ALenum InitEffect(ALeffect *effect)
{
InitEffectParams(effect, AL_EFFECT_NULL);
return AL_NO_ERROR;
}
static ALeffect *AllocEffect(ALCcontext *context)
ALvoid ReleaseALEffects(ALCdevice *device)
{
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)
ALsizei i;
for(i = 0;i < device->EffectMap.size;i++)
{
if(sublist->FreeMask)
{
slidx = CTZ64(sublist->FreeMask);
effect = sublist->Effects + slidx;
break;
}
++lidx;
ALeffect *temp = device->EffectMap.values[i];
device->EffectMap.values[i] = NULL;
// Release effect structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALeffect));
al_free(temp);
}
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);
alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated");
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);
alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch");
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)<<slidx);
almtx_unlock(&device->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;
}
void ReleaseALEffects(ALCdevice *device)
{
EffectSubList *sublist = VECTOR_BEGIN(device->EffectList);
EffectSubList *subend = VECTOR_END(device->EffectList);
size_t leftover = 0;
for(;sublist != subend;++sublist)
{
ALuint64 usemask = ~sublist->FreeMask;
while(usemask)
{
ALsizei idx = CTZ64(usemask);
ALeffect *effect = sublist->Effects + idx;
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");
}
@@ -503,7 +418,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->vtab = &ALeaxreverb_vtable;
SET_VTABLE1(ALeaxreverb, effect);
break;
case AL_EFFECT_REVERB:
effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
@@ -533,14 +448,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->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;
SET_VTABLE1(ALreverb, effect);
break;
case AL_EFFECT_CHORUS:
effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
@@ -549,11 +457,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->vtab = &ALchorus_vtable;
SET_VTABLE1(ALchorus, effect);
break;
case AL_EFFECT_COMPRESSOR:
effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
effect->vtab = &ALcompressor_vtable;
SET_VTABLE1(ALcompressor, effect);
break;
case AL_EFFECT_DISTORTION:
effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
@@ -561,7 +469,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->vtab = &ALdistortion_vtable;
SET_VTABLE1(ALdistortion, effect);
break;
case AL_EFFECT_ECHO:
effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
@@ -569,7 +477,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->vtab = &ALecho_vtable;
SET_VTABLE1(ALecho, effect);
break;
case AL_EFFECT_EQUALIZER:
effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
@@ -582,41 +490,30 @@ 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->vtab = &ALequalizer_vtable;
SET_VTABLE1(ALequalizer, effect);
break;
case AL_EFFECT_FLANGER:
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;
effect->vtab = &ALflanger_vtable;
break;
case AL_EFFECT_FREQUENCY_SHIFTER:
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;
effect->Props.Flanger.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
effect->Props.Flanger.Phase = AL_FLANGER_DEFAULT_PHASE;
effect->Props.Flanger.Rate = AL_FLANGER_DEFAULT_RATE;
effect->Props.Flanger.Depth = AL_FLANGER_DEFAULT_DEPTH;
effect->Props.Flanger.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
effect->Props.Flanger.Delay = AL_FLANGER_DEFAULT_DELAY;
SET_VTABLE1(ALflanger, effect);
break;
case AL_EFFECT_RING_MODULATOR:
effect->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->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;
SET_VTABLE1(ALmodulator, effect);
break;
case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
case AL_EFFECT_DEDICATED_DIALOGUE:
effect->Props.Dedicated.Gain = 1.0f;
effect->vtab = &ALdedicated_vtable;
SET_VTABLE1(ALdedicated, effect);
break;
default:
effect->vtab = &ALnull_vtable;
SET_VTABLE1(ALnull, effect);
break;
}
effect->type = type;
@@ -759,7 +656,7 @@ static const struct {
};
#undef DECL
void LoadReverbPreset(const char *name, ALeffect *effect)
ALvoid LoadReverbPreset(const char *name, ALeffect *effect)
{
size_t i;
@@ -770,9 +667,9 @@ void LoadReverbPreset(const char *name, ALeffect *effect)
return;
}
if(!DisabledEffects[EAXREVERB_EFFECT])
if(!DisabledEffects[AL__EAXREVERB])
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
else if(!DisabledEffects[REVERB_EFFECT])
else if(!DisabledEffects[AL__REVERB])
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
+12 -43
View File
@@ -21,7 +21,6 @@
#include "config.h"
#include <signal.h>
#include <stdarg.h>
#ifdef HAVE_WINDOWS_H
#define WIN32_LEAN_AND_MEAN
@@ -34,32 +33,11 @@
ALboolean TrapALError = AL_FALSE;
void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...)
ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
{
ALenum curerr = AL_NO_ERROR;
char message[1024] = { 0 };
va_list args;
int msglen;
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 = (int)strlen(message);
}
if(msglen > 0)
msg = message;
else
{
msg = "<internal error constructing message>";
msglen = (int)strlen(msg);
}
WARN("Error generated on context %p, code 0x%04x, \"%s\"\n",
context, errorCode, message);
WARN("Error generated on context %p, code 0x%04x\n", Context, errorCode);
if(TrapALError)
{
#ifdef _WIN32
@@ -71,29 +49,19 @@ void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...)
#endif
}
ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&context->LastError, &curerr, errorCode);
if((ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed)&EventType_Error))
{
ALbitfieldSOFT enabledevts;
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->EventCbLock);
}
(void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&Context->LastError, &curerr, errorCode));
}
AL_API ALenum AL_APIENTRY alGetError(void)
{
ALCcontext *context;
ALCcontext *Context;
ALenum errorCode;
context = GetContextRef();
if(!context)
Context = GetContextRef();
if(!Context)
{
const ALenum deferror = AL_INVALID_OPERATION;
WARN("Querying error state on null context (implicitly 0x%04x)\n", deferror);
WARN("Querying error state on null context (implicitly 0x%04x)\n",
AL_INVALID_OPERATION);
if(TrapALError)
{
#ifdef _WIN32
@@ -103,11 +71,12 @@ AL_API ALenum AL_APIENTRY alGetError(void)
raise(SIGTRAP);
#endif
}
return deferror;
return AL_INVALID_OPERATION;
}
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;
}
+18 -2
View File
@@ -35,6 +35,22 @@
#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;
@@ -45,8 +61,8 @@ AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
context = GetContextRef();
if(!context) return AL_FALSE;
if(!extName)
SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
if(!(extName))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
len = strlen(extName);
ptr = context->ExtensionList;
+293 -245
View File
@@ -25,56 +25,66 @@
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
#include "alThunk.h"
#include "alError.h"
#define FILTER_MIN_GAIN 0.0f
#define FILTER_MAX_GAIN 4.0f /* +12dB */
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 freq_mult, ALfloat bandwidth);
extern inline void LockFilterList(ALCdevice *device);
extern inline void UnlockFilterList(ALCdevice *device);
static ALfilter *AllocFilter(ALCcontext *context);
static void FreeFilter(ALCdevice *device, ALfilter *filter);
static void InitFilterParams(ALfilter *filter, ALenum type);
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)<<slidx)))
return NULL;
return sublist->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;
if(!(n >= 0))
alSetError(context, AL_INVALID_VALUE, "Generating %d filters", n);
else for(cur = 0;cur < n;cur++)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
device = context->Device;
for(cur = 0;cur < n;cur++)
{
ALfilter *filter = AllocFilter(context);
ALfilter *filter = al_calloc(16, sizeof(ALfilter));
if(!filter)
{
alDeleteFilters(cur, filters);
break;
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
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);
SET_ERROR_AND_GOTO(context, err, done);
}
filters[cur] = filter->id;
}
done:
ALCcontext_DecRef(context);
}
@@ -89,22 +99,26 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters)
if(!context) return;
device = context->Device;
LockFilterList(device);
LockFiltersWrite(device);
if(!(n >= 0))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d filters", n);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < n;i++)
{
if(filters[i] && LookupFilter(device, filters[i]) == NULL)
SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid filter ID %u", filters[i]);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
}
for(i = 0;i < n;i++)
{
if((filter=LookupFilter(device, filters[i])) != NULL)
FreeFilter(device, filter);
if((filter=RemoveFilter(device, filters[i])) == NULL)
continue;
FreeThunkEntry(filter->id);
memset(filter, 0, sizeof(*filter));
al_free(filter);
}
done:
UnlockFilterList(device);
UnlockFiltersWrite(device);
ALCcontext_DecRef(context);
}
@@ -116,10 +130,10 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
Context = GetContextRef();
if(!Context) return AL_FALSE;
LockFilterList(Context->Device);
LockFiltersRead(Context->Device);
result = ((!filter || LookupFilter(Context->Device, filter)) ?
AL_TRUE : AL_FALSE);
UnlockFilterList(Context->Device);
UnlockFiltersRead(Context->Device);
ALCcontext_DecRef(Context);
@@ -136,9 +150,9 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_FILTER_TYPE)
@@ -147,15 +161,15 @@ 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, "Invalid filter type 0x%04x", value);
alSetError(Context, AL_INVALID_VALUE);
}
else
{
/* Call the appropriate handler */
ALfilter_setParami(ALFilter, Context, param, value);
ALfilter_SetParami(ALFilter, Context, param, value);
}
}
UnlockFilterList(Device);
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -177,15 +191,15 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *v
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_setParamiv(ALFilter, Context, param, values);
ALfilter_SetParamiv(ALFilter, Context, param, values);
}
UnlockFilterList(Device);
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -200,15 +214,15 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value)
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_setParamf(ALFilter, Context, param, value);
ALfilter_SetParamf(ALFilter, Context, param, value);
}
UnlockFilterList(Device);
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -223,15 +237,15 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersWrite(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_setParamfv(ALFilter, Context, param, values);
ALfilter_SetParamfv(ALFilter, Context, param, values);
}
UnlockFilterList(Device);
UnlockFiltersWrite(Device);
ALCcontext_DecRef(Context);
}
@@ -246,9 +260,9 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
if(param == AL_FILTER_TYPE)
@@ -256,10 +270,10 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value
else
{
/* Call the appropriate handler */
ALfilter_getParami(ALFilter, Context, param, value);
ALfilter_GetParami(ALFilter, Context, param, value);
}
}
UnlockFilterList(Device);
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
@@ -281,15 +295,15 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *valu
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_getParamiv(ALFilter, Context, param, values);
ALfilter_GetParamiv(ALFilter, Context, param, values);
}
UnlockFilterList(Device);
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
@@ -304,15 +318,15 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *val
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_getParamf(ALFilter, Context, param, value);
ALfilter_GetParamf(ALFilter, Context, param, value);
}
UnlockFilterList(Device);
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
@@ -327,52 +341,134 @@ AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *va
if(!Context) return;
Device = Context->Device;
LockFilterList(Device);
LockFiltersRead(Device);
if((ALFilter=LookupFilter(Device, filter)) == NULL)
alSetError(Context, AL_INVALID_NAME, "Invalid filter ID %u", filter);
alSetError(Context, AL_INVALID_NAME);
else
{
/* Call the appropriate handler */
ALfilter_getParamfv(ALFilter, Context, param, values);
ALfilter_GetParamfv(ALFilter, Context, param, values);
}
UnlockFilterList(Device);
UnlockFiltersRead(Device);
ALCcontext_DecRef(Context);
}
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)
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, 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 * freq_mult;
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 lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_LOWPASS_GAIN:
if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val);
if(!(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_LOWPASS_GAINHF:
if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val);
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainHF = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALlowpass_setParamf(filter, context, param, vals[0]); }
static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
lp_SetParamf(filter, context, param, vals[0]);
}
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)
static void lp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@@ -385,47 +481,49 @@ static void ALlowpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum pa
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALlowpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALlowpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALlowpass);
static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
lp_GetParamf(filter, context, param, vals);
}
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)
static void hp_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))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range");
if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
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,, "High-pass gainlf out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALhighpass_setParamf(filter, context, param, vals[0]); }
static void hp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
hp_SetParamf(filter, context, param, vals[0]);
}
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)
static void hp_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))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@@ -438,53 +536,55 @@ static void ALhighpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALhighpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALhighpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALhighpass);
static void hp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
hp_GetParamf(filter, context, param, vals);
}
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)
static void bp_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))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range");
if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
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,, "Band-pass gainhf out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
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,, "Band-pass gainlf out of range");
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{ ALbandpass_setParamf(filter, context, param, vals[0]); }
static void bp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
bp_SetParamf(filter, context, param, vals[0]);
}
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)
static void bp_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))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
@@ -501,131 +601,47 @@ static void ALbandpass_getParamf(ALfilter *filter, ALCcontext *context, ALenum p
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void ALbandpass_getParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{ ALbandpass_getParamf(filter, context, param, vals); }
DEFINE_ALFILTER_VTABLE(ALbandpass);
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);
static ALfilter *AllocFilter(ALCcontext *context)
static void bp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
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))
{
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);
alSetError(context, AL_OUT_OF_MEMORY, "Too many filters allocated");
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);
alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate filter batch");
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)<<slidx);
almtx_unlock(&device->FilterLock);
return filter;
bp_GetParamf(filter, context, param, vals);
}
static void FreeFilter(ALCdevice *device, ALfilter *filter)
static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamf(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_GetParamfv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
ALvoid ReleaseALFilters(ALCdevice *device)
{
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)
ALsizei i;
for(i = 0;i < device->FilterMap.size;i++)
{
ALuint64 usemask = ~sublist->FreeMask;
while(usemask)
{
ALsizei idx = CTZ64(usemask);
ALfilter *filter = sublist->Filters + idx;
ALfilter *temp = device->FilterMap.values[i];
device->FilterMap.values[i] = NULL;
memset(filter, 0, sizeof(*filter));
++leftover;
usemask &= ~(U64(1) << idx);
}
sublist->FreeMask = ~usemask;
// Release filter structure
FreeThunkEntry(temp->id);
memset(temp, 0, sizeof(ALfilter));
al_free(temp);
}
if(leftover > 0)
WARN("(%p) Deleted "SZFMT" Filter%s\n", device, leftover, (leftover==1)?"":"s");
}
@@ -638,7 +654,15 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->vtab = &ALlowpass_vtable;
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;
}
else if(type == AL_FILTER_HIGHPASS)
{
@@ -647,7 +671,15 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->vtab = &ALhighpass_vtable;
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;
}
else if(type == AL_FILTER_BANDPASS)
{
@@ -656,7 +688,15 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->vtab = &ALbandpass_vtable;
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;
}
else
{
@@ -665,7 +705,15 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->vtab = &ALnullfilter_vtable;
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->type = type;
}
+113 -105
View File
@@ -21,101 +21,85 @@
#include "config.h"
#include "alMain.h"
#include "alu.h"
#include "AL/alc.h"
#include "alError.h"
#include "alListener.h"
#include "alSource.h"
#define DO_UPDATEPROPS() do { \
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire)) \
UpdateListenerProps(context); \
else \
ATOMIC_FLAG_CLEAR(&listener->PropsClean, almemory_order_release); \
} while(0)
AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
{
ALlistener *listener;
ALCcontext *context;
context = GetContextRef();
if(!context) return;
listener = context->Listener;
almtx_lock(&context->PropLock);
WriteLock(&context->PropLock);
switch(param)
{
case AL_GAIN:
if(!(value >= 0.0f && isfinite(value)))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener gain out of range");
listener->Gain = value;
DO_UPDATEPROPS();
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Gain = value;
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, done, "Listener meters per unit out of range");
context->MetersPerUnit = value;
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateContextProps(context);
else
ATOMIC_FLAG_CLEAR(&context->PropsClean, almemory_order_release);
if(!(value >= 0.0f && isfinite(value)))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->MetersPerUnit = value;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
almtx_unlock(&context->PropLock);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
{
ALlistener *listener;
ALCcontext *context;
context = GetContextRef();
if(!context) return;
listener = context->Listener;
almtx_lock(&context->PropLock);
WriteLock(&context->PropLock);
switch(param)
{
case AL_POSITION:
if(!(isfinite(value1) && isfinite(value2) && isfinite(value3)))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener position out of range");
listener->Position[0] = value1;
listener->Position[1] = value2;
listener->Position[2] = value3;
DO_UPDATEPROPS();
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
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)))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener velocity out of range");
listener->Velocity[0] = value1;
listener->Velocity[1] = value2;
listener->Velocity[2] = value3;
DO_UPDATEPROPS();
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Velocity[0] = value1;
context->Listener->Velocity[1] = value2;
context->Listener->Velocity[2] = value3;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
almtx_unlock(&context->PropLock);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
{
ALlistener *listener;
ALCcontext *context;
if(values)
@@ -137,31 +121,32 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
context = GetContextRef();
if(!context) return;
listener = context->Listener;
almtx_lock(&context->PropLock);
if(!values) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, 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])))
SETERR_GOTO(context, AL_INVALID_VALUE, done, "Listener orientation out of range");
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
/* AT then UP */
listener->Forward[0] = values[0];
listener->Forward[1] = values[1];
listener->Forward[2] = values[2];
listener->Up[0] = values[3];
listener->Up[1] = values[4];
listener->Up[2] = values[5];
DO_UPDATEPROPS();
context->Listener->Forward[0] = values[0];
context->Listener->Forward[1] = values[1];
context->Listener->Forward[2] = values[2];
context->Listener->Up[0] = values[3];
context->Listener->Up[1] = values[4];
context->Listener->Up[2] = values[5];
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
almtx_unlock(&context->PropLock);
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -173,14 +158,17 @@ AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint UNUSED(value))
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
WriteLock(&context->PropLock);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -200,14 +188,17 @@ AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, A
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
WriteLock(&context->PropLock);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -241,16 +232,19 @@ AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
WriteLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
if(!ATOMIC_LOAD(&context->DeferUpdates, almemory_order_acquire))
UpdateListenerProps(context);
done:
WriteUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -262,24 +256,25 @@ AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!value)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_GAIN:
*value = context->Listener->Gain;
break;
case AL_METERS_PER_UNIT:
*value = context->MetersPerUnit;
*value = context->Listener->MetersPerUnit;
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener float property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -291,10 +286,10 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!value1 || !value2 || !value3)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_POSITION:
*value1 = context->Listener->Position[0];
@@ -309,10 +304,11 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-float property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -337,10 +333,10 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_ORIENTATION:
// AT then UP
@@ -353,10 +349,11 @@ AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener float-vector property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -368,16 +365,17 @@ AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!value)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(value))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -389,10 +387,10 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!value1 || !value2 || !value3)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(value1 && value2 && value3))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch (param)
{
case AL_POSITION:
*value1 = (ALint)context->Listener->Position[0];
@@ -407,10 +405,11 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener 3-integer property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -430,10 +429,10 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
context = GetContextRef();
if(!context) return;
almtx_lock(&context->PropLock);
if(!values)
alSetError(context, AL_INVALID_VALUE, "NULL pointer");
else switch(param)
ReadLock(&context->PropLock);
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(param)
{
case AL_ORIENTATION:
// AT then UP
@@ -446,10 +445,11 @@ AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
break;
default:
alSetError(context, AL_INVALID_ENUM, "Invalid listener integer-vector property");
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
almtx_unlock(&context->PropLock);
done:
ReadUnlock(&context->PropLock);
ALCcontext_DecRef(context);
}
@@ -460,7 +460,7 @@ void UpdateListenerProps(ALCcontext *context)
struct ALlistenerProps *props;
/* Get an unused proprty container, or allocate a new one as needed. */
props = ATOMIC_LOAD(&context->FreeListenerProps, almemory_order_acquire);
props = ATOMIC_LOAD(&listener->FreeList, almemory_order_acquire);
if(!props)
props = al_calloc(16, sizeof(*props));
else
@@ -468,7 +468,7 @@ void UpdateListenerProps(ALCcontext *context)
struct ALlistenerProps *next;
do {
next = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&context->FreeListenerProps, &props, next,
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(&listener->FreeList, &props, next,
almemory_order_seq_cst, almemory_order_acquire) == 0);
}
@@ -489,6 +489,14 @@ void UpdateListenerProps(ALCcontext *context)
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_PTR(&listener->Update, props, almemory_order_acq_rel);
@@ -497,6 +505,6 @@ void UpdateListenerProps(ALCcontext *context)
/* If there was an unused update container, put it back in the
* freelist.
*/
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &context->FreeListenerProps, props);
ATOMIC_REPLACE_HEAD(struct ALlistenerProps*, &listener->FreeList, props);
}
}

Some files were not shown because too many files have changed in this diff Show More